Skip to content

Conversation

@premiumjibles
Copy link
Contributor

@premiumjibles premiumjibles commented Dec 14, 2025

Summary by CodeRabbit

  • New Features

    • Full limit order support: create, view, and cancel CoW Protocol orders with tracking links and history.
  • New Features (UI)

    • New limit order interfaces: multi-step order workflow, order list with status badges, and cancellation flow with stepper and explorer links.
  • Improvements

    • Portfolio activity list now includes limit orders (sorted by time).
    • Activity rows/details redesigned for clearer amounts, statuses, loading states, and explorer links.
    • Added analytics events for limit order create/cancel.

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

@vercel
Copy link

vercel bot commented Dec 14, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
shapeshift-agentic Ready Ready Preview, Comment Dec 16, 2025 6:53am

@coderabbitai
Copy link

coderabbitai bot commented Dec 14, 2025

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Adds end-to-end CoW Protocol limit-order support: server tools (create/get/cancel), client UIs and multi-step execution hooks (create/cancel), activity types/normalization, activity-row refactor into per-type components, step utilities and EIP‑712 signing helpers, and analytics tracking.

Changes

Cohort / File(s) Summary
Server — CoW types & runtime
apps/agentic-server/src/lib/cow/types.ts, apps/agentic-server/src/lib/cow/index.ts
New CoW protocol types, chain mappings, EIP‑712 shapes, helper URL/API builders, and exported constants/utilities.
Server — Limit order tools
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts, apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts, apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts, apps/agentic-server/src/tools/limitOrder/index.ts
New zod schemas, execute functions, and tool exports for create/get/cancel limit orders; includes enrichment, approval-building, signing data, querying, and cancellation flows.
Server — Chat integration & exports
apps/agentic-server/src/index.ts, apps/agentic-server/src/routes/chat.ts
Exposes limit-order tool APIs/types and registers create/get/cancel tools in chat buildTools with wallet-context propagation.
Client — Tool UIs & registry
apps/agentic-chat/src/components/tools/LimitOrderUI.tsx, apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx, apps/agentic-chat/src/components/tools/CancelLimitOrderUI.tsx, apps/agentic-chat/src/components/toolUIRegistry.tsx
New React UIs for creating, listing, and cancelling limit orders and registry mappings for these tools.
Client — Execution hooks
apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx, apps/agentic-chat/src/hooks/useCancelLimitOrderExecution.tsx
New persisted multi-step hooks (prepare, network switch, approval, sign, submit, complete) with persistence/hydration, signing helpers, submission helpers, and step status outputs.
Client — Activity types & normalization
apps/agentic-chat/src/types/activity.ts, apps/agentic-chat/src/lib/activityNormalizer.ts, apps/agentic-chat/src/stores/chatStore.ts
Added LimitOrder activity types/details, normalizer support for limit_order, and extended PersistedToolState (includes limit_order/cancel_limit_order, outputs, walletAddress).
Client — Activity UI refactor
Deleted: apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx
Added/Updated: apps/agentic-chat/src/components/Portfolio/ActivityRow/ActivityRow.tsx, apps/agentic-chat/src/components/Portfolio/ActivityRow/index.ts, apps/agentic-chat/src/components/Portfolio/ActivityRow/components/LimitOrderDetails.tsx, apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SendDetails.tsx, apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx
Replaced monolithic ActivityRow with scoped module and per-type detail components; removed old top-level file.
Client — Activity list & helpers
apps/agentic-chat/src/components/Portfolio/ActivityList.tsx, apps/agentic-chat/src/lib/stepUtils.ts, apps/agentic-chat/src/lib/eventHandlers.ts, apps/agentic-chat/src/lib/cow-config.ts
ActivityList now includes limit_order and sorts by timestamp; added generic step utilities, EIP‑712 signing helper, stopPropagationHandler, and COW API URL mapping.
Client — Step/per-step UI changes
apps/agentic-chat/src/components/ui/TxStepCard.tsx, apps/agentic-chat/src/hooks/useSendExecution.ts, apps/agentic-chat/src/hooks/useSwapExecution.tsx
TxStepCard SwapPair/Amount signatures updated to support loading/formatting; send/swap hooks migrated to centralized stepUtils phase mapping for persistence.
Client — Tool execution safety
apps/agentic-chat/src/hooks/useToolExecutionEffect.ts
Wraps tool execution invocation in try/catch and invokes fire-and-forget to avoid unhandled promise rejections.
Client — Misc UI tweaks
apps/agentic-chat/src/components/tools/InitiateSwapUI.tsx, apps/agentic-chat/src/components/tools/SendUI.tsx
Consolidated header/amount rendering to use TxStepCard primitives with isLoading; simplified some text.
Client — Analytics
apps/agentic-chat/src/lib/mixpanel.ts
Added analytics methods trackLimitOrder and trackCancelLimitOrder.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ChatUI
    participant Wallet
    participant Server
    participant CoW
    Note over User,CoW: Create Limit Order
    User->>ChatUI: trigger createLimitOrder(input)
    ChatUI->>Server: executeCreateLimitOrder(input)
    Server-->>ChatUI: CreateLimitOrderOutput (orderParams, signingData, approvalTx?)
    ChatUI->>Wallet: switch network (if needed)
    Wallet-->>ChatUI: network switched
    alt approval required
        ChatUI->>Wallet: send approval tx
        Wallet-->>ChatUI: approval tx hash
    end
    ChatUI->>Wallet: sign EIP‑712 order
    Wallet-->>ChatUI: signature
    ChatUI->>Server: submitSignedOrder(signature)
    Server->>CoW: POST signed order
    CoW-->>Server: orderId
    Server-->>ChatUI: orderId/trackingUrl
    ChatUI->>User: show complete / tracking link
Loading
sequenceDiagram
    participant User
    participant ChatUI
    participant Wallet
    participant Server
    participant CoW
    Note over User,CoW: Cancel Limit Order
    User->>ChatUI: trigger cancelLimitOrder(orderId)
    ChatUI->>Server: executeCancelLimitOrder(orderId)
    Server-->>ChatUI: CancellationSigningData
    ChatUI->>Wallet: switch network (if needed)
    Wallet-->>ChatUI: network switched
    ChatUI->>Wallet: sign cancellation (EIP‑712)
    Wallet-->>ChatUI: signature
    ChatUI->>Server: submit cancellation(signature)
    Server->>CoW: DELETE order with signature
    CoW-->>Server: confirmation
    Server-->>ChatUI: cancellation confirmed
    ChatUI->>User: show cancelled status
Loading
sequenceDiagram
    participant User
    participant ChatUI
    participant Server
    participant CoW
    Note over User,CoW: Get Limit Orders
    User->>ChatUI: request list (params)
    ChatUI->>Server: executeGetLimitOrders(params)
    Server->>CoW: fetch orders per chain
    CoW-->>Server: orders
    Server->>Server: enrich & format orders
    Server-->>ChatUI: GetLimitOrdersOutput (order list)
    ChatUI->>User: render list with badges & tracking links
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60–75 minutes

  • Pay special attention to:
    • useLimitOrderExecution / useCancelLimitOrderExecution: step transitions, persistence/hydration, error handling, and wallet/network switching.
    • Server CoW integration and EIP‑712 signing data correctness (types, domain, primaryType).
    • createLimitOrder/getLimitOrders/cancelLimitOrder: asset resolution, amount conversions, approval tx construction, and edge cases.
    • Activity normalization and ActivityRow refactor: mapping persisted tool state to activity items and event propagation handling.
    • TxStepCard signature changes: ensure all call sites use new props.

Possibly related PRs

Poem

🐇 I signed a limit order by moonlit code,

Steps marched and persisted down the road,
Explorer links blink and trackers hum,
Orders open, cancelled, fulfilled — then drum,
A hopping rabbit cheers: "Trade on, go! 🥕"

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.06% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main changes: infrastructure for long-running tools and limit orders implementation, which aligns with the substantial changeset.

📜 Recent review details

Configuration used: CodeRabbit 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 8fe318a and 9b99169.

📒 Files selected for processing (34)
  • apps/agentic-chat/src/components/Portfolio/ActivityList.tsx (2 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx (0 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/ActivityRow.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/LimitOrderDetails.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SendDetails.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/index.ts (1 hunks)
  • apps/agentic-chat/src/components/toolUIRegistry.tsx (2 hunks)
  • apps/agentic-chat/src/components/tools/CancelLimitOrderUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/InitiateSwapUI.tsx (3 hunks)
  • apps/agentic-chat/src/components/tools/LimitOrderUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/SendUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/ui/TxStepCard.tsx (3 hunks)
  • apps/agentic-chat/src/hooks/useCancelLimitOrderExecution.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useSendExecution.ts (4 hunks)
  • apps/agentic-chat/src/hooks/useSwapExecution.tsx (4 hunks)
  • apps/agentic-chat/src/hooks/useToolExecutionEffect.ts (1 hunks)
  • apps/agentic-chat/src/lib/activityNormalizer.ts (3 hunks)
  • apps/agentic-chat/src/lib/cow-config.ts (1 hunks)
  • apps/agentic-chat/src/lib/eventHandlers.ts (1 hunks)
  • apps/agentic-chat/src/lib/mixpanel.ts (1 hunks)
  • apps/agentic-chat/src/lib/stepUtils.ts (1 hunks)
  • apps/agentic-chat/src/stores/chatStore.ts (2 hunks)
  • apps/agentic-chat/src/types/activity.ts (2 hunks)
  • apps/agentic-server/src/index.ts (1 hunks)
  • apps/agentic-server/src/lib/cow/index.ts (1 hunks)
  • apps/agentic-server/src/lib/cow/types.ts (1 hunks)
  • apps/agentic-server/src/routes/chat.ts (5 hunks)
  • apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/index.ts (1 hunks)

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: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/agentic-chat/src/hooks/useToolExecutionEffect.ts (1)

33-54: Don’t silently swallow tool failures—persist an error/terminal state (or rethrow selectively).

Catching + fire-and-forget avoids unhandled rejections, but it also means callers/UI can’t react; you may end up with initialized runtime state and no indication the tool failed. Consider setting an error/status in runtime state (keyed by toolCallId) inside the catch, and include toolCallId in the log.

 const executeWrapper = async () => {
   try {
     await executeRef.current(data, setStateRef.current)
   } catch (error) {
-    console.error('[useToolExecutionEffect] Tool execution failed:', error)
+    console.error('[useToolExecutionEffect] Tool execution failed:', { toolCallId, error })
+    setStateRef.current((draft: any) => {
+      draft.status = 'error'
+      draft.error = String(error)
+    })
   }
 }
🧹 Nitpick comments (10)
apps/agentic-server/src/lib/cow/index.ts (2)

53-64: Unreachable error due to fallback logic.

Line 54 falls back to COW_SETTLEMENT_CONTRACT[1] when the chainId isn't found, so verifyingContract will always be defined. The error on line 56 is unreachable dead code. This also silently uses mainnet's contract for unsupported chains instead of failing early.

Consider removing the fallback to properly reject unsupported chains:

 function getEIP712Domain(chainId: number): CowEIP712Domain {
-  const verifyingContract = COW_SETTLEMENT_CONTRACT[chainId] ?? COW_SETTLEMENT_CONTRACT[1]
-  if (!verifyingContract) {
-    throw new Error(`No settlement contract for chain ${chainId}`)
-  }
+  const verifyingContract = COW_SETTLEMENT_CONTRACT[chainId]
+  if (!verifyingContract) {
+    throw new Error(`No settlement contract for chain ${chainId}`)
+  }
   return {

147-153: Consider adding request timeouts for external API calls.

All fetch calls to the CoW API lack timeouts. If the CoW API is slow or unresponsive, these requests could hang indefinitely. Consider using AbortController with a reasonable timeout (e.g., 30 seconds) for better resilience.

const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), 30000)

try {
  const response = await fetch(url, {
    signal: controller.signal,
    // ... other options
  })
} finally {
  clearTimeout(timeoutId)
}

Also applies to: 176-180, 196-200, 244-253

apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx (1)

23-29: Make link click handler element-typed + more robust status check.
Consider MouseEvent<HTMLAnchorElement> for handleLinkClick, and Object.prototype.hasOwnProperty.call(STATUS_CONFIG, status) to avoid prototype edge-cases.

Also applies to: 97-105

apps/agentic-server/src/index.ts (1)

91-110: Consolidate the 3 re-export blocks into one for maintainability.
No functional issue—just reduces duplication and future drift when renaming/moving exports.

apps/agentic-chat/src/components/tools/LimitOrderUI.tsx (1)

29-48: Emoji in UI strings may not match existing tone/i18n strategy.
If the rest of the app avoids emoji (or requires i18n), consider replacing with standard copy.

apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx (1)

22-31: Type link click handler to anchor + consider optional trackingUrl.
handleLinkClick can be MouseEvent<HTMLAnchorElement>. Also, if LimitOrderActivityDetails.trackingUrl can ever be missing, guard the Track Order row (or make the type required).

Also applies to: 114-147

apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1)

54-68: Schema constraints should be enforced at validation time.

Update expirationHours to z.number().min(1).max(8760).default(168) to validate bounds directly. For sellAmount and limitPrice, add regex validation to ensure numeric strings, e.g., z.string().regex(/^\d+(\.\d+)?$/).describe(...) to reject non-numeric input at schema level rather than relying on runtime handling.

apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (1)

34-48: Consider logging failed detection attempts for debugging.

The empty catch block silently swallows errors, making it harder to diagnose issues when order detection fails across all chains.

  for (const chainId of chainsToTry) {
    try {
      const order = await getCowOrder(orderId, chainId)
      if (order) return chainId
    } catch {
-      // Order not found on this chain, try next
+      // Order not found on this chain, try next
+      console.debug(`[cancelLimitOrder] Order ${orderId} not found on chain ${chainId}`)
    }
  }
apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (2)

102-132: Clarify intent: currentStep is always set to COMPLETE.

The function unconditionally sets currentStep = LimitOrderStep.COMPLETE regardless of the persisted phases. This appears intentional (hydration only occurs for terminal states), but adding a brief comment would improve maintainability.

 function persistedStateToLimitOrderState(persisted: PersistedToolState): LimitOrderState {
   const completedSteps = new Set<LimitOrderStep>()
-  const currentStep = LimitOrderStep.COMPLETE
+  // Persisted states are only saved for completed/errored flows, so we default to COMPLETE
+  const currentStep = LimitOrderStep.COMPLETE

166-216: Response parsing could be more robust.

The manual quote stripping orderId.replace(/"/g, '') is fragile. If the CoW API returns a proper JSON string, consider using JSON.parse() for safer parsing.

-  const orderId = await response.text()
-  return orderId.replace(/"/g, '')
+  const responseText = await response.text()
+  // CoW API returns the order ID as a JSON-encoded string (e.g., "0x123...")
+  try {
+    return JSON.parse(responseText)
+  } catch {
+    // Fallback if response is not JSON-encoded
+    return responseText.replace(/"/g, '')
+  }
📜 Review details

Configuration used: CodeRabbit 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 ac8f530 and 940daa0.

📒 Files selected for processing (17)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx (6 hunks)
  • apps/agentic-chat/src/components/toolUIRegistry.tsx (2 hunks)
  • apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/LimitOrderUI.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useToolExecutionEffect.ts (1 hunks)
  • apps/agentic-chat/src/lib/activityNormalizer.ts (3 hunks)
  • apps/agentic-chat/src/stores/chatStore.ts (2 hunks)
  • apps/agentic-chat/src/types/activity.ts (2 hunks)
  • apps/agentic-server/src/index.ts (1 hunks)
  • apps/agentic-server/src/lib/cow/index.ts (1 hunks)
  • apps/agentic-server/src/lib/cow/types.ts (1 hunks)
  • apps/agentic-server/src/routes/chat.ts (4 hunks)
  • apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/index.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-18T20:08:31.777Z
Learnt from: kaladinlight
Repo: shapeshift/agentic-chat PR: 73
File: apps/agentic-chat/src/components/assistant-ui/GetPortalsAssets.tsx:30-33
Timestamp: 2025-09-18T20:08:31.777Z
Learning: In assistant UI components using makeAssistantToolUI, the toolName should match the exact key name as defined in the agent's tools configuration object, not the underlying tool's id. For example, if a tool is referenced as 'getPortalsAssetsTool' in the agent's tools object, the UI component should use toolName: 'getPortalsAssetsTool'.

Applied to files:

  • apps/agentic-chat/src/components/toolUIRegistry.tsx
📚 Learning: 2025-09-22T20:32:10.539Z
Learnt from: kaladinlight
Repo: shapeshift/agentic-chat PR: 76
File: apps/agentic-server/src/mastra/tools/asset/coingecko/constants.ts:1-10
Timestamp: 2025-09-22T20:32:10.539Z
Learning: When cross-app dependencies are identified (like server code importing from chat packages), the user prefers to extract shared constants into dedicated packages in the packages/ directory following the existing pattern of shapeshiftoss/types and shapeshiftoss/utils.

Applied to files:

  • apps/agentic-chat/src/stores/chatStore.ts
🧬 Code graph analysis (4)
apps/agentic-chat/src/components/toolUIRegistry.tsx (2)
apps/agentic-chat/src/components/tools/LimitOrderUI.tsx (1)
  • LimitOrderUI (15-187)
apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx (1)
  • GetLimitOrdersUI (111-179)
apps/agentic-chat/src/lib/activityNormalizer.ts (3)
apps/agentic-chat/src/stores/chatStore.ts (1)
  • PersistedToolState (21-29)
apps/agentic-chat/src/types/activity.ts (2)
  • ActivityItem (70-70)
  • LimitOrderActivityDetails (39-52)
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1)
  • CreateLimitOrderOutput (90-106)
apps/agentic-server/src/routes/chat.ts (5)
apps/agentic-server/src/index.ts (3)
  • createLimitOrderTool (92-92)
  • getLimitOrdersTool (99-99)
  • cancelLimitOrderTool (105-105)
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1)
  • createLimitOrderTool (272-294)
apps/agentic-server/src/tools/limitOrder/index.ts (3)
  • createLimitOrderTool (2-2)
  • getLimitOrdersTool (11-11)
  • cancelLimitOrderTool (19-19)
apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (1)
  • getLimitOrdersTool (155-176)
apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (1)
  • cancelLimitOrderTool (111-130)
apps/agentic-server/src/lib/cow/index.ts (1)
apps/agentic-server/src/lib/cow/types.ts (10)
  • CowEIP712Types (44-46)
  • CowEIP712Domain (37-42)
  • CreateCowOrderParams (55-64)
  • CreateCowOrderResult (66-72)
  • isCowSupportedChain (96-98)
  • CowOrderQuote (24-35)
  • CowOrderSigningData (48-53)
  • getCowExplorerUrl (100-106)
  • getCowApiUrl (108-121)
  • CowOrder (7-22)
⏰ 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: main
🔇 Additional comments (21)
apps/agentic-chat/src/hooks/useToolExecutionEffect.ts (1)

38-53: Verify this remains single-execution under React 18/19 StrictMode and store timing.

The “run once” gating depends on hasRuntimeState(toolCallId) becoming true before any second effect pass; if initializeRuntimeState isn’t synchronous/atomic, you can double-execute. Worth confirming with a StrictMode dev run and/or making initialization+check atomic in the store.

apps/agentic-server/src/lib/cow/index.ts (3)

70-114: LGTM!

The function correctly prepares EIP-712 signing data for CoW limit orders. The placeholder orderId is appropriately noted in the comment, and the actual ID will be assigned after submission.


214-231: LGTM!

The cancellation signing data preparation correctly follows the CoW Protocol's EIP-712 format for order cancellations.


236-259: LGTM!

The cancellation submission correctly uses the DELETE method with the signature payload as expected by the CoW API.

apps/agentic-chat/src/stores/chatStore.ts (1)

21-29: LGTM!

The PersistedToolState interface is correctly extended to support limit orders by adding 'limit_order' to the toolType union and CreateLimitOrderOutput to the toolOutput union. This follows the existing pattern for swap, send, and network_switch tools.

apps/agentic-chat/src/types/activity.ts (2)

39-52: LGTM!

The LimitOrderActivityDetails interface is well-structured with all necessary fields for displaying limit order information. Including trackingUrl directly in the details is convenient for UI rendering.


64-68: LGTM!

Using Omit<BaseActivityItem, 'txHash'> is the correct approach since CoW limit orders are off-chain and don't have a transaction hash until execution. The orderId field appropriately replaces txHash for order identification.

apps/agentic-chat/src/lib/activityNormalizer.ts (1)

118-119: No action needed. LimitOrderSummary.sellAsset includes both chainId and network fields as string properties (defined at createLimitOrder.ts lines 76-77), so accessing them at lines 118-119 is safe and will not return undefined.

apps/agentic-server/src/tools/limitOrder/index.ts (1)

1-24: Clean barrel export.
Nice consolidation point for the limit-order tool surface.

apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx (1)

149-175: Good: suppress TX link for limit orders and add dedicated details.
This avoids misleading users (limit orders are off-chain until executed) while still providing an explorer tracking link.

apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1)

184-201: Remove Sepolia from consideration or add explicit chain validation earlier in the flow.

The WETH_ADDRESSES mapping currently covers only mainnet chains (Ethereum, Gnosis, Arbitrum). If a Sepolia request (chainId 11155111) reaches this code, it will fall back to the native token address, which CoW Protocol will reject. Since CoW Protocol does not officially support Sepolia testnet, either ensure the function rejects unsupported chains before reaching this point, or remove any Sepolia-related functionality from the supported chain list if it's being exposed elsewhere.

apps/agentic-server/src/routes/chat.ts (3)

28-28: LGTM!

The import follows the existing pattern and is correctly placed with other tool imports.


164-187: LGTM!

The three limit order tools are correctly wired with the same pattern as other wallet-context-dependent tools (e.g., initiateSwapTool, sendTool). Each tool logs arguments and passes walletContext to the underlying execute function.


304-310: LGTM!

The system prompt documentation for limit orders is clear and consistent with the existing format. It correctly documents supported networks, use cases, and behavior.

apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (3)

9-15: LGTM!

Schema definition is well-structured with clear descriptions. The optional network parameter with auto-detection fallback provides good UX.


50-108: LGTM!

The execution flow is well-structured with proper validation:

  • Chain ID resolution with fallback detection
  • Order ownership verification
  • Status checks preventing cancellation of fulfilled/cancelled/expired orders
  • Proper EIP-712 signing data preparation

The error messages are user-friendly and actionable.


111-129: LGTM!

The tool description follows the established pattern with UI card guidance and concise default responses.

apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (4)

22-53: LGTM!

The step enum and state interface are well-designed. The getStepStatus helper correctly handles all state transitions including failure states.


218-245: LGTM!

The hydration logic correctly resets on toolCallId change and properly handles the case where runtime state already exists.


263-396: Well-structured multi-step execution flow.

The execution logic properly handles:

  • Wallet validation and address verification
  • Network switching with primary wallet handling
  • Conditional approval flow with confirmation
  • EIP-712 signing
  • Order submission with proper state persistence at each step
  • Comprehensive error handling with toast notifications

The use of current(draft) from Immer on line 385 correctly captures the state snapshot for persistence after an error.


405-422: LGTM!

The return value properly exposes step statuses, error state, and tracking information. The trackingUrl fallback from state.orderId to orderData?.trackingUrl handles both successful submissions and pre-submission states.

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: 3

♻️ Duplicate comments (9)
apps/agentic-chat/src/components/tools/LimitOrderUI.tsx (1)

50-57: completedCount calculation inconsistent with rendered step statuses.

When needsApproval is false, the UI renders approval steps as StepStatus.SKIPPED (lines 148, 152), but completedCount uses the raw approvalStep.status and approvalConfirmStep.status. This causes progress bar mismatch.

Apply this diff to compute effective statuses consistently:

-  const completedCount = [
-    prepareStep.status,
-    networkStep.status,
-    approvalStep.status,
-    approvalConfirmStep.status,
-    signStep.status,
-    submitStep.status,
-  ].filter(s => s === StepStatus.COMPLETE || s === StepStatus.SKIPPED).length
+  const effectiveApprovalStatus = needsApproval ? approvalStep.status : StepStatus.SKIPPED
+  const effectiveApprovalConfirmStatus = needsApproval ? approvalConfirmStep.status : StepStatus.SKIPPED
+  const completedCount = [
+    prepareStep.status,
+    networkStep.status,
+    effectiveApprovalStatus,
+    effectiveApprovalConfirmStatus,
+    signStep.status,
+    submitStep.status,
+  ].filter(s => s === StepStatus.COMPLETE || s === StepStatus.SKIPPED).length
apps/agentic-server/src/lib/cow/types.ts (1)

74-95: Incomplete sepolia support across mappings.

COW_SUPPORTED_CHAINS includes sepolia (11155111), but NETWORK_TO_CHAIN_ID and CHAIN_ID_TO_NETWORK omit it. This creates inconsistency where isCowSupportedChain(11155111) returns true, but CHAIN_ID_TO_NETWORK[11155111] returns undefined.

Either fully support sepolia by adding it to all mappings, or remove it from COW_SUPPORTED_CHAINS:

 export const NETWORK_TO_CHAIN_ID: Record<string, number> = {
   ethereum: 1,
   gnosis: 100,
   arbitrum: 42161,
+  sepolia: 11155111,
 }

 export const CHAIN_ID_TO_NETWORK: Record<number, string> = {
+  11155111: 'sepolia',
 }
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (3)

108-120: Critical: parseFloat causes precision loss in limit order price calculations.

Using parseFloat for financial math will silently misprice orders due to floating-point representation errors. Use BigNumber end-to-end as it's already imported.

 function calculateBuyAmount(buyAsset: Asset, sellAmount: string, limitPrice: string): string {
-  const sellAmountNum = parseFloat(sellAmount)
-  const limitPriceNum = parseFloat(limitPrice)
-
-  if (isNaN(sellAmountNum) || isNaN(limitPriceNum)) {
-    throw new Error('Invalid sellAmount or limitPrice')
-  }
-
-  const buyAmountNum = sellAmountNum * limitPriceNum
-  return toBaseUnit(buyAmountNum.toString(), buyAsset.precision)
+  const bnSell = new BigNumber(sellAmount)
+  const bnPrice = new BigNumber(limitPrice)
+  if (!bnSell.isFinite() || !bnPrice.isFinite() || bnSell.lte(0) || bnPrice.lte(0)) {
+    throw new Error('Invalid sellAmount or limitPrice')
+  }
+  const buyAmountHuman = bnSell.times(bnPrice)
+  return toBaseUnit(buyAmountHuman.toFixed(buyAsset.precision), buyAsset.precision)
 }

135-136: Remove sensitive input logging.

console.log('[createLimitOrder]:', JSON.stringify(input, null, 2)) can leak user trading intent and amounts. Use a structured logger with redaction or remove entirely.

-  console.log('[createLimitOrder]:', JSON.stringify(input, null, 2))

268-268: trackingUrl with placeholder 'pending' leads to invalid page.

The URL https://explorer.cow.fi/orders/pending doesn't exist. Either make trackingUrl optional and set it after order submission, or omit it until a real order ID is available.

-    trackingUrl: getCowExplorerUrl('pending'),
+    trackingUrl: '', // Will be set after order submission with real order ID

Or make the field optional in CreateLimitOrderOutput:

-  trackingUrl: string
+  trackingUrl?: string
apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (2)

74-79: presignaturePending mapped to open loses distinct order state.

Per CoW Protocol semantics, presignaturePending (awaiting on-chain pre-signature, not tradable) differs from open (active in orderbook). Collapsing them prevents users from distinguishing orders awaiting signature from actively tradable orders.

Either preserve the distinct status or document why simplification is intentional:

 function formatOrderStatus(status: CowOrderStatus): CowOrderStatus {
-  if (status === 'presignaturePending') return 'open'
+  // Keep presignaturePending distinct - UI can handle both states
   return status
 }

And update the schema to include presignaturePending if preserving:

   status: z
-    .enum(['open', 'filled', 'cancelled', 'expired', 'all'])
+    .enum(['open', 'presignaturePending', 'filled', 'cancelled', 'expired', 'all'])

93-93: Remove verbose input logging.

console.log('[getLimitOrders]:', JSON.stringify(input, null, 2)) is noisy and may leak user intent. Use a structured logger with appropriate log levels or remove.

-  console.log('[getLimitOrders]:', JSON.stringify(input, null, 2))
apps/agentic-chat/src/lib/activityNormalizer.ts (1)

92-122: Use network-aware tracking URL from output.

Line 110 hardcodes https://explorer.cow.fi/orders/${orderId}, which always produces the mainnet format. The getCowExplorerUrl utility in the server (as noted in past reviews) handles network-specific URLs like explorer.cow.fi/gnosis/orders/ for Gnosis chain.

Apply this diff to use the network-aware URL:

-    trackingUrl: `https://explorer.cow.fi/orders/${orderId}`,
+    trackingUrl: output.trackingUrl,

The output.trackingUrl from CreateLimitOrderOutput should already contain the correct network-specific URL from the server.

apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (1)

315-337: Handle missing publicClient explicitly before marking approval confirmation complete.
This can mark APPROVAL_CONFIRMATION as complete without actually confirming on-chain.

🧹 Nitpick comments (10)
apps/agentic-chat/src/components/tools/LimitOrderUI.tsx (1)

69-92: Minor: Inner component functions recreate on each render.

SwapPair and BuyAmount are defined inside the component body, causing new function instances on every render. For this UI, the impact is negligible, but if performance becomes a concern, consider memoizing or extracting them.

apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1)

192-200: Native token fallback may return original address for unmapped chains.

If WETH_ADDRESSES[evmChainId] is undefined (e.g., for a new chain), the fallback || sellTokenAddress returns the native token address, which CoW Protocol likely doesn't accept. This is partially guarded by isCowSupportedChain, but adding explicit validation would be safer.

   const sellToken =
     sellTokenAddress.toLowerCase() === NATIVE_TOKEN_ADDRESS.toLowerCase()
-      ? WETH_ADDRESSES[evmChainId] || sellTokenAddress
+      ? WETH_ADDRESSES[evmChainId] ?? (() => { throw new Error(`No WETH mapping for chain ${evmChainId}`) })()
       : sellTokenAddress

   const buyToken =
     buyTokenAddress.toLowerCase() === NATIVE_TOKEN_ADDRESS.toLowerCase()
-      ? WETH_ADDRESSES[evmChainId] || buyTokenAddress
+      ? WETH_ADDRESSES[evmChainId] ?? (() => { throw new Error(`No WETH mapping for chain ${evmChainId}`) })()
       : buyTokenAddress
apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (2)

113-173: Sequential chain fetching increases latency.

The for...of loop queries chains sequentially. For users with wallets on multiple chains, this creates cumulative latency. Consider parallelizing with Promise.allSettled:

-  for (const chainId of chainsToQuery) {
-    const chainIdString = `eip155:${chainId}`
-    let userAddress: string
-    try {
-      userAddress = getAddressForChain(walletContext, chainIdString)
-    } catch {
-      continue
-    }
-
-    try {
-      const orders = await getCowOrders(userAddress, chainId, { limit: 50 })
-      // ... process orders
-    } catch (error) {
-      console.warn(`Failed to fetch orders from chain ${chainId}:`, error)
-    }
-  }
+  const fetchPromises = chainsToQuery.map(async (chainId) => {
+    const chainIdString = `eip155:${chainId}`
+    let userAddress: string
+    try {
+      userAddress = getAddressForChain(walletContext, chainIdString)
+    } catch {
+      return [] // No wallet for this chain
+    }
+
+    try {
+      const orders = await getCowOrders(userAddress, chainId, { limit: 50 })
+      // ... process and return orders
+    } catch (error) {
+      console.warn(`Failed to fetch orders from chain ${chainId}:`, error)
+      return []
+    }
+  })
+
+  const results = await Promise.allSettled(fetchPromises)
+  for (const result of results) {
+    if (result.status === 'fulfilled') {
+      allOrders.push(...result.value)
+    }
+  }

44-44: Magic number for default decimals.

Consider extracting DEFAULT_DECIMALS = 18 to a shared constants file or adding a comment explaining why 18 is the fallback (standard ERC-20 decimals).

apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (1)

34-48: Consider explaining chain priority order.

The chain order [1, 42161, 100] (Ethereum, Arbitrum, Gnosis) is stated as "most likely chains first", but this assumption may change over time or differ based on usage patterns.

Consider adding a brief comment explaining the priority rationale or making it configurable:

-  // Try each chain to find the order
-  const chainsToTry = [1, 42161, 100] // Most likely chains first
+  // Try chains in order of typical usage volume: Ethereum > Arbitrum > Gnosis
+  const chainsToTry = [1, 42161, 100]
apps/agentic-chat/src/components/Portfolio/ActivityRow/index.tsx (2)

20-24: Add a defensive fallback for unknown activity types (runtime safety).
Even if ActivityItem is a union, activity data can still be malformed at runtime; ACTIVITY_ICONS[activity.type] would become undefined and crash render.

 const ACTIVITY_ICONS = {
   swap: ArrowRightLeft,
   send: Send,
   limit_order: Timer,
 }
@@
 export function ActivityRow({ activity }: ActivityRowProps) {
-  const Icon = ACTIVITY_ICONS[activity.type]
+  const Icon = ACTIVITY_ICONS[activity.type] ?? Timer

Also applies to: 71-78


30-39: Make formatActivityTitle() exhaustiveness explicit.
Right now there’s no default, so a future ActivityItem extension can silently return undefined at runtime.

 function formatActivityTitle(activity: ActivityItem): string {
   switch (activity.type) {
     case 'swap':
       return `Swapped ${formatCryptoAmount(activity.details.sellAsset.amount, { symbol: activity.details.sellAsset.symbol })} to ${formatCryptoAmount(activity.details.buyAsset.amount, { symbol: activity.details.buyAsset.symbol })}`
     case 'send':
       return `Sent ${formatCryptoAmount(activity.details.asset.amount, { symbol: activity.details.asset.symbol })}`
     case 'limit_order':
       return `Limit order: ${formatCryptoAmount(activity.details.sellAsset.amount, { symbol: activity.details.sellAsset.symbol })} → ${formatCryptoAmount(activity.details.buyAsset.estimatedAmount, { symbol: activity.details.buyAsset.symbol })}`
   }
+  // If `ActivityItem` is widened without updating this switch, fail loudly.
+  return 'Activity'
 }
apps/agentic-chat/src/hooks/useCancelLimitOrderExecution.tsx (2)

140-168: Add timeout/abort + surface structured API errors for cancellation submission.
Right now fetch() can hang indefinitely, and response.text() may not be helpful/consistent error parsing.

At minimum, wrap with AbortController + a reasonable timeout, and include HTTP status in the thrown error.


141-146: Avoid duplicating CoW chain → base URL mapping across hooks.
This mapping is repeated in useLimitOrderExecution.tsx; centralize it (e.g., apps/agentic-chat/src/lib/cow.ts) to prevent drift.

Also applies to: 147-150

apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (1)

166-216: Harden order submission: timeout + response parsing.
response.text() and stripping quotes is brittle; prefer await response.json() (or at least handle a plain string vs JSON string explicitly), and add an abort timeout to avoid hanging tool executions.

📜 Review details

Configuration used: CodeRabbit 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 940daa0 and dfd2b10.

📒 Files selected for processing (24)
  • apps/agentic-chat/src/components/Portfolio/ActivityList.tsx (2 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx (0 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/LimitOrderDetails.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SendDetails.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/index.tsx (1 hunks)
  • apps/agentic-chat/src/components/toolUIRegistry.tsx (2 hunks)
  • apps/agentic-chat/src/components/tools/CancelLimitOrderUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/LimitOrderUI.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useCancelLimitOrderExecution.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useToolExecutionEffect.ts (1 hunks)
  • apps/agentic-chat/src/lib/activityNormalizer.ts (3 hunks)
  • apps/agentic-chat/src/stores/chatStore.ts (2 hunks)
  • apps/agentic-chat/src/types/activity.ts (2 hunks)
  • apps/agentic-server/src/index.ts (1 hunks)
  • apps/agentic-server/src/lib/cow/index.ts (1 hunks)
  • apps/agentic-server/src/lib/cow/types.ts (1 hunks)
  • apps/agentic-server/src/routes/chat.ts (4 hunks)
  • apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/index.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx
🚧 Files skipped from review as they are similar to previous changes (6)
  • apps/agentic-chat/src/components/toolUIRegistry.tsx
  • apps/agentic-server/src/routes/chat.ts
  • apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx
  • apps/agentic-server/src/lib/cow/index.ts
  • apps/agentic-server/src/index.ts
  • apps/agentic-server/src/tools/limitOrder/index.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-22T20:32:10.539Z
Learnt from: kaladinlight
Repo: shapeshift/agentic-chat PR: 76
File: apps/agentic-server/src/mastra/tools/asset/coingecko/constants.ts:1-10
Timestamp: 2025-09-22T20:32:10.539Z
Learning: When cross-app dependencies are identified (like server code importing from chat packages), the user prefers to extract shared constants into dedicated packages in the packages/ directory following the existing pattern of shapeshiftoss/types and shapeshiftoss/utils.

Applied to files:

  • apps/agentic-chat/src/stores/chatStore.ts
🧬 Code graph analysis (9)
apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SendDetails.tsx (5)
apps/agentic-chat/src/types/activity.ts (1)
  • SendActivityDetails (28-37)
apps/agentic-chat/src/components/ui/ToolCard.tsx (1)
  • ToolCard (71-78)
apps/agentic-chat/src/components/ui/Amount.tsx (1)
  • Amount (88-92)
apps/agentic-chat/src/lib/utils.ts (1)
  • truncateAddress (9-12)
apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx (1)
  • SendDetails (85-99)
apps/agentic-chat/src/stores/chatStore.ts (2)
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1)
  • CreateLimitOrderOutput (90-106)
apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (1)
  • CancelLimitOrderOutput (26-32)
apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx (6)
apps/agentic-chat/src/types/activity.ts (1)
  • SwapActivityDetails (9-26)
apps/agentic-chat/src/lib/explorers.ts (1)
  • getExplorerUrl (1-15)
apps/agentic-chat/src/components/ui/ToolCard.tsx (1)
  • ToolCard (71-78)
apps/agentic-chat/src/components/ui/Amount.tsx (1)
  • Amount (88-92)
apps/agentic-chat/src/lib/utils.ts (1)
  • truncateAddress (9-12)
apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx (1)
  • SwapDetails (30-83)
apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (4)
apps/agentic-server/src/lib/cow/types.ts (5)
  • CowOrderStatus (5-5)
  • CowOrder (7-22)
  • NETWORK_TO_CHAIN_ID (83-87)
  • COW_SUPPORTED_CHAINS (75-80)
  • getCowExplorerUrl (100-102)
packages/types/src/network.ts (1)
  • Network (44-44)
apps/agentic-server/src/utils/walletContextSimple.ts (2)
  • WalletContext (4-6)
  • getAddressForChain (13-26)
packages/utils/src/index.ts (1)
  • fromBaseUnit (38-41)
apps/agentic-chat/src/components/Portfolio/ActivityRow/components/LimitOrderDetails.tsx (3)
apps/agentic-chat/src/types/activity.ts (1)
  • LimitOrderActivityDetails (39-52)
apps/agentic-chat/src/components/ui/ToolCard.tsx (1)
  • ToolCard (71-78)
apps/agentic-chat/src/components/ui/Amount.tsx (1)
  • Amount (88-92)
apps/agentic-chat/src/hooks/useCancelLimitOrderExecution.tsx (5)
apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (1)
  • CancelLimitOrderOutput (26-32)
apps/agentic-chat/src/stores/chatStore.ts (2)
  • PersistedToolState (22-30)
  • useChatStore (75-194)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (23-48)
apps/agentic-chat/src/providers/ChatProvider.tsx (1)
  • useChatContext (33-39)
apps/agentic-chat/src/hooks/useToolExecutionEffect.ts (1)
  • useToolExecutionEffect (10-60)
apps/agentic-chat/src/lib/activityNormalizer.ts (5)
apps/agentic-chat/src/stores/chatStore.ts (1)
  • PersistedToolState (22-30)
apps/agentic-chat/src/types/activity.ts (2)
  • ActivityItem (70-70)
  • LimitOrderActivityDetails (39-52)
apps/agentic-server/src/index.ts (1)
  • CreateLimitOrderOutput (95-95)
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1)
  • CreateLimitOrderOutput (90-106)
apps/agentic-server/src/tools/limitOrder/index.ts (1)
  • CreateLimitOrderOutput (6-6)
apps/agentic-chat/src/components/Portfolio/ActivityRow/index.tsx (8)
apps/agentic-chat/src/types/activity.ts (1)
  • ActivityItem (70-70)
apps/agentic-chat/src/lib/explorers.ts (1)
  • getExplorerUrl (1-15)
apps/agentic-chat/src/components/ui/ToolCard.tsx (1)
  • ToolCard (71-78)
apps/agentic-chat/src/lib/utils.ts (1)
  • truncateAddress (9-12)
apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx (1)
  • SwapDetails (18-71)
apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SendDetails.tsx (1)
  • SendDetails (10-24)
apps/agentic-chat/src/components/Portfolio/ActivityRow/components/LimitOrderDetails.tsx (1)
  • LimitOrderDetails (15-48)
apps/agentic-chat/src/components/ui/DrawerListItem.tsx (1)
  • DrawerListItem (13-41)
apps/agentic-chat/src/components/tools/LimitOrderUI.tsx (6)
apps/agentic-chat/src/components/tools/toolUIHelpers.tsx (1)
  • ToolUIComponentProps (6-8)
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1)
  • CreateLimitOrderOutput (90-106)
apps/agentic-server/src/tools/limitOrder/index.ts (1)
  • CreateLimitOrderOutput (6-6)
apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (1)
  • useLimitOrderExecution (218-423)
apps/agentic-chat/src/components/ui/TxStepCard.tsx (1)
  • TxStepCard (149-162)
apps/agentic-chat/src/components/ui/TruncateText.tsx (1)
  • TruncateText (9-26)
⏰ 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: main
🔇 Additional comments (13)
apps/agentic-chat/src/hooks/useToolExecutionEffect.ts (1)

44-52: LGTM! Error handling improves resilience.

The try/catch wrapper prevents unhandled promise rejections from crashing the execution flow, and void executeWrapper() correctly signals fire-and-forget intent.

One consideration: errors are only logged to console and not exposed to the UI state. If downstream components need to display tool execution failures, consider updating the state with error information within the catch block.

apps/agentic-chat/src/components/tools/CancelLimitOrderUI.tsx (1)

1-125: LGTM! Well-structured cancellation UI component.

The component properly handles:

  • Historical skip scenarios
  • Step validation before rendering
  • Error state propagation to footer
  • External link security attributes (rel="noopener noreferrer")

Minor UX note: Using XCircle with green color for successful cancellation (line 67) might be slightly confusing since X typically indicates failure. Consider using CheckCircle for the completed state while keeping XCircle for the in-progress state.

apps/agentic-chat/src/components/tools/LimitOrderUI.tsx (1)

165-175: LGTM! External link security.

Proper use of target="_blank" with rel="noopener noreferrer" prevents reverse tabnabbing.

apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (2)

9-32: LGTM! Well-structured schema and type definitions.

The Zod schema provides clear descriptions for the AI agent, and the TypeScript interfaces properly model the EIP-712 cancellation data structure.


50-109: LGTM! Solid security and validation logic.

The function properly:

  • Validates ownership by comparing wallet addresses
  • Prevents cancellation of already filled/cancelled/expired orders
  • Provides clear error messages for each failure case
apps/agentic-chat/src/stores/chatStore.ts (1)

2-8: LGTM! Consistent extension of store types.

The additions follow the established pattern for tool state management, adding limit order types alongside existing swap/send types.

Also applies to: 24-24, 29-29

apps/agentic-chat/src/components/Portfolio/ActivityList.tsx (1)

15-15: LGTM! Clean integration of limit order activities.

The changes properly extend activity filtering to include limit orders and add sensible descending timestamp sorting for a better user experience.

Also applies to: 19-19, 26-26

apps/agentic-chat/src/components/Portfolio/ActivityRow/components/LimitOrderDetails.tsx (1)

1-48: LGTM! Well-structured detail component.

The component cleanly renders all limit order fields with appropriate formatting. The click handler on line 11-13 correctly prevents event propagation for the tracking link.

apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SendDetails.tsx (1)

1-24: LGTM! Clean component extraction.

This is a straightforward refactor that extracts send details rendering into a dedicated component, improving code organization and maintainability.

apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx (1)

1-71: LGTM! Clean component extraction.

This refactor successfully extracts swap details rendering into a dedicated component. The conditional approval TX section and link handling are implemented correctly.

apps/agentic-chat/src/types/activity.ts (1)

39-70: LGTM! Well-designed activity type extensions.

The LimitOrderActivityItem correctly omits txHash from the base type since limit orders use orderId instead. This design appropriately reflects the different lifecycle of limit orders vs immediate transactions.

apps/agentic-chat/src/lib/activityNormalizer.ts (1)

1-23: LGTM! Clean dispatch routing.

The normalization dispatcher correctly routes limit orders to the new handler, following the established pattern for swap and send activities.

apps/agentic-chat/src/components/Portfolio/ActivityRow/index.tsx (1)

41-67: Details rendering looks clean and consistent.
Stopping propagation on links is the right move to avoid toggling the drawer, and per-type detail components keep this maintainable.

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: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/agentic-server/src/routes/chat.ts (1)

272-311: Fix tool naming mismatch in system prompt for limit order tools.

The system prompt (lines 305, 308-309) instructs the model to use createLimitOrder, getLimitOrders, and cancelLimitOrder, but the registered tool keys in buildTools() (lines 164-186) are createLimitOrderTool, getLimitOrdersTool, and cancelLimitOrderTool. The model will fail to invoke these tools because the names in the prompt don't match the registered keys. Update lines 305, 308-309 to use the suffixed names: createLimitOrderTool, getLimitOrdersTool, cancelLimitOrderTool.

♻️ Duplicate comments (12)
apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx (1)

174-187: Verify that sellAmount and buyAmount from server are human-readable values.

The Amount.Crypto component will display these values directly. If the server returns base-unit amounts (wei, etc.), users will see misleading large numbers. This concern was raised in a previous review.

#!/bin/bash
# Check getLimitOrders output structure to verify amount format
ast-grep --pattern 'interface OrderInfo {
  $$$
}'

# Also check the getLimitOrders implementation
rg -n "sellAmount|buyAmount" --type ts -A2 -B2 apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (3)

108-120: Precision loss from parseFloat for financial calculations.

This issue was flagged in a previous review. The function uses parseFloat which loses precision for large numbers or decimals with many significant digits, potentially mispricing orders.


135-136: Remove or redact sensitive input logging.

This issue was flagged in a previous review. Logging the full input can leak user intent and amounts.


273-273: trackingUrl with placeholder 'pending' may confuse users.

This issue was flagged in a previous review. Users clicking this link would land on a non-existent order page.

apps/agentic-chat/src/lib/activityNormalizer.ts (1)

110-110: Hardcoded mainnet URL ignores network-specific explorer paths.

This issue was flagged in a previous review. The hardcoded URL https://explorer.cow.fi/orders/${orderId} produces the mainnet format regardless of chain. CoW explorer uses different paths for Gnosis (/gnosis/orders/) and Arbitrum (/arbitrum/orders/).

Consider using the output's trackingUrl if available, or constructing the URL based on chainId:

-    trackingUrl: `https://explorer.cow.fi/orders/${orderId}`,
+    trackingUrl: output.trackingUrl ?? `https://explorer.cow.fi/orders/${orderId}`,
apps/agentic-chat/src/components/tools/LimitOrderUI.tsx (1)

50-58: Fix completedCount to match the rendered “effective” step statuses (approval skipped).
Right now progress can disagree with the UI when needsApproval is false.

-  const completedCount = [
-    prepareStep.status,
-    networkStep.status,
-    approvalStep.status,
-    approvalConfirmStep.status,
-    signStep.status,
-    submitStep.status,
-  ].filter(s => s === StepStatus.COMPLETE || s === StepStatus.SKIPPED).length
+  const effectiveApprovalStatus = needsApproval ? approvalStep.status : StepStatus.SKIPPED
+  const effectiveApprovalConfirmStatus = needsApproval ? approvalConfirmStep.status : StepStatus.SKIPPED
+  const completedCount = [
+    prepareStep.status,
+    networkStep.status,
+    effectiveApprovalStatus,
+    effectiveApprovalConfirmStatus,
+    signStep.status,
+    submitStep.status,
+  ].filter(s => s === StepStatus.COMPLETE || s === StepStatus.SKIPPED).length

Also applies to: 141-163

apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (3)

113-173: Parallelize per-chain fetch (independent calls) and keep partial failures.
Today each chain is fetched sequentially; worst-case latency scales with #chains.

-  for (const chainId of chainsToQuery) {
+  await Promise.allSettled(
+    chainsToQuery.map(async chainId => {
       // Get user address for this chain
       const chainIdString = `eip155:${chainId}`
       let userAddress: string
       try {
         userAddress = getAddressForChain(walletContext, chainIdString)
       } catch {
         // User doesn't have wallet connected for this chain, skip
-      continue
+        return
       }
 
       try {
         const orders = await getCowOrders(userAddress, chainId, { limit: 50 })
@@
-    } catch (error) {
+      } catch (error) {
         // ...
-    }
-  }
+      }
+    })
+  )

11-21: Preserve presignaturePending (don’t collapse it to open) and consider aligning filled vs fulfilled vocabulary.
formatOrderStatus() currently maps presignaturePendingopen, losing an important CoW order state; and the input schema uses filled while the underlying type is fulfilled.

 export const getLimitOrdersSchema = z.object({
   status: z
-    .enum(['open', 'filled', 'cancelled', 'expired', 'all'])
+    .enum(['open', 'filled', 'cancelled', 'expired', 'presignaturePending', 'all'])
     .optional()
     .default('all')
     .describe('Filter orders by status. Default is "all".'),
@@
 function mapStatusFilter(status: string): CowOrderStatus | null {
   switch (status) {
@@
     case 'expired':
       return 'expired'
+    case 'presignaturePending':
+      return 'presignaturePending'
     default:
       return null
   }
 }
 
 function formatOrderStatus(status: CowOrderStatus): CowOrderStatus {
-  // Map CoW status to our simplified status
   if (status === 'fulfilled') return 'fulfilled'
-  if (status === 'presignaturePending') return 'open'
   return status
 }

Also applies to: 59-72, 74-79


89-93: Remove/redact console.log / console.warn (PII + user intent) and use the server logger.

 export async function executeGetLimitOrders(
   input: GetLimitOrdersInput,
   walletContext?: WalletContext
 ): Promise<GetLimitOrdersOutput> {
-  console.log('[getLimitOrders]:', JSON.stringify(input, null, 2))
+  // TODO: use structured logger + redact (avoid logging wallet addresses / user intent)
@@
-    } catch (error) {
-      console.warn(`Failed to fetch orders from chain ${chainId}:`, error)
+    } catch (error) {
+      // TODO: logger.warn({ chainId, err: safeError(error) }, 'Failed to fetch orders from chain')
       // Continue with other chains
     }
   }

Also applies to: 169-172

apps/agentic-chat/src/hooks/useCancelLimitOrderExecution.tsx (1)

41-79: Persist + rehydrate currentStep and failedStep (post-refresh step UI is currently wrong).

 function cancelOrderStateToPersistedState(
@@
   return {
@@
     meta: {
       ...(orderOutput?.orderId && { orderId: orderOutput.orderId }),
       ...(state.error && { error: state.error }),
+      ...(state.failedStep !== undefined && { failedStep: state.failedStep }),
+      ...(state.currentStep !== undefined && { currentStep: state.currentStep }),
       ...(networkName && { networkName }),
     },
@@
 }
 
 function persistedStateToCancelOrderState(persisted: PersistedToolState): CancelOrderState {
   const completedSteps = new Set<CancelOrderStep>()
-  const currentStep = CancelOrderStep.COMPLETE
+  const currentStep = (persisted.meta.currentStep as CancelOrderStep | undefined) ?? CancelOrderStep.COMPLETE
@@
   return {
     currentStep,
     completedSteps,
     error: persisted.meta.error as string | undefined,
+    failedStep: persisted.meta.failedStep as CancelOrderStep | undefined,
   }
 }

Also applies to: 81-103

apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (2)

49-95: Persist + rehydrate currentStep and failedStep (same step-status fidelity bug as before).

   return {
@@
     meta: {
       ...(state.orderId && { orderId: state.orderId }),
       ...(state.approvalTxHash && { approvalTxHash: state.approvalTxHash }),
       ...(state.error && { error: state.error }),
+      ...(state.failedStep !== undefined && { failedStep: state.failedStep }),
+      ...(state.currentStep !== undefined && { currentStep: state.currentStep }),
       ...(networkName && { networkName }),
     },
@@
 function persistedStateToLimitOrderState(persisted: PersistedToolState): LimitOrderState {
   const completedSteps = new Set<LimitOrderStep>()
-  const currentStep = LimitOrderStep.COMPLETE
+  const currentStep = (persisted.meta.currentStep as LimitOrderStep | undefined) ?? LimitOrderStep.COMPLETE
@@
   return {
     currentStep,
     completedSteps,
     orderId: persisted.meta.orderId as string | undefined,
     approvalTxHash: persisted.meta.approvalTxHash as string | undefined,
     error: persisted.meta.error as string | undefined,
+    failedStep: persisted.meta.failedStep as LimitOrderStep | undefined,
   }
 }

Also applies to: 96-126


282-298: Handle missing publicClient explicitly (don’t silently skip receipt confirmation).

         const publicClient = getPublicClient(wagmiConfig, {
           chainId: orderParams.chainId,
         })
-        if (publicClient) {
-          await publicClient.waitForTransactionReceipt({
-            hash: approvalTxHash as `0x${string}`,
-            confirmations: 1,
-          })
-        }
+        if (!publicClient) {
+          throw new Error(`No public client for chain ${orderParams.chainId}; cannot confirm approval transaction`)
+        }
+        await publicClient.waitForTransactionReceipt({
+          hash: approvalTxHash as `0x${string}`,
+          confirmations: 1,
+        })
🧹 Nitpick comments (7)
apps/agentic-chat/src/lib/cow-config.ts (1)

2-6: Consider tightening types to prevent accidental unsupported chain calls.
If the supported set is intentionally small, you can make it harder to call getCowApiUrl() with arbitrary numbers by using an as const map + derived union type (and/or an isSupportedCowChainId() type guard).

Also applies to: 8-14

apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx (1)

102-107: filledPercent display logic may be misleading for fulfilled orders.

For fulfilled orders (status === 'fulfilled'), showing "X% filled" when it's 100% filled is redundant. Consider showing this only for partially filled orders or changing the label.

-          {isFilled && filledPercent > 0 && (
+          {isFilled && filledPercent > 0 && filledPercent < 100 && (
             <>
               <span>•</span>
-              <span>{filledPercent}% filled</span>
+              <span>{filledPercent}% partially filled</span>
             </>
           )}
apps/agentic-chat/src/components/Portfolio/ActivityRow/index.tsx (2)

20-24: Harden icon mapping against future ActivityItem['type'] additions (avoid Icon being undefined).
Today it’s safe via the union, but this will become a runtime crash if a new type ships before this file is updated.

-const ACTIVITY_ICONS = {
+const ACTIVITY_ICONS = {
   swap: ArrowRightLeft,
   send: Send,
   limit_order: Timer,
-}
+} satisfies Record<ActivityItem['type'], React.ComponentType<{ className?: string }>>

Also applies to: 67-74


26-35: Make formatActivityTitle() exhaustiveness explicit (prevents accidental undefined titles).
Right now it relies on the union being perfectly in sync. An explicit guard makes failures loud during dev.

 function formatActivityTitle(activity: ActivityItem): string {
   switch (activity.type) {
     case 'swap':
       return `Swapped ${formatCryptoAmount(activity.details.sellAsset.amount, { symbol: activity.details.sellAsset.symbol })} to ${formatCryptoAmount(activity.details.buyAsset.amount, { symbol: activity.details.buyAsset.symbol })}`
     case 'send':
       return `Sent ${formatCryptoAmount(activity.details.asset.amount, { symbol: activity.details.asset.symbol })}`
     case 'limit_order':
       return `Limit order: ${formatCryptoAmount(activity.details.sellAsset.amount, { symbol: activity.details.sellAsset.symbol })} → ${formatCryptoAmount(activity.details.buyAsset.estimatedAmount, { symbol: activity.details.buyAsset.symbol })}`
   }
+  // If `ActivityItem` expands, fail loudly instead of rendering an empty title.
+  // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
+  throw new Error(`Unhandled activity type: ${(activity as any).type}`)
 }
apps/agentic-chat/src/components/tools/CancelLimitOrderUI.tsx (2)

50-54: Ensure error is always a string before interpolating (avoid Cancellation failed: [object Object]).
If the hook ever returns a non-string, this UI will degrade.
-->

-    if (error) return { type: 'error' as const, text: `Cancellation failed: ${error}` }
+    if (error) return { type: 'error' as const, text: `Cancellation failed: ${String(error)}` }

66-69: Optional: use a success icon when complete (XCircle-in-green reads odd).
Consider CheckCircle for complete and keep XCircle for error/failed states.

apps/agentic-server/src/routes/chat.ts (1)

164-187: Optional: reduce repetition with a wrapWalletToolWithLogging() helper.
The three limit-order tool blocks are mechanically identical to other walletContext wrappers here.

+function wrapWalletToolWithLogging<T extends { description: string; inputSchema: unknown }>(
+  name: string,
+  tool: T & { execute: (args: any, walletContext: WalletContext) => unknown },
+  walletContext: WalletContext
+) {
+  return {
+    description: tool.description,
+    inputSchema: tool.inputSchema,
+    execute: async (args: Parameters<typeof tool.execute>[0]) => {
+      console.log(`[Tool] ${name}:`, JSON.stringify(args, null, 2))
+      return tool.execute(args, walletContext)
+    },
+  }
+}

(Then use it for createLimitOrderTool, getLimitOrdersTool, cancelLimitOrderTool.)

📜 Review details

Configuration used: CodeRabbit 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 dfd2b10 and 7536eb0.

📒 Files selected for processing (27)
  • apps/agentic-chat/src/components/Portfolio/ActivityList.tsx (2 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx (0 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/LimitOrderDetails.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SendDetails.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/index.tsx (1 hunks)
  • apps/agentic-chat/src/components/toolUIRegistry.tsx (2 hunks)
  • apps/agentic-chat/src/components/tools/CancelLimitOrderUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/LimitOrderUI.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useCancelLimitOrderExecution.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useToolExecutionEffect.ts (1 hunks)
  • apps/agentic-chat/src/lib/activityNormalizer.ts (3 hunks)
  • apps/agentic-chat/src/lib/cow-config.ts (1 hunks)
  • apps/agentic-chat/src/lib/eventHandlers.ts (1 hunks)
  • apps/agentic-chat/src/lib/stepUtils.ts (1 hunks)
  • apps/agentic-chat/src/stores/chatStore.ts (2 hunks)
  • apps/agentic-chat/src/types/activity.ts (2 hunks)
  • apps/agentic-server/src/index.ts (1 hunks)
  • apps/agentic-server/src/lib/cow/index.ts (1 hunks)
  • apps/agentic-server/src/lib/cow/types.ts (1 hunks)
  • apps/agentic-server/src/routes/chat.ts (4 hunks)
  • apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/index.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx
🚧 Files skipped from review as they are similar to previous changes (11)
  • apps/agentic-chat/src/hooks/useToolExecutionEffect.ts
  • apps/agentic-chat/src/stores/chatStore.ts
  • apps/agentic-chat/src/components/toolUIRegistry.tsx
  • apps/agentic-server/src/index.ts
  • apps/agentic-chat/src/types/activity.ts
  • apps/agentic-chat/src/components/Portfolio/ActivityList.tsx
  • apps/agentic-server/src/lib/cow/types.ts
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SendDetails.tsx
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/LimitOrderDetails.tsx
  • apps/agentic-server/src/lib/cow/index.ts
🧰 Additional context used
🧬 Code graph analysis (11)
apps/agentic-chat/src/lib/cow-config.ts (1)
apps/agentic-server/src/lib/cow/types.ts (1)
  • getCowApiUrl (104-117)
apps/agentic-chat/src/lib/activityNormalizer.ts (5)
apps/agentic-chat/src/stores/chatStore.ts (1)
  • PersistedToolState (22-30)
apps/agentic-chat/src/types/activity.ts (2)
  • ActivityItem (70-70)
  • LimitOrderActivityDetails (39-52)
apps/agentic-server/src/index.ts (1)
  • CreateLimitOrderOutput (95-95)
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1)
  • CreateLimitOrderOutput (90-106)
apps/agentic-server/src/tools/limitOrder/index.ts (1)
  • CreateLimitOrderOutput (6-6)
apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx (8)
apps/agentic-chat/src/lib/utils.ts (1)
  • cn (5-7)
apps/agentic-chat/src/components/ui/Amount.tsx (1)
  • Amount (88-92)
apps/agentic-chat/src/lib/eventHandlers.ts (1)
  • stopPropagationHandler (4-6)
apps/agentic-chat/src/components/tools/toolUIHelpers.tsx (2)
  • ToolUIComponentProps (6-8)
  • useToolStateRender (10-31)
apps/agentic-server/src/index.ts (1)
  • GetLimitOrdersOutput (102-102)
apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (1)
  • GetLimitOrdersOutput (54-57)
apps/agentic-server/src/tools/limitOrder/index.ts (1)
  • GetLimitOrdersOutput (15-15)
apps/agentic-chat/src/components/ui/ToolCard.tsx (1)
  • ToolCard (71-78)
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (9)
apps/agentic-server/src/lib/schemas/swapSchemas.ts (2)
  • TransactionData (75-75)
  • assetInputSchema (15-21)
packages/caip/src/assetId.ts (1)
  • fromAssetId (87-106)
apps/agentic-server/src/utils/transactionHelpers.ts (1)
  • createTransaction (17-33)
apps/agentic-server/src/tools/limitOrder/index.ts (1)
  • createLimitOrderTool (2-2)
apps/agentic-server/src/lib/cow/types.ts (3)
  • CowOrderSigningData (48-53)
  • isCowSupportedChain (96-98)
  • getCowExplorerUrl (100-102)
apps/agentic-server/src/utils/walletContextSimple.ts (2)
  • WalletContext (4-6)
  • getAddressForChain (13-26)
apps/agentic-server/src/utils/assetHelpers.ts (1)
  • resolveAsset (8-25)
apps/agentic-server/src/lib/cow/index.ts (2)
  • COW_VAULT_RELAYER_ADDRESS (30-30)
  • prepareCowLimitOrder (70-114)
apps/agentic-server/src/utils/getAllowance.ts (1)
  • getAllowance (24-57)
apps/agentic-chat/src/components/Portfolio/ActivityRow/index.tsx (9)
apps/agentic-chat/src/types/activity.ts (1)
  • ActivityItem (70-70)
apps/agentic-chat/src/lib/explorers.ts (1)
  • getExplorerUrl (1-15)
apps/agentic-chat/src/components/ui/ToolCard.tsx (1)
  • ToolCard (71-78)
apps/agentic-chat/src/lib/eventHandlers.ts (1)
  • stopPropagationHandler (4-6)
apps/agentic-chat/src/lib/utils.ts (1)
  • truncateAddress (9-12)
apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx (1)
  • SwapDetails (13-66)
apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SendDetails.tsx (1)
  • SendDetails (10-24)
apps/agentic-chat/src/components/Portfolio/ActivityRow/components/LimitOrderDetails.tsx (1)
  • LimitOrderDetails (10-43)
apps/agentic-chat/src/components/ui/DrawerListItem.tsx (1)
  • DrawerListItem (13-41)
apps/agentic-chat/src/lib/stepUtils.ts (1)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (23-48)
apps/agentic-server/src/routes/chat.ts (5)
apps/agentic-server/src/index.ts (3)
  • createLimitOrderTool (92-92)
  • getLimitOrdersTool (99-99)
  • cancelLimitOrderTool (105-105)
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1)
  • createLimitOrderTool (277-299)
apps/agentic-server/src/tools/limitOrder/index.ts (3)
  • createLimitOrderTool (2-2)
  • getLimitOrdersTool (11-11)
  • cancelLimitOrderTool (19-19)
apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (1)
  • getLimitOrdersTool (184-205)
apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (1)
  • cancelLimitOrderTool (111-130)
apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (4)
apps/agentic-server/src/lib/cow/types.ts (6)
  • CowOrderStatus (5-5)
  • CHAIN_ID_TO_NETWORK (90-94)
  • CowOrder (7-22)
  • NETWORK_TO_CHAIN_ID (83-87)
  • COW_SUPPORTED_CHAINS (75-80)
  • getCowExplorerUrl (100-102)
apps/agentic-server/src/utils/walletContextSimple.ts (2)
  • WalletContext (4-6)
  • getAddressForChain (13-26)
apps/agentic-server/src/lib/cow/index.ts (1)
  • getCowOrders (168-188)
packages/utils/src/index.ts (1)
  • fromBaseUnit (38-41)
apps/agentic-chat/src/components/tools/LimitOrderUI.tsx (9)
apps/agentic-chat/src/components/tools/toolUIHelpers.tsx (1)
  • ToolUIComponentProps (6-8)
apps/agentic-server/src/index.ts (1)
  • CreateLimitOrderOutput (95-95)
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1)
  • CreateLimitOrderOutput (90-106)
apps/agentic-server/src/tools/limitOrder/index.ts (1)
  • CreateLimitOrderOutput (6-6)
apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (1)
  • useLimitOrderExecution (185-390)
apps/agentic-chat/src/components/ui/TxStepCard.tsx (1)
  • TxStepCard (149-162)
apps/agentic-chat/src/components/ui/Skeleton.tsx (1)
  • Skeleton (7-7)
apps/agentic-chat/src/components/ui/Amount.tsx (1)
  • Amount (88-92)
apps/agentic-chat/src/components/ui/TruncateText.tsx (1)
  • TruncateText (9-26)
apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (3)
apps/agentic-server/src/lib/cow/types.ts (4)
  • CowEIP712Domain (37-42)
  • NETWORK_TO_CHAIN_ID (83-87)
  • CHAIN_ID_TO_NETWORK (90-94)
  • getCowExplorerUrl (100-102)
apps/agentic-server/src/lib/cow/index.ts (2)
  • getCowOrder (193-208)
  • prepareCowOrderCancellation (214-231)
apps/agentic-server/src/utils/walletContextSimple.ts (2)
  • WalletContext (4-6)
  • getAddressForChain (13-26)
apps/agentic-chat/src/hooks/useCancelLimitOrderExecution.tsx (6)
apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (1)
  • CancelLimitOrderOutput (26-32)
apps/agentic-chat/src/stores/chatStore.ts (1)
  • PersistedToolState (22-30)
apps/agentic-chat/src/lib/cow-config.ts (1)
  • getCowApiUrl (8-14)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (23-48)
apps/agentic-chat/src/providers/ChatProvider.tsx (1)
  • useChatContext (33-39)
apps/agentic-chat/src/lib/stepUtils.ts (1)
  • signTypedDataWithWallet (32-48)
⏰ 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: main
🔇 Additional comments (20)
apps/agentic-chat/src/lib/stepUtils.ts (1)

32-48: LGTM!

The type assertions are well-documented, and the approach pragmatically handles the type mismatch between CoW Protocol's API format and viem's expectations.

apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (3)

27-52: LGTM!

The approval transaction builder correctly handles the ERC20 approve encoding and chain validation.


54-68: LGTM!

The schema has sensible defaults (168 hours = 7 days) and clear descriptions for the AI to understand limit price semantics.


277-299: LGTM!

The tool definition has clear documentation including the important note about using the maths tool to calculate limitPrice from total amounts.

apps/agentic-chat/src/lib/eventHandlers.ts (1)

1-6: LGTM!

Simple, focused utility that prevents click propagation. The React MouseEvent typing is correct.

apps/agentic-chat/src/lib/activityNormalizer.ts (3)

1-8: LGTM!

The imports are correctly updated to include the new limit order types.


18-19: LGTM!

The switch case correctly routes limit orders to the new normalization function.


92-122: LGTM overall structure.

The normalization function follows the established pattern for swap and send activities. The null checks and data mapping are consistent with other normalizers.

apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx (4)

15-27: LGTM!

The status configuration covers all CoW Protocol order states with appropriate icons and colors. The type guard isValidOrderStatus provides safe runtime validation.


29-39: LGTM!

Clean component with fallback to 'open' status config if lookup fails.


67-76: Good use of BigNumber for rate calculation.

The rate computation correctly uses BigNumber to avoid floating-point precision issues, and handles division by zero gracefully.


126-155: LGTM!

The component properly handles loading, error, and empty states using the shared useToolStateRender hook. The empty state UI is clean and informative.

apps/agentic-chat/src/components/tools/CancelLimitOrderUI.tsx (1)

13-25: Good step orchestration + historical-skipped handling.
The early-return paths make this resilient to missing persisted state and partial hydration.

apps/agentic-server/src/tools/limitOrder/index.ts (1)

1-24: Clean, discoverable public surface for limit-order tooling.
Nice consolidation for downstream imports.

apps/agentic-server/src/routes/chat.ts (1)

28-29: Wallet-context passthrough for limit-order tools looks consistent with the other wallet tools.
Good: context is passed server-side (vs relying on model-provided addresses).

Also applies to: 164-187

apps/agentic-chat/src/components/Portfolio/ActivityRow/index.tsx (1)

26-35: The code is correct as-is. activity.timestamp is properly typed as number (line 3 of types/activity.ts), which is an accepted parameter type for formatDistanceToNow. No parsing is required.

apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (1)

83-93: Cancellability + signing payload assembly looks correct.
Status gating is clear and prepareCowOrderCancellation() is wired through with primaryType.

Also applies to: 94-109

apps/agentic-chat/src/hooks/useCancelLimitOrderExecution.tsx (2)

118-137: Confirm CoW cancellation endpoint contract (DELETE with JSON body + signingScheme).
If CoW changes/varies by chain, this will fail at runtime.


195-225: Step transitions + error capture look solid.
failedStep = currentStep paired with toast + persistence is a good UX pattern (once hydration is fixed).

Also applies to: 237-253

apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (1)

142-183: CoW order submission payload: verify required fields + response parsing.
await response.text() + stripping quotes works, but consider JSON.parse if/when CoW returns JSON consistently.

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

♻️ Duplicate comments (19)
apps/agentic-chat/src/lib/stepUtils.ts (1)

14-20: Step status logic incorrectly reports completed current step as IN_PROGRESS.

When currentStep === step and the step exists in completedSteps, Line 17 returns IN_PROGRESS before Line 18 can check completion status. Move the completedSteps.has(step) check before the currentStep === step check.

Apply this diff:

 export function getStepStatus<TStep extends number>(step: TStep, state: StepState<TStep>): StepStatus {
   if (state.failedStep === step) return StepStatus.FAILED
+  if (state.completedSteps.has(step)) return StepStatus.COMPLETE
   if (state.currentStep < step) return StepStatus.NOT_STARTED
   if (state.currentStep === step && !state.error) return StepStatus.IN_PROGRESS
-  if (state.completedSteps.has(step)) return StepStatus.COMPLETE
   return StepStatus.SKIPPED
 }
apps/agentic-chat/src/lib/cow-config.ts (1)

2-14: Client/server CoW API URL logic is inconsistent.

The client throws on unsupported chains and omits Sepolia (chain ID 11155111), but the server (at apps/agentic-server/src/lib/cow/types.ts lines 103-116) includes Sepolia and defaults unknown chains to mainnet. This causes:

  1. Client-side limit orders fail hard on Sepolia or future chains
  2. Different error behavior between client and server

Align with server behavior:

 export const COW_API_URLS: Record<number, string> = {
+  11155111: 'https://api.cow.fi/sepolia',
 }
 
 export function getCowApiUrl(chainId: number): string {
-  const apiUrl = COW_API_URLS[chainId]
-  if (!apiUrl) {
-    throw new Error(`Unsupported chain for CoW Protocol: ${chainId}`)
-  }
-  return apiUrl
+  return COW_API_URLS[chainId] ?? COW_API_URLS[1]
 }
apps/agentic-chat/src/components/tools/LimitOrderUI.tsx (1)

50-58: completedCount disagrees with rendered step statuses when approval is skipped.

Lines 50-57 compute completedCount from raw step statuses, but Lines 148-157 render approval steps with conditional statuses (needsApproval ? status : StepStatus.SKIPPED). This causes the progress indicator to show incorrect completion counts when approval is not needed.

Compute completedCount using effective statuses:

+  const effectiveApprovalStatus = needsApproval ? approvalStep.status : StepStatus.SKIPPED
+  const effectiveApprovalConfirmStatus = needsApproval ? approvalConfirmStep.status : StepStatus.SKIPPED
   const completedCount = [
     prepareStep.status,
     networkStep.status,
-    approvalStep.status,
-    approvalConfirmStep.status,
+    effectiveApprovalStatus,
+    effectiveApprovalConfirmStatus,
     signStep.status,
     submitStep.status,
   ].filter(s => s === StepStatus.COMPLETE || s === StepStatus.SKIPPED).length
apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (3)

124-185: Consider parallel per-chain fetch with Promise.allSettled.

This issue was previously flagged and remains unaddressed. Sequential chain calls increase worst-case latency.

Parallelize:

- const allOrders: OrderInfo[] = []
- for (const chainId of chainsToQuery) {
-   // ... fetch and process
- }
+ const chainResults = await Promise.allSettled(
+   chainsToQuery.map(async chainId => {
+     const chainIdString = `eip155:${chainId}`
+     let userAddress: string
+     try {
+       userAddress = getAddressForChain(walletContext, chainIdString)
+     } catch {
+       return []
+     }
+     try {
+       const orders = await getCowOrders(userAddress, chainId, { limit: 50 })
+       // ... process and return OrderInfo[]
+     } catch (error) {
+       console.warn(`Failed to fetch orders from chain ${chainId}:`, error)
+       return []
+     }
+   })
+ )
+ const allOrders = chainResults.flatMap(r => r.status === 'fulfilled' ? r.value : [])

82-87: Remove the presignaturePendingopen mapping; preserve distinct order states.

This issue was previously flagged and remains unaddressed. CoW Protocol distinguishes between presignaturePending (awaiting on-chain pre-signature) and open (active in orderbook). Collapsing them loses important state information.

Either remove the mapping or document why it's intentional:

 function formatOrderStatus(status: CowOrderStatus): CowOrderStatus {
-  // Map CoW status to our simplified status
-  if (status === 'fulfilled') return 'fulfilled'
-  if (status === 'presignaturePending') return 'open'
-  return status
+  // Return status as-is; UI and filters should handle all CoW statuses
+  return status
 }

Then add 'presignaturePending' to any filter schemas that currently exclude it.


101-101: Remove raw input logging.

This issue was previously flagged and remains unaddressed. Logging full input can leak user intent/filters.

- console.log('[getLimitOrders]:', JSON.stringify(input, null, 2))
+ // Use structured logger with redaction if needed
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (5)

108-120: Blocker: parseFloat loses precision for limit order price math.

This issue was previously flagged and remains unaddressed. Float arithmetic will silently misprice orders, especially for tokens with high precision or small fractional prices.

Apply this diff to use BigNumber throughout:

 function calculateBuyAmount(buyAsset: Asset, sellAmount: string, limitPrice: string): string {
-  // limitPrice is buyAsset per sellAsset
-  // buyAmount = sellAmount * limitPrice
-  const sellAmountNum = parseFloat(sellAmount)
-  const limitPriceNum = parseFloat(limitPrice)
-
-  if (isNaN(sellAmountNum) || isNaN(limitPriceNum)) {
-    throw new Error('Invalid sellAmount or limitPrice')
-  }
-
-  const buyAmountNum = sellAmountNum * limitPriceNum
-  return toBaseUnit(buyAmountNum.toString(), buyAsset.precision)
+  const bnSell = new BigNumber(sellAmount)
+  const bnPrice = new BigNumber(limitPrice)
+  if (!bnSell.isFinite() || !bnPrice.isFinite() || bnSell.lte(0) || bnPrice.lte(0)) {
+    throw new Error('Invalid sellAmount or limitPrice')
+  }
+  const buyAmountHuman = bnSell.times(bnPrice)
+  return toBaseUnit(buyAmountHuman.toFixed(buyAsset.precision), buyAsset.precision)
 }

122-129: parseInt may return NaN without validation.

This issue was previously flagged and remains unaddressed. If parts[1] contains invalid characters, NaN propagates silently.

Apply this diff:

 function getEvmChainId(chainId: string): number {
   const parts = chainId.split(':')
   if (parts.length !== 2 || !parts[1]) {
     throw new Error(`Invalid chainId format: ${chainId}`)
   }
-  return parseInt(parts[1], 10)
+  const numericId = parseInt(parts[1], 10)
+  if (isNaN(numericId)) {
+    throw new Error(`Invalid numeric chainId: ${chainId}`)
+  }
+  return numericId
 }

135-136: Remove raw input logging.

This issue was previously flagged and remains unaddressed. Logging full input can leak sensitive user data (amounts, assets, wallet intent).

Remove or replace with a structured logger that redacts sensitive fields:

- console.log('[createLimitOrder]:', JSON.stringify(input, null, 2))
+ // Use structured logger with redaction if needed

237-238: Inconsistent precision: estimatedBuyAmount uses BigNumber but calculateBuyAmount uses parseFloat.

This issue was previously flagged and remains unaddressed. The display value (line 238) and actual order amount (line 209) may differ due to float rounding in calculateBuyAmount.

Once calculateBuyAmount is fixed to use BigNumber, this inconsistency will be resolved.


273-273: Placeholder trackingUrl may confuse users.

This issue was previously flagged and remains unaddressed. Returning getCowExplorerUrl('pending') leads users to a non-existent order page.

Consider making trackingUrl optional or returning a generic explorer URL without an order ID:

-    trackingUrl: getCowExplorerUrl('pending'),
+    trackingUrl: undefined, // or 'https://explorer.cow.fi'

Update the CreateLimitOrderOutput type to make trackingUrl optional if you choose undefined.

apps/agentic-server/src/lib/cow/types.ts (2)

74-94: Incomplete sepolia support + unsafe mainnet fallback.

This issue was previously flagged and remains unaddressed. Sepolia exists in COW_SUPPORTED_CHAINS and has API routing, but is absent from NETWORK_TO_CHAIN_ID and CHAIN_ID_TO_NETWORK, causing "unknown" network labels and potential misrouting.

Either fully support sepolia or remove it:

 export const NETWORK_TO_CHAIN_ID: Record<string, number> = {
   ethereum: 1,
   gnosis: 100,
   arbitrum: 42161,
+  sepolia: 11155111,
 }

 export const CHAIN_ID_TO_NETWORK: Record<number, string> = {
+  11155111: 'sepolia',
 }

Also update tool schemas to include 'sepolia' in network enums and remove any explicit filters excluding 11155111.


104-117: getCowApiUrl silently defaults to mainnet for unknown chains.

This issue was previously flagged and remains unaddressed. Orders could be submitted to the wrong network.

Replace the default fallback with an error:

 export function getCowApiUrl(chainId: number): string {
   switch (chainId) {
     case 1:
       return 'https://api.cow.fi/mainnet'
     case 100:
       return 'https://api.cow.fi/gnosis'
     case 11155111:
       return 'https://api.cow.fi/sepolia'
     case 42161:
       return 'https://api.cow.fi/arbitrum_one'
     default:
-      return 'https://api.cow.fi/mainnet'
+      throw new Error(`Unsupported chain ID for CoW Protocol: ${chainId}`)
   }
 }
apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (2)

285-295: Handle missing publicClient explicitly.

This issue was previously flagged and remains unaddressed. When publicClient is null, the code silently skips waiting for the transaction receipt, which could cause race conditions.

Consider logging a warning:

       if (needsApproval && approvalTxHash) {
         const publicClient = getPublicClient(wagmiConfig, {
           chainId: orderParams.chainId,
         })
-        if (publicClient) {
-          await publicClient.waitForTransactionReceipt({
-            hash: approvalTxHash as `0x${string}`,
-            confirmations: 1,
-          })
+        if (!publicClient) {
+          console.warn(`[useLimitOrderExecution] No public client for chain ${orderParams.chainId}, skipping receipt confirmation`)
+        } else {
+          await publicClient.waitForTransactionReceipt({
+            hash: approvalTxHash as `0x${string}`,
+            confirmations: 1,
+          })
         }

49-128: Persist/rehydrate loses failedStep and currentStep, breaking step-status fidelity after refresh.

This issue was previously flagged and remains unaddressed. The UI cannot reliably show which step failed after a page refresh.

Apply the same fix pattern as suggested for the cancel hook—persist and restore both fields:

 function limitOrderStateToPersistedState(
   // ...
 ): PersistedToolState {
   // ...
   return {
     // ...
     meta: {
       ...(state.orderId && { orderId: state.orderId }),
       ...(state.approvalTxHash && { approvalTxHash: state.approvalTxHash }),
       ...(state.error && { error: state.error }),
+      ...(state.failedStep !== undefined && { failedStep: state.failedStep }),
+      ...(state.currentStep !== undefined && { currentStep: state.currentStep }),
       ...(networkName && { networkName }),
     },
     // ...
   }
 }

 function persistedStateToLimitOrderState(persisted: PersistedToolState): LimitOrderState {
   const completedSteps = new Set<LimitOrderStep>()
-  const currentStep = LimitOrderStep.COMPLETE
+  const currentStep = (persisted.meta.currentStep as LimitOrderStep | undefined) ?? LimitOrderStep.COMPLETE

   // ... (rebuild completedSteps)

   return {
     currentStep,
     completedSteps,
     orderId: persisted.meta.orderId as string | undefined,
     approvalTxHash: persisted.meta.approvalTxHash as string | undefined,
     error: persisted.meta.error as string | undefined,
+    failedStep: persisted.meta.failedStep as LimitOrderStep | undefined,
   }
 }
apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (2)

34-48: Differentiate 404 (not found) from transient errors in chain detection.

This issue was previously flagged and remains unaddressed. All errors are treated as "order not on this chain," masking real API failures.

Enhance getCowOrder to expose HTTP status and handle errors appropriately:

// In getCowOrder (lib/cow/index.ts):
if (!response.ok) {
  if (response.status === 404) {
    throw new NotFoundError(`Order ${orderId} not found on chain ${chainId}`)
  }
  const errorText = await response.text()
  throw new Error(`Failed to fetch order from CoW: ${errorText}`)
}

// Then in detectChainIdFromOrderId:
for (const chainId of chainsToTry) {
  try {
    const order = await getCowOrder(orderId, chainId)
    if (order) return chainId
  } catch (error) {
    if (error instanceof NotFoundError) continue // Try next chain
    throw error // Propagate transient failures
  }
}

54-54: Remove raw input logging and avoid echoing order.owner in error messages.

This issue was previously flagged and remains unaddressed. Logging and error messages can leak sensitive data.

Apply this diff:

- console.log('[cancelLimitOrder]:', JSON.stringify(input, null, 2))
+ // Use structured logger with redaction if needed

  const order = await getCowOrder(input.orderId, chainId)
  if (order.owner.toLowerCase() !== userAddress.toLowerCase()) {
-    throw new Error(`You do not own this order. Order owner: ${order.owner}`)
+    throw new Error(`You do not own this order. Please verify the order ID and connected wallet.`)
  }

Also applies to: 79-81

apps/agentic-chat/src/hooks/useCancelLimitOrderExecution.tsx (1)

41-103: Persist/rehydrate loses failedStep and currentStep, breaking step-status fidelity after refresh.

This issue was previously flagged and remains unaddressed. The UI cannot reliably show which step failed after a page refresh.

Apply the same fix pattern:

 function cancelOrderStateToPersistedState(
   // ...
 ): PersistedToolState {
   // ...
   return {
     // ...
     meta: {
       ...(orderOutput?.orderId && { orderId: orderOutput.orderId }),
       ...(state.error && { error: state.error }),
+      ...(state.failedStep !== undefined && { failedStep: state.failedStep }),
+      ...(state.currentStep !== undefined && { currentStep: state.currentStep }),
       ...(networkName && { networkName }),
     },
     // ...
   }
 }

 function persistedStateToCancelOrderState(persisted: PersistedToolState): CancelOrderState {
   const completedSteps = new Set<CancelOrderStep>()
-  const currentStep = CancelOrderStep.COMPLETE
+  const currentStep = (persisted.meta.currentStep as CancelOrderStep | undefined) ?? CancelOrderStep.COMPLETE

   // ... (rebuild completedSteps)

   return {
     currentStep,
     completedSteps,
     error: persisted.meta.error as string | undefined,
+    failedStep: persisted.meta.failedStep as CancelOrderStep | undefined,
   }
 }
apps/agentic-server/src/lib/cow/index.ts (1)

121-163: from field should be the order signer, not receiver.

This issue was previously flagged and remains unaddressed. The from field represents the order owner/signer, but using order.receiver is incorrect when the receiver differs from the signer.

Update the function signature and usage:

 export async function submitCowOrder(
   chainId: number,
   order: CowOrderQuote,
   signature: string,
-  signingScheme: 'eip712' | 'ethsign' = 'eip712'
+  signingScheme: 'eip712' | 'ethsign' = 'eip712',
+  from: string
 ): Promise<string> {
   // ...
   const orderPayload = {
     // ...
-    from: order.receiver, // owner of the order
+    from, // owner/signer of the order
   }

Update all callers to pass the actual signer address.

🧹 Nitpick comments (3)
apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx (1)

24-28: Remove unnecessary fragment wrappers.

The fragment wrappers around the Amount.Fiat components in the suffix props serve no purpose since they only contain a single child.

Apply this diff to simplify the code:

           suffix={
-            <>
-              (<Amount.Fiat value={details.sellAsset.valueUSD} />)
-            </>
+            <>(<Amount.Fiat value={details.sellAsset.valueUSD} />)</>
           }

And similarly for the buyAsset:

           suffix={
-            <>
-              (<Amount.Fiat value={details.buyAsset.valueUSD} />)
-            </>
+            <>(<Amount.Fiat value={details.buyAsset.valueUSD} />)</>
           }

Also applies to: 38-42

apps/agentic-chat/src/components/Portfolio/ActivityRow/components/LimitOrderDetails.tsx (1)

3-3: Fix event typing for stopPropagationHandler (React event ≠ DOM MouseEvent)

onClick receives a React synthetic mouse event; the shared helper is typed as DOM MouseEvent, which is brittle and can start failing as TS settings/types evolve.

Minimal local fix:

+import type React from 'react'
 ...
-            onClick={stopPropagationHandler}
+            onClick={(e: React.MouseEvent<HTMLAnchorElement>) => e.stopPropagation()}

Better global fix: retarget apps/agentic-chat/src/lib/eventHandlers.ts to accept React.SyntheticEvent (or a small structural type with stopPropagation(): void) and keep callsites clean.

Also applies to: 35-35

apps/agentic-chat/src/lib/stepUtils.ts (1)

40-45: Type assertions bypass viem's type safety.

The type assertions at Lines 40-44 force compatibility between CoW Protocol's API format and viem's signTypedData expectations, but they bypass compile-time type checking. If CoW's format or viem's signature changes, runtime errors could occur.

Consider adding runtime validation or helper functions that safely transform CoW data to viem's expected structure, documenting the specific format differences you're bridging.

📜 Review details

Configuration used: CodeRabbit 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 7536eb0 and 9a40ec3.

📒 Files selected for processing (27)
  • apps/agentic-chat/src/components/Portfolio/ActivityList.tsx (2 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx (0 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/LimitOrderDetails.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SendDetails.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/index.tsx (1 hunks)
  • apps/agentic-chat/src/components/toolUIRegistry.tsx (2 hunks)
  • apps/agentic-chat/src/components/tools/CancelLimitOrderUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/LimitOrderUI.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useCancelLimitOrderExecution.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useToolExecutionEffect.ts (1 hunks)
  • apps/agentic-chat/src/lib/activityNormalizer.ts (3 hunks)
  • apps/agentic-chat/src/lib/cow-config.ts (1 hunks)
  • apps/agentic-chat/src/lib/eventHandlers.ts (1 hunks)
  • apps/agentic-chat/src/lib/stepUtils.ts (1 hunks)
  • apps/agentic-chat/src/stores/chatStore.ts (2 hunks)
  • apps/agentic-chat/src/types/activity.ts (2 hunks)
  • apps/agentic-server/src/index.ts (1 hunks)
  • apps/agentic-server/src/lib/cow/index.ts (1 hunks)
  • apps/agentic-server/src/lib/cow/types.ts (1 hunks)
  • apps/agentic-server/src/routes/chat.ts (4 hunks)
  • apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/index.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx
🚧 Files skipped from review as they are similar to previous changes (7)
  • apps/agentic-chat/src/hooks/useToolExecutionEffect.ts
  • apps/agentic-chat/src/lib/eventHandlers.ts
  • apps/agentic-chat/src/types/activity.ts
  • apps/agentic-chat/src/components/toolUIRegistry.tsx
  • apps/agentic-server/src/index.ts
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/index.tsx
  • apps/agentic-chat/src/lib/activityNormalizer.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-22T20:32:10.539Z
Learnt from: kaladinlight
Repo: shapeshift/agentic-chat PR: 76
File: apps/agentic-server/src/mastra/tools/asset/coingecko/constants.ts:1-10
Timestamp: 2025-09-22T20:32:10.539Z
Learning: When cross-app dependencies are identified (like server code importing from chat packages), the user prefers to extract shared constants into dedicated packages in the packages/ directory following the existing pattern of shapeshiftoss/types and shapeshiftoss/utils.

Applied to files:

  • apps/agentic-chat/src/stores/chatStore.ts
🧬 Code graph analysis (11)
apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx (7)
apps/agentic-chat/src/types/activity.ts (1)
  • SwapActivityDetails (9-26)
apps/agentic-chat/src/lib/explorers.ts (1)
  • getExplorerUrl (1-15)
apps/agentic-chat/src/components/ui/ToolCard.tsx (1)
  • ToolCard (71-78)
apps/agentic-chat/src/components/ui/Amount.tsx (1)
  • Amount (88-92)
apps/agentic-chat/src/lib/eventHandlers.ts (1)
  • stopPropagationHandler (4-6)
apps/agentic-chat/src/lib/utils.ts (1)
  • truncateAddress (9-12)
apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx (1)
  • SwapDetails (30-83)
apps/agentic-chat/src/components/Portfolio/ActivityRow/components/LimitOrderDetails.tsx (4)
apps/agentic-chat/src/types/activity.ts (1)
  • LimitOrderActivityDetails (39-52)
apps/agentic-chat/src/components/ui/ToolCard.tsx (1)
  • ToolCard (71-78)
apps/agentic-chat/src/components/ui/Amount.tsx (1)
  • Amount (88-92)
apps/agentic-chat/src/lib/eventHandlers.ts (1)
  • stopPropagationHandler (4-6)
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (9)
apps/agentic-server/src/utils/chains/helpers.ts (1)
  • isEvmChain (3-6)
packages/caip/src/assetId.ts (1)
  • fromAssetId (87-106)
apps/agentic-server/src/utils/transactionHelpers.ts (1)
  • createTransaction (17-33)
apps/agentic-server/src/lib/cow/types.ts (3)
  • CowOrderSigningData (48-53)
  • isCowSupportedChain (96-98)
  • getCowExplorerUrl (100-102)
packages/utils/src/index.ts (1)
  • toBaseUnit (43-46)
apps/agentic-server/src/utils/walletContextSimple.ts (1)
  • WalletContext (4-6)
apps/agentic-server/src/utils/assetHelpers.ts (1)
  • resolveAsset (8-25)
apps/agentic-server/src/lib/cow/index.ts (2)
  • COW_VAULT_RELAYER_ADDRESS (30-30)
  • prepareCowLimitOrder (70-114)
apps/agentic-server/src/utils/getAllowance.ts (1)
  • getAllowance (24-57)
apps/agentic-server/src/routes/chat.ts (5)
apps/agentic-server/src/index.ts (3)
  • createLimitOrderTool (92-92)
  • getLimitOrdersTool (99-99)
  • cancelLimitOrderTool (105-105)
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1)
  • createLimitOrderTool (277-299)
apps/agentic-server/src/tools/limitOrder/index.ts (3)
  • createLimitOrderTool (2-2)
  • getLimitOrdersTool (11-11)
  • cancelLimitOrderTool (19-19)
apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (1)
  • getLimitOrdersTool (196-221)
apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (1)
  • cancelLimitOrderTool (111-130)
apps/agentic-chat/src/components/tools/LimitOrderUI.tsx (7)
apps/agentic-server/src/index.ts (1)
  • CreateLimitOrderOutput (95-95)
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1)
  • CreateLimitOrderOutput (90-106)
apps/agentic-server/src/tools/limitOrder/index.ts (1)
  • CreateLimitOrderOutput (6-6)
apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (1)
  • useLimitOrderExecution (187-393)
apps/agentic-chat/src/components/ui/TxStepCard.tsx (1)
  • TxStepCard (149-162)
apps/agentic-chat/src/components/ui/Amount.tsx (1)
  • Amount (88-92)
apps/agentic-chat/src/components/ui/TruncateText.tsx (1)
  • TruncateText (9-26)
apps/agentic-server/src/lib/cow/types.ts (1)
apps/agentic-chat/src/lib/cow-config.ts (1)
  • getCowApiUrl (8-14)
apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (4)
apps/agentic-server/src/lib/cow/types.ts (5)
  • CowOrderStatus (5-5)
  • CHAIN_ID_TO_NETWORK (90-94)
  • CowOrder (7-22)
  • COW_SUPPORTED_CHAINS (75-80)
  • getCowExplorerUrl (100-102)
apps/agentic-server/src/utils/walletContextSimple.ts (2)
  • WalletContext (4-6)
  • getAddressForChain (13-26)
apps/agentic-server/src/lib/cow/index.ts (1)
  • getCowOrders (168-188)
packages/utils/src/index.ts (1)
  • fromBaseUnit (38-41)
apps/agentic-chat/src/lib/cow-config.ts (1)
apps/agentic-server/src/lib/cow/types.ts (1)
  • getCowApiUrl (104-117)
apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (3)
apps/agentic-server/src/lib/cow/types.ts (4)
  • CowEIP712Domain (37-42)
  • NETWORK_TO_CHAIN_ID (83-87)
  • CHAIN_ID_TO_NETWORK (90-94)
  • getCowExplorerUrl (100-102)
apps/agentic-server/src/lib/cow/index.ts (2)
  • getCowOrder (193-208)
  • prepareCowOrderCancellation (214-231)
apps/agentic-server/src/utils/walletContextSimple.ts (2)
  • WalletContext (4-6)
  • getAddressForChain (13-26)
apps/agentic-server/src/lib/cow/index.ts (2)
apps/agentic-server/src/lib/cow/types.ts (10)
  • CowEIP712Types (44-46)
  • CowEIP712Domain (37-42)
  • CreateCowOrderParams (55-64)
  • CreateCowOrderResult (66-72)
  • isCowSupportedChain (96-98)
  • CowOrderQuote (24-35)
  • CowOrderSigningData (48-53)
  • getCowExplorerUrl (100-102)
  • getCowApiUrl (104-117)
  • CowOrder (7-22)
apps/agentic-chat/src/lib/cow-config.ts (1)
  • getCowApiUrl (8-14)
apps/agentic-chat/src/lib/stepUtils.ts (1)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (23-48)
⏰ 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: main
🔇 Additional comments (10)
apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx (2)

1-6: LGTM!

All imports are correctly structured and necessary for the component implementation.


8-11: LGTM!

Type definition is clean and appropriate for the component's requirements.

apps/agentic-chat/src/components/Portfolio/ActivityRow/components/LimitOrderDetails.tsx (1)

30-38: Validate trackingUrl scheme to prevent unexpected navigation

While rel="noopener noreferrer" provides some protection, ensure trackingUrl is validated as an http(s) URL before rendering to prevent navigation via unexpected schemes if the source changes in the future. This is particularly important if the value is derived from external data or user input rather than being hardcoded server-side.

If trackingUrl is guaranteed to be safe (e.g., hardcoded or validated server-side), add a comment documenting this assumption. Otherwise, implement URL validation:

+const isValidHttpUrl = (url: string): boolean => {
+  try {
+    const parsed = new URL(url)
+    return parsed.protocol === 'https:' || parsed.protocol === 'http:'
+  } catch {
+    return false
+  }
+}
+
+const safeTrackingHref = isValidHttpUrl(details.trackingUrl) ? details.trackingUrl : undefined
...
-          <a
-            href={details.trackingUrl}
+          <a
+            href={safeTrackingHref}
             target="_blank"
apps/agentic-chat/src/components/Portfolio/ActivityList.tsx (1)

13-20: LGTM! Filter and sort logic correctly extended for limit orders.

The filter now includes 'limit_order' alongside swaps and sends, and the new .sort() ensures latest activities appear first. The implementation is clean and maintains consistency with existing patterns.

apps/agentic-server/src/routes/chat.ts (1)

164-187: LGTM! Limit order tools properly integrated.

The three limit order tools (createLimitOrderTool, getLimitOrdersTool, cancelLimitOrderTool) follow the established pattern: each wraps execution with logging, passes walletContext, and maintains consistent structure with existing tools like initiateSwapTool and sendTool.

apps/agentic-chat/src/components/tools/CancelLimitOrderUI.tsx (1)

13-124: LGTM! Well-structured cancel UI with proper error handling.

The component correctly handles historical-skipped cases, validates all required steps, computes completion progress, and provides clear user feedback through status icons, tracking links, and error messages. The step rendering is clean and follows established patterns.

apps/agentic-chat/src/stores/chatStore.ts (1)

22-31: LGTM! Store types properly extended for limit orders.

The PersistedToolState interface now includes 'limit_order' and 'cancel_limit_order' tool types, their corresponding output types (CreateLimitOrderOutput, CancelLimitOrderOutput), and an optional walletAddress field. These extensions follow the established pattern and enable proper state persistence for limit order flows.

apps/agentic-server/src/tools/limitOrder/index.ts (1)

1-24: LGTM! Clean barrel export consolidating limit order APIs.

The file properly re-exports tools, execution functions, schemas, and types from all three limit order modules (createLimitOrder, getLimitOrders, cancelLimitOrder), providing a clean public API surface.

apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx (1)

1-257: LGTM! UI now handles human-readable amounts and symbols correctly.

The UI receives properly formatted data (symbols, decimals, human amounts) from the server's GetLimitOrdersOutput and renders them correctly. The previous issue about displaying base-unit amounts and addresses has been addressed.

apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (1)

32-180: LGTM! Server now returns enriched order data with symbols and human-readable amounts.

The tool correctly resolves token metadata (symbol, precision) and converts base-unit amounts to human-readable format. The previous issue about returning raw base units has been addressed.

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: 5

♻️ Duplicate comments (16)
apps/agentic-chat/src/lib/stepUtils.ts (1)

14-20: Step status ordering can mark a completed current step as IN_PROGRESS.
Check completedSteps.has(step) before the currentStep === step IN_PROGRESS branch.

apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (4)

108-120: Blocker: limit-order pricing uses parseFloat (precision loss) + display amount can disagree with signed amount.
Use BigNumber end-to-end and derive both buyAmountBaseUnit and estimatedBuyAmount from the same precise calculation.

 function calculateBuyAmount(buyAsset: Asset, sellAmount: string, limitPrice: string): string {
-  const sellAmountNum = parseFloat(sellAmount)
-  const limitPriceNum = parseFloat(limitPrice)
-
-  if (isNaN(sellAmountNum) || isNaN(limitPriceNum)) {
-    throw new Error('Invalid sellAmount or limitPrice')
-  }
-
-  const buyAmountNum = sellAmountNum * limitPriceNum
-  return toBaseUnit(buyAmountNum.toString(), buyAsset.precision)
+  const bnSell = new BigNumber(sellAmount)
+  const bnPrice = new BigNumber(limitPrice)
+  if (!bnSell.isFinite() || !bnPrice.isFinite() || bnSell.lte(0) || bnPrice.lte(0)) {
+    throw new Error('Invalid sellAmount or limitPrice')
+  }
+  const buyAmountHuman = bnSell.times(bnPrice)
+  // avoid scientific notation
+  return toBaseUnit(buyAmountHuman.toFixed(buyAsset.precision), buyAsset.precision)
 }
 ...
-  const estimatedBuyAmount = new BigNumber(input.sellAmount).times(input.limitPrice).toFixed(6)
+  const estimatedBuyAmount = new BigNumber(input.sellAmount).times(input.limitPrice).toFixed(6)

(After the change, estimatedBuyAmount and buyAmountBaseUnit will agree up to rounding rules.)

Also applies to: 209-210, 237-239


122-129: Validate parseInt result in getEvmChainId (avoid NaN propagation).
parseInt can return NaN for malformed chain IDs.

 function getEvmChainId(chainId: string): number {
   const parts = chainId.split(':')
   if (parts.length !== 2 || !parts[1]) {
     throw new Error(`Invalid chainId format: ${chainId}`)
   }
-  return parseInt(parts[1], 10)
+  const numericId = parseInt(parts[1].trim(), 10)
+  if (Number.isNaN(numericId)) throw new Error(`Invalid numeric chainId: ${chainId}`)
+  return numericId
 }

135-136: Remove/redact tool input logging (console.log(JSON.stringify(input))).
This can leak amounts and user intent.


258-274: Return a real/consistent trackingUrl (don’t hardcode 'pending').
You already have orderResult.trackingUrl (and orderResult.orderId); the current return is guaranteed to be wrong/broken.

   return {
     summary,
     signingData: orderResult.signingData,
     orderParams: {
       sellToken,
       buyToken,
       sellAmount: sellAmountBaseUnit,
       buyAmount: buyAmountBaseUnit,
       validTo: orderResult.orderToSign.validTo,
       receiver: userAddress,
       chainId: evmChainId,
     },
     needsApproval,
     approvalTx,
     approvalTarget,
-    trackingUrl: getCowExplorerUrl('pending'),
+    trackingUrl: orderResult.trackingUrl,
   }
apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (2)

34-48: Don’t treat all getCowOrder failures as “order not found” (distinguish 404 vs transient).
Catching everything will misreport CoW outages/timeouts as “could not find order”.


54-55: Remove/redact console.log + don’t include full order.owner in errors.
Log redacted metadata at most, and report “ownership mismatch” without leaking addresses.

Also applies to: 79-81

apps/agentic-chat/src/components/Portfolio/ActivityRow/components/LimitOrderDetails.tsx (1)

25-26: Guard against invalid/ambiguous expiry rendering.
new Date(details.expiresAt).toLocaleString() can produce “Invalid Date” and varies by locale/timezone; add a safe formatter/fallback.

apps/agentic-chat/src/lib/activityNormalizer.ts (1)

110-110: Hardcoded mainnet URL ignores network-specific explorer paths.

The hardcoded https://explorer.cow.fi/orders/${orderId} will always produce mainnet format regardless of which chain the order is on. The getCowExplorerUrl utility (or network-aware logic) should be used instead.

Consider using the trackingUrl from output if available:

-    trackingUrl: `https://explorer.cow.fi/orders/${orderId}`,
+    trackingUrl: output.trackingUrl ?? `https://explorer.cow.fi/orders/${orderId}`,

Based on past review comments, this issue was previously flagged.

apps/agentic-server/src/lib/cow/types.ts (2)

74-95: Incomplete sepolia support creates inconsistent behavior.

Sepolia (chainId 11155111) appears in COW_SUPPORTED_CHAINS (line 78) and getCowApiUrl (lines 110-111), but is completely missing from NETWORK_TO_CHAIN_ID (lines 83-87) and CHAIN_ID_TO_NETWORK (lines 90-94). This inconsistency means:

  • isCowSupportedChain(11155111) returns true
  • But CHAIN_ID_TO_NETWORK[11155111] returns undefined
  • Tool schemas in other files explicitly exclude sepolia from valid networks

Either fully support sepolia by adding it to both mappings, or remove it from COW_SUPPORTED_CHAINS to avoid API-level inconsistency:

 export const NETWORK_TO_CHAIN_ID: Record<string, number> = {
   ethereum: 1,
   gnosis: 100,
   arbitrum: 42161,
+  sepolia: 11155111,
 }

 export const CHAIN_ID_TO_NETWORK: Record<number, string> = {
+  11155111: 'sepolia',
 }

Based on past review comments, this issue was previously flagged.


104-117: getCowApiUrl silently defaults to mainnet for unknown chains.

The default fallback to mainnet (line 115) could cause orders to be submitted to the wrong network if called with an unsupported chain ID. This creates a data integrity risk.

Throw an error for unsupported chains instead of silently defaulting:

 export function getCowApiUrl(chainId: number): string {
   switch (chainId) {
     case 1:
       return 'https://api.cow.fi/mainnet'
     case 100:
       return 'https://api.cow.fi/gnosis'
     case 11155111:
       return 'https://api.cow.fi/sepolia'
     case 42161:
       return 'https://api.cow.fi/arbitrum_one'
     default:
-      return 'https://api.cow.fi/mainnet'
+      throw new Error(`Unsupported chain ID for CoW Protocol: ${chainId}`)
   }
 }

Based on past review comments, this issue was previously flagged.

apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (3)

124-185: Parallelize per-chain fetches and use structured logging.

Sequential chain iteration increases worst-case latency (3-4x slower than parallel). Additionally, console.warn on line 182 should use structured logging.

Refactor to use Promise.allSettled for concurrent chain queries:

const chainResults = await Promise.allSettled(
  chainsToQuery.map(async (chainId) => {
    const chainIdString = `eip155:${chainId}`
    let userAddress: string
    try {
      userAddress = getAddressForChain(walletContext, chainIdString)
    } catch {
      return [] // Skip if wallet not connected
    }

    try {
      const orders = await getCowOrders(userAddress, chainId, { limit: 50 })
      const networkName = CHAIN_ID_TO_NETWORK[chainId] || 'unknown'
      
      return orders
        .filter(order => {
          const orderStatus = formatOrderStatus(order.status)
          if (statusFilter && orderStatus !== statusFilter) return false
          return order.class === 'limit'
        })
        .map(order => {
          // ... existing enrichment logic ...
        })
    } catch (error) {
      // Use structured logger instead of console.warn
      return []
    }
  })
)

const allOrders = chainResults
  .filter(result => result.status === 'fulfilled')
  .flatMap(result => result.value)

82-87: Remove the presignaturePendingopen mapping; preserve distinct order states.

Per CoW Protocol semantics, presignaturePending (order awaiting on-chain pre-signature, not tradable) and open (signed and active in orderbook) are fundamentally different states. Collapsing them prevents filtering logic and user visibility of orders awaiting pre-signature workflow.

Based on learnings, CoW Protocol distinguishes these states for valid operational reasons. Either remove the mapping or document the intentional simplification.


101-101: Replace console.log with structured logging or remove.

Logging user input with console.log is noisy in production and may leak user intent. Use a structured logger with appropriate redaction or remove the log statement.

apps/agentic-chat/src/hooks/useCancelLimitOrderExecution.tsx (1)

41-103: Persist and restore failedStep and currentStep to maintain post-refresh UI state.

The hydration logic in persistedStateToCancelOrderState always forces currentStep to COMPLETE and never restores failedStep, causing the UI to lose failure state after page refresh. The persisting function also doesn't write these fields to meta.

Apply this diff to persist and restore both fields:

 function cancelOrderStateToPersistedState(
   toolCallId: string,
   state: CancelOrderState,
   conversationId: string,
   orderOutput: CancelLimitOrderOutput | null,
   networkName?: string
 ): PersistedToolState {
   const phases: string[] = []

   if (state.completedSteps.has(CancelOrderStep.PREPARE)) {
     phases.push('prepare_complete')
   }
   if (state.completedSteps.has(CancelOrderStep.NETWORK_SWITCH)) {
     phases.push('network_switched')
   }
   if (state.completedSteps.has(CancelOrderStep.SIGN)) {
     phases.push('signed')
   }
   if (state.completedSteps.has(CancelOrderStep.SUBMIT)) {
     phases.push('submitted')
   }
   if (state.error) {
     phases.push('error')
   }

   return {
     toolCallId,
     toolType: 'cancel_limit_order',
     conversationId,
     timestamp: Date.now(),
     phases,
     meta: {
       ...(orderOutput?.orderId && { orderId: orderOutput.orderId }),
       ...(state.error && { error: state.error }),
+      ...(state.failedStep !== undefined && { failedStep: state.failedStep }),
+      currentStep: state.currentStep,
       ...(networkName && { networkName }),
     },
     ...(orderOutput && { toolOutput: orderOutput }),
   }
 }

 function persistedStateToCancelOrderState(persisted: PersistedToolState): CancelOrderState {
   const completedSteps = new Set<CancelOrderStep>()
-  const currentStep = CancelOrderStep.COMPLETE
+  const currentStep = (persisted.meta.currentStep as CancelOrderStep | undefined) ?? CancelOrderStep.COMPLETE

   if (persisted.phases.includes('prepare_complete')) {
     completedSteps.add(CancelOrderStep.PREPARE)
   }
   if (persisted.phases.includes('network_switched')) {
     completedSteps.add(CancelOrderStep.NETWORK_SWITCH)
   }
   if (persisted.phases.includes('signed')) {
     completedSteps.add(CancelOrderStep.SIGN)
   }
   if (persisted.phases.includes('submitted')) {
     completedSteps.add(CancelOrderStep.SUBMIT)
   }

   return {
     currentStep,
     completedSteps,
     error: persisted.meta.error as string | undefined,
+    failedStep: persisted.meta.failedStep as CancelOrderStep | undefined,
   }
 }
apps/agentic-server/src/lib/cow/index.ts (1)

144-144: from field must be the order signer, not receiver.

The from field in the CoW API payload represents the order owner/signer address. Using order.receiver is incorrect when the receiver differs from the signer (e.g., when sending tokens to another address).

Apply this diff to accept the signer address as a parameter:

 export async function submitCowOrder(
   chainId: number,
   order: CowOrderQuote,
   signature: string,
-  signingScheme: 'eip712' | 'ethsign' = 'eip712'
+  signingScheme: 'eip712' | 'ethsign' = 'eip712',
+  from: string
 ): Promise<string> {
   const apiUrl = getCowApiUrl(chainId)

   const orderPayload = {
     sellToken: order.sellToken,
     buyToken: order.buyToken,
     receiver: order.receiver,
     sellAmount: order.sellAmount,
     buyAmount: order.buyAmount,
     validTo: order.validTo,
     appData: order.appData,
     feeAmount: order.feeAmount,
     kind: order.kind,
     partiallyFillable: order.partiallyFillable,
     sellTokenBalance: 'erc20',
     buyTokenBalance: 'erc20',
     signingScheme,
     signature,
-    from: order.receiver, // owner of the order
+    from, // owner/signer of the order
   }
🧹 Nitpick comments (5)
apps/agentic-server/src/index.ts (1)

91-110: Consider consolidating the three from './tools/limitOrder' export blocks.
Non-blocking, but reduces repetition and makes merge conflicts less likely.

apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (1)

285-307: Consider warning when publicClient is unavailable.

When publicClient is null (line 290), the code silently skips waiting for the transaction receipt but still marks APPROVAL_CONFIRMATION as complete. This could lead to race conditions where approval hasn't been confirmed on-chain yet.

Add a warning log when skipping confirmation:

       if (needsApproval && approvalTxHash) {
         const publicClient = getPublicClient(wagmiConfig, {
           chainId: orderParams.chainId,
         })
-        if (publicClient) {
+        if (!publicClient) {
+          console.warn(`[useLimitOrderExecution] No public client for chain ${orderParams.chainId}, skipping receipt confirmation`)
+        } else {
           await publicClient.waitForTransactionReceipt({
             hash: approvalTxHash as `0x${string}`,
             confirmations: 1,
           })
         }

Based on past review comments, this concern was previously raised.

apps/agentic-chat/src/hooks/useCancelLimitOrderExecution.tsx (1)

228-236: Use current runtime state for persistence instead of manual construction.

The success path manually constructs a state object for persistence, while the error path (line 243) correctly captures the current runtime state with current(draft). This inconsistency creates maintenance risk—future state fields could be missed.

Apply this diff:

-      toast.success(<span>Your limit order has been cancelled</span>)
-
-      persistState({
-        currentStep: CancelOrderStep.COMPLETE,
-        completedSteps: new Set([
-          CancelOrderStep.PREPARE,
-          CancelOrderStep.NETWORK_SWITCH,
-          CancelOrderStep.SIGN,
-          CancelOrderStep.SUBMIT,
-        ]),
-      })
+      let finalState: CancelOrderState | undefined
+      setState(draft => {
+        finalState = current(draft)
+      })
+
+      if (finalState) persistState(finalState)
+
+      toast.success(<span>Your limit order has been cancelled</span>)
apps/agentic-server/src/lib/cow/index.ts (2)

160-162: Fragile string quote removal; parse response properly.

Using regex to strip quotes from the response is brittle. Check the Content-Type header and parse accordingly, or handle both quoted and unquoted string responses explicitly.

   // Response is the order UID as a string
-  const orderId = await response.text()
-  return orderId.replace(/"/g, '') // Remove quotes if present
+  const contentType = response.headers.get('content-type')
+  if (contentType?.includes('application/json')) {
+    return await response.json()
+  }
+  const orderId = await response.text()
+  return orderId.trim().replace(/^"|"$/g, '')

236-259: Note: Unused cancellation endpoint differs from the hook implementation.

This function uses DELETE /api/v1/orders/{orderId} (singular), while useCancelLimitOrderExecution uses DELETE /api/v1/orders (plural, batch endpoint) with orderUids in the body. Both are valid CoW API endpoints, but this function is currently unused. Consider removing it or documenting when to use each endpoint.

Run this script to verify usage of cancelCowOrder:

#!/bin/bash
# Search for usages of cancelCowOrder
rg -n "cancelCowOrder" --type ts
📜 Review details

Configuration used: CodeRabbit 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 9a40ec3 and 839d0ba.

📒 Files selected for processing (28)
  • apps/agentic-chat/src/components/Portfolio/ActivityList.tsx (2 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx (0 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/ActivityRow.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/LimitOrderDetails.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SendDetails.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/index.ts (1 hunks)
  • apps/agentic-chat/src/components/toolUIRegistry.tsx (2 hunks)
  • apps/agentic-chat/src/components/tools/CancelLimitOrderUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/LimitOrderUI.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useCancelLimitOrderExecution.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useToolExecutionEffect.ts (1 hunks)
  • apps/agentic-chat/src/lib/activityNormalizer.ts (3 hunks)
  • apps/agentic-chat/src/lib/cow-config.ts (1 hunks)
  • apps/agentic-chat/src/lib/eventHandlers.ts (1 hunks)
  • apps/agentic-chat/src/lib/stepUtils.ts (1 hunks)
  • apps/agentic-chat/src/stores/chatStore.ts (2 hunks)
  • apps/agentic-chat/src/types/activity.ts (2 hunks)
  • apps/agentic-server/src/index.ts (1 hunks)
  • apps/agentic-server/src/lib/cow/index.ts (1 hunks)
  • apps/agentic-server/src/lib/cow/types.ts (1 hunks)
  • apps/agentic-server/src/routes/chat.ts (4 hunks)
  • apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/index.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx
🚧 Files skipped from review as they are similar to previous changes (8)
  • apps/agentic-chat/src/hooks/useToolExecutionEffect.ts
  • apps/agentic-chat/src/lib/eventHandlers.ts
  • apps/agentic-chat/src/lib/cow-config.ts
  • apps/agentic-chat/src/components/toolUIRegistry.tsx
  • apps/agentic-chat/src/components/tools/LimitOrderUI.tsx
  • apps/agentic-server/src/tools/limitOrder/index.ts
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SendDetails.tsx
  • apps/agentic-chat/src/types/activity.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-22T20:32:10.539Z
Learnt from: kaladinlight
Repo: shapeshift/agentic-chat PR: 76
File: apps/agentic-server/src/mastra/tools/asset/coingecko/constants.ts:1-10
Timestamp: 2025-09-22T20:32:10.539Z
Learning: When cross-app dependencies are identified (like server code importing from chat packages), the user prefers to extract shared constants into dedicated packages in the packages/ directory following the existing pattern of shapeshiftoss/types and shapeshiftoss/utils.

Applied to files:

  • apps/agentic-chat/src/stores/chatStore.ts
🧬 Code graph analysis (11)
apps/agentic-chat/src/lib/stepUtils.ts (1)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (23-48)
apps/agentic-chat/src/stores/chatStore.ts (2)
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1)
  • CreateLimitOrderOutput (90-106)
apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (1)
  • CancelLimitOrderOutput (26-32)
apps/agentic-chat/src/hooks/useCancelLimitOrderExecution.tsx (8)
apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (1)
  • CancelLimitOrderOutput (26-32)
apps/agentic-chat/src/stores/chatStore.ts (2)
  • PersistedToolState (22-31)
  • useChatStore (76-195)
apps/agentic-chat/src/lib/cow-config.ts (1)
  • getCowApiUrl (8-14)
apps/agentic-server/src/lib/cow/types.ts (1)
  • getCowApiUrl (104-117)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (23-48)
apps/agentic-chat/src/providers/ChatProvider.tsx (1)
  • useChatContext (33-39)
apps/agentic-chat/src/hooks/useToolExecutionEffect.ts (1)
  • useToolExecutionEffect (10-60)
apps/agentic-chat/src/lib/stepUtils.ts (2)
  • signTypedDataWithWallet (32-48)
  • getStepStatus (14-20)
apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx (8)
apps/agentic-chat/src/components/ui/Amount.tsx (1)
  • Amount (88-92)
apps/agentic-chat/src/lib/eventHandlers.ts (1)
  • stopPropagationHandler (4-6)
apps/agentic-chat/src/stores/chatStore.ts (2)
  • PersistedToolState (22-31)
  • useChatStore (76-195)
apps/agentic-server/src/index.ts (2)
  • CreateLimitOrderOutput (95-95)
  • GetLimitOrdersOutput (102-102)
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1)
  • CreateLimitOrderOutput (90-106)
apps/agentic-server/src/tools/limitOrder/index.ts (2)
  • CreateLimitOrderOutput (6-6)
  • GetLimitOrdersOutput (15-15)
apps/agentic-chat/src/components/tools/toolUIHelpers.tsx (1)
  • useToolStateRender (10-31)
apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (1)
  • GetLimitOrdersOutput (62-65)
apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (3)
apps/agentic-server/src/lib/cow/types.ts (4)
  • CowEIP712Domain (37-42)
  • NETWORK_TO_CHAIN_ID (83-87)
  • CHAIN_ID_TO_NETWORK (90-94)
  • getCowExplorerUrl (100-102)
apps/agentic-server/src/lib/cow/index.ts (2)
  • getCowOrder (193-208)
  • prepareCowOrderCancellation (214-231)
apps/agentic-server/src/utils/walletContextSimple.ts (2)
  • WalletContext (4-6)
  • getAddressForChain (13-26)
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (9)
apps/agentic-server/src/utils/chains/helpers.ts (1)
  • isEvmChain (3-6)
packages/caip/src/assetId.ts (1)
  • fromAssetId (87-106)
apps/agentic-server/src/utils/transactionHelpers.ts (1)
  • createTransaction (17-33)
apps/agentic-server/src/lib/cow/types.ts (3)
  • CowOrderSigningData (48-53)
  • isCowSupportedChain (96-98)
  • getCowExplorerUrl (100-102)
packages/utils/src/index.ts (1)
  • toBaseUnit (43-46)
apps/agentic-server/src/utils/walletContextSimple.ts (2)
  • WalletContext (4-6)
  • getAddressForChain (13-26)
apps/agentic-server/src/utils/assetHelpers.ts (1)
  • resolveAsset (8-25)
apps/agentic-server/src/lib/cow/index.ts (2)
  • COW_VAULT_RELAYER_ADDRESS (30-30)
  • prepareCowLimitOrder (70-114)
apps/agentic-server/src/utils/getAllowance.ts (1)
  • getAllowance (24-57)
apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx (7)
apps/agentic-chat/src/types/activity.ts (1)
  • SwapActivityDetails (9-26)
apps/agentic-chat/src/lib/explorers.ts (1)
  • getExplorerUrl (1-15)
apps/agentic-chat/src/components/ui/ToolCard.tsx (1)
  • ToolCard (71-78)
apps/agentic-chat/src/components/ui/Amount.tsx (1)
  • Amount (88-92)
apps/agentic-chat/src/lib/eventHandlers.ts (1)
  • stopPropagationHandler (4-6)
apps/agentic-chat/src/lib/utils.ts (1)
  • truncateAddress (9-12)
apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx (1)
  • SwapDetails (30-83)
apps/agentic-server/src/lib/cow/index.ts (2)
apps/agentic-server/src/lib/cow/types.ts (10)
  • CowEIP712Types (44-46)
  • CowEIP712Domain (37-42)
  • CreateCowOrderParams (55-64)
  • CreateCowOrderResult (66-72)
  • isCowSupportedChain (96-98)
  • CowOrderQuote (24-35)
  • CowOrderSigningData (48-53)
  • getCowExplorerUrl (100-102)
  • getCowApiUrl (104-117)
  • CowOrder (7-22)
apps/agentic-chat/src/lib/cow-config.ts (1)
  • getCowApiUrl (8-14)
apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (7)
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1)
  • CreateLimitOrderOutput (90-106)
apps/agentic-chat/src/stores/chatStore.ts (2)
  • PersistedToolState (22-31)
  • useChatStore (76-195)
apps/agentic-chat/src/lib/cow-config.ts (1)
  • getCowApiUrl (8-14)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (23-48)
apps/agentic-chat/src/hooks/useToolExecutionEffect.ts (1)
  • useToolExecutionEffect (10-60)
apps/agentic-chat/src/utils/swapExecutor.ts (1)
  • executeApproval (34-44)
apps/agentic-chat/src/lib/wagmi-config.ts (1)
  • wagmiConfig (15-19)
apps/agentic-chat/src/components/Portfolio/ActivityRow/components/LimitOrderDetails.tsx (4)
apps/agentic-chat/src/types/activity.ts (1)
  • LimitOrderActivityDetails (39-52)
apps/agentic-chat/src/components/ui/ToolCard.tsx (1)
  • ToolCard (71-78)
apps/agentic-chat/src/components/ui/Amount.tsx (1)
  • Amount (88-92)
apps/agentic-chat/src/lib/eventHandlers.ts (1)
  • stopPropagationHandler (4-6)
apps/agentic-server/src/lib/cow/types.ts (1)
apps/agentic-chat/src/lib/cow-config.ts (1)
  • getCowApiUrl (8-14)
⏰ 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: main
🔇 Additional comments (21)
apps/agentic-chat/src/components/Portfolio/ActivityList.tsx (1)

13-20: LGTM — includes limit_order + sorts latest-first + updated empty state copy.
Good incremental update for the new activity type.

Also applies to: 22-27

apps/agentic-chat/src/components/Portfolio/ActivityRow/index.ts (1)

1-1: LGTM — clean barrel re-export.

apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx (1)

13-66: LGTM — clean extraction, and link click propagation is handled.

apps/agentic-chat/src/stores/chatStore.ts (1)

2-31: LGTM! Clean type extensions for limit order support.

The type extensions correctly add limit order support to the persisted state:

  • New tool types ('limit_order', 'cancel_limit_order') properly extend the toolType union
  • Output types correctly include CreateLimitOrderOutput and CancelLimitOrderOutput
  • walletAddress field appropriately optional for backward compatibility
apps/agentic-chat/src/components/Portfolio/ActivityRow/ActivityRow.tsx (3)

26-35: LGTM! Activity title formatting handles all activity types correctly.

The formatActivityTitle function appropriately handles all three activity types (swap, send, limit_order) with correct amount and symbol formatting. The limit_order case correctly uses estimatedAmount for the buy asset, which is appropriate for limit orders where the exact buy amount may vary.


37-64: LGTM! ActivityDetails conditional rendering is correct.

The component correctly:

  • Excludes txHash for limit_order activities (line 38), as they use orderId instead
  • Conditionally renders TX ID link only when both explorerUrl and txHash exist
  • Routes to appropriate detail components based on activity type

1-1: date-fns dependency is properly declared at the workspace level.

The library is included in the root package.json with version ^4.1.0 and is available to all packages in this monorepo structure, including apps/agentic-chat. No action required.

apps/agentic-chat/src/components/tools/CancelLimitOrderUI.tsx (1)

13-124: LGTM! Solid multi-step cancellation UI with proper error handling.

The CancelLimitOrderUI component correctly:

  • Handles historical data skipping gracefully (lines 25-33)
  • Validates all 4 required steps are present before rendering (lines 35-44)
  • Calculates completed steps including SKIPPED status (lines 46-48)
  • Provides clear error messages via footer (lines 50-54, 115-121)
  • Displays truncated order ID in monospaced font for readability (lines 79-81)
  • Shows CoW Explorer tracking link when available (lines 103-113)
apps/agentic-chat/src/lib/activityNormalizer.ts (1)

92-122: LGTM! Limit order normalization correctly structured.

The normalizeLimitOrderActivity function properly:

  • Validates required output and orderId presence (line 96)
  • Extracts limit order details from CreateLimitOrderOutput
  • Returns correctly typed ActivityItem for limit_order type
apps/agentic-server/src/routes/chat.ts (2)

164-187: LGTM! Limit order tools follow established patterns.

The three new tool wrappers (createLimitOrderTool, getLimitOrdersTool, cancelLimitOrderTool) correctly:

  • Follow the same structure as existing tools (initiateSwapTool, sendTool, etc.)
  • Log arguments for debugging
  • Pass walletContext for address resolution
  • Maintain consistent error handling

304-310: LGTM! System prompt clearly documents limit order capabilities.

The limit order documentation in the system prompt appropriately:

  • Describes when to use limit orders (specific price points)
  • Notes gasless execution via EIP-712 signatures
  • Lists supported chains (Ethereum, Gnosis, Arbitrum)
  • Clarifies same-chain only limitation
  • Documents order lifecycle (getLimitOrders, cancelLimitOrder, auto-execution)
apps/agentic-server/src/lib/cow/types.ts (1)

5-72: LGTM! CoW Protocol type definitions are well-structured.

The type definitions correctly model:

  • Order status union with all valid CoW states
  • CowOrder interface with all required order fields
  • EIP-712 signing data structures (domain, types, message)
  • Order creation parameters and results
apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx (3)

19-41: LGTM! Status badge configuration and component are well-designed.

The status configuration correctly:

  • Maps all valid CoW order statuses to appropriate icons and colors
  • Provides a fallback to 'open' status for safety (line 32)
  • Uses semantic colors (blue for open, green for filled, red for cancelled, etc.)

56-136: LGTM! OrderListItem properly formats amounts and displays order details.

The component correctly:

  • Uses BigNumber for precise rate calculation (lines 71-80) to avoid floating-point errors
  • Formats amounts via Amount.Crypto component for proper decimal handling
  • Shows filled percentage for fulfilled orders (lines 114-119)
  • Displays expiration date for open orders (lines 108-113)
  • Truncates wallet address when present (lines 82, 102-107)
  • Includes external link to tracking URL with proper rel attributes

175-254: LGTM! GetLimitOrdersUI handles both history and live modes correctly.

The main component properly:

  • Detects history mode via accountScope parameter (line 178)
  • Loads historical orders from persisted transactions for history mode (lines 180, 191)
  • Uses server data for live mode with status validation (lines 189-195)
  • Displays empty state when no orders exist (lines 197-214)
  • Shows open order count for live mode (line 226)
  • Maps orders to OrderListItem components with appropriate props (lines 234-248)
apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (2)

144-185: LGTM! submitSignedOrder correctly constructs and POSTs the CoW order.

The function properly:

  • Constructs order payload with all required CoW Protocol fields
  • Uses dynamic API URL based on chainId via getCowApiUrl
  • Sets correct headers and serializes payload as JSON
  • Handles error responses with descriptive messages
  • Strips quotes from returned orderId

216-366: LGTM! Execution flow properly orchestrates all limit order steps.

The hook correctly:

  • Validates wallet connection and address consistency (lines 236-242)
  • Marks PREPARE complete before starting execution (lines 245-249)
  • Switches network via Dynamic wallet connector (lines 252-266)
  • Conditionally executes approval if needed (lines 269-283)
  • Waits for approval confirmation before signing (lines 286-307)
  • Signs EIP-712 message with wallet (line 310)
  • Submits signed order to CoW API (line 320)
  • Persists state after completion and on errors (lines 336-348, 358)
  • Shows user-friendly toast notifications (lines 329-334, 360-364)
apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (2)

11-60: LGTM! Schema and type definitions are well-structured.

The schema includes appropriate filters and the OrderInfo interface properly includes enriched token metadata (symbols, decimals, human-readable amounts) addressing the need for UI-friendly data.


148-179: LGTM! Defensive token metadata handling is solid.

The fallback to DEFAULT_DECIMALS for missing precision and truncated address for missing symbols ensures the function remains robust when token metadata is unavailable.

apps/agentic-server/src/lib/cow/index.ts (2)

19-64: LGTM! EIP-712 domain and constants are correctly structured.

The settlement contract addresses, vault relayer address, and EIP-712 type definitions align with CoW Protocol specifications.


70-114: LGTM! Order preparation logic is correct.

The function properly constructs CoW limit orders with appropriate EIP-712 signing data. The receiver fallback to userAddress handles the case where no explicit receiver is specified.

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: 5

♻️ Duplicate comments (11)
apps/agentic-chat/src/lib/stepUtils.ts (2)

47-53: Step status logic may incorrectly report completed current step as IN_PROGRESS.

When currentStep === step and the step is already in completedSteps, the function returns IN_PROGRESS (Line 50) before checking completedSteps.has(step) (Line 51). This could cause a completed step to display as in-progress.

Consider reordering the checks as previously suggested:

 export function getStepStatus<TStep extends number>(step: TStep, state: StepState<TStep>): StepStatus {
   if (state.failedStep === step) return StepStatus.FAILED
+  if (state.completedSteps.has(step)) return StepStatus.COMPLETE
   if (state.currentStep < step) return StepStatus.NOT_STARTED
   if (state.currentStep === step && !state.error) return StepStatus.IN_PROGRESS
-  if (state.completedSteps.has(step)) return StepStatus.COMPLETE
   return StepStatus.SKIPPED
 }

1-1: Type-only import used with typeof may cause issues.

The import type { useWalletConnection } is used with typeof useWalletConnection at line 66. While this may work in type positions, it's non-idiomatic and fragile. Consider exporting and importing the return type directly from the hook file.

-import type { useWalletConnection } from '@/hooks/useWalletConnection'
+import type { WalletConnectionResult } from '@/hooks/useWalletConnection'
...
 export async function signTypedDataWithWallet(
-  evmWallet: NonNullable<ReturnType<typeof useWalletConnection>['evmWallet']>,
+  evmWallet: NonNullable<WalletConnectionResult['evmWallet']>,
   signingData: Eip712SigningData
 ): Promise<string> {
apps/agentic-server/src/lib/cow/types.ts (3)

104-117: getCowApiUrl silently defaults to mainnet for unsupported chains.

The default fallback to mainnet (line 115) could cause orders to be submitted to the wrong network if called with an unsupported chain ID. Note that apps/agentic-chat/src/lib/cow-config.ts already has a safer implementation that throws on unsupported chains.

Consider aligning with the safer pattern:

 export function getCowApiUrl(chainId: number): string {
   switch (chainId) {
     case 1:
       return 'https://api.cow.fi/mainnet'
     case 100:
       return 'https://api.cow.fi/gnosis'
     case 11155111:
       return 'https://api.cow.fi/sepolia'
     case 42161:
       return 'https://api.cow.fi/arbitrum_one'
     default:
-      return 'https://api.cow.fi/mainnet'
+      throw new Error(`Unsupported chain ID for CoW Protocol: ${chainId}`)
   }
 }

100-102: getCowExplorerUrl hardcodes mainnet format for all networks.

CoW Explorer uses network-specific paths (e.g., explorer.cow.fi/gnosis/orders/...). Orders from other networks will link to incorrect explorer pages.

Accept chainId parameter and route to correct network path:

-export function getCowExplorerUrl(orderId: string): string {
-  return `https://explorer.cow.fi/orders/${orderId}`
+export function getCowExplorerUrl(chainId: number, orderId: string): string {
+  const network = CHAIN_ID_TO_NETWORK[chainId] ?? 'mainnet'
+  return `https://explorer.cow.fi/${network}/orders/${orderId}`
 }

74-94: Inconsistent sepolia support across mappings.

COW_SUPPORTED_CHAINS includes sepolia (11155111) but NETWORK_TO_CHAIN_ID and CHAIN_ID_TO_NETWORK omit it. This inconsistency means isCowSupportedChain(11155111) returns true, but CHAIN_ID_TO_NETWORK[11155111] returns undefined.

Either add sepolia to all mappings or remove it from COW_SUPPORTED_CHAINS:

 export const NETWORK_TO_CHAIN_ID: Record<string, number> = {
   ethereum: 1,
   gnosis: 100,
   arbitrum: 42161,
+  sepolia: 11155111,
 }
 
 export const CHAIN_ID_TO_NETWORK: Record<number, string> = {
+  11155111: 'sepolia',
 }
apps/agentic-chat/src/lib/activityNormalizer.ts (1)

110-110: Hardcoded mainnet URL ignores the order's network.

This was flagged in a previous review. The URL https://explorer.cow.fi/orders/${orderId} is the mainnet format, but orders on Gnosis, Arbitrum, or Sepolia need network-specific paths like https://explorer.cow.fi/gnosis/orders/${orderId}.

Consider using output.trackingUrl if the server provides it, or construct a network-aware URL:

-    trackingUrl: `https://explorer.cow.fi/orders/${orderId}`,
+    trackingUrl: output.trackingUrl ?? `https://explorer.cow.fi/orders/${orderId}`,
apps/agentic-chat/src/hooks/useCancelLimitOrderExecution.tsx (1)

47-75: failedStep and currentStep not persisted, breaking post-refresh UI state.

The hydration function persistedStateToCancelOrderState always sets currentStep to COMPLETE and doesn't restore failedStep. After a page refresh, the UI cannot show which step failed.

As suggested in the previous review, persist these fields in meta and restore on hydration:

 function cancelOrderStateToPersistedState(
   // ...
 ): PersistedToolState {
   return {
     // ...
     meta: {
       ...(orderOutput?.orderId && { orderId: orderOutput.orderId }),
       ...(state.error && { error: state.error }),
+      ...(state.failedStep !== undefined && { failedStep: state.failedStep }),
+      ...(state.currentStep !== undefined && { currentStep: state.currentStep }),
       ...(networkName && { networkName }),
     },
     // ...
   }
 }

 function persistedStateToCancelOrderState(persisted: PersistedToolState): CancelOrderState {
+  const currentStep = (persisted.meta.currentStep as CancelOrderStep | undefined) ?? CancelOrderStep.COMPLETE
   return {
-    currentStep: CancelOrderStep.COMPLETE,
+    currentStep,
     completedSteps: CANCEL_ORDER_PHASES.fromPhases(persisted.phases),
     error: persisted.meta.error as string | undefined,
+    failedStep: persisted.meta.failedStep as CancelOrderStep | undefined,
   }
 }
apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx (1)

154-169: Add type assertion to fix TypeScript errors.

The pipeline fails with multiple TS2339: Property 'summary' does not exist on type errors. Cast tx.toolOutput to CreateLimitOrderOutput to resolve.

 const toDisplayOrder = (tx: PersistedToolState): DisplayOrder => {
-  const output = tx.toolOutput
+  const output = tx.toolOutput as CreateLimitOrderOutput | undefined
   const orderId = tx.meta.orderId as string
+  const network = output?.summary?.sellAsset?.network ?? 'ethereum'
   return {
     orderId,
-    network: output?.summary?.sellAsset?.network ?? 'unknown',
+    network,
     sellTokenSymbol: output?.summary?.sellAsset?.symbol ?? 'Unknown',
     buyTokenSymbol: output?.summary?.buyAsset?.symbol ?? 'Unknown',
     sellAmount: output?.summary?.sellAsset?.amount ?? '0',
     buyAmount: output?.summary?.buyAsset?.estimatedAmount ?? '0',
     filledPercent: 0,
     expiresAt: output?.summary?.expiresAt ?? new Date().toISOString(),
-    trackingUrl: `https://explorer.cow.fi/orders/${orderId}`,
+    trackingUrl: output?.trackingUrl ?? `https://explorer.cow.fi/${network !== 'ethereum' ? `${network}/` : ''}orders/${orderId}`,
     walletAddress: tx.walletAddress,
   }
 }

This also addresses the hardcoded mainnet URL issue flagged in previous reviews by constructing a network-aware URL.

apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (2)

34-48: Differentiate 404 (not found) from transient errors in chain detection.

The catch-all error handling prevents distinguishing between "order doesn't exist on this chain" (expected, continue to next chain) and actual failures like API downtime or network errors (should propagate). Users see "Could not find order" even when the real issue is a CoW API incident.

Based on past review comments, this issue has already been raised.


72-79: Avoid exposing order owner address in error messages.

Line 78 includes order.owner in the error message, which exposes the owner's wallet address. This is a privacy concern and should be avoided.

Based on past review comments, this issue has already been raised.

apps/agentic-server/src/lib/cow/index.ts (1)

121-163: from field should be the order signer, not receiver.

Line 144 uses order.receiver as the from field, but the CoW API expects the order signer/owner address. This is incorrect when the receiver differs from the signer (e.g., when sending tokens to another address).

Based on past review comments, this issue has already been raised.

🧹 Nitpick comments (5)
apps/agentic-chat/src/components/tools/InitiateSwapUI.tsx (1)

85-94: LGTM! Consider adding nested optional chaining for extra safety.

The refactor to inline TxStepCard.SwapPair and TxStepCard.Amount is excellent—it consolidates loading state handling and removes local subcomponents. The isLoading prop is correctly derived and passed through.

For defensive coding, consider extending optional chaining to nested properties:

 <TxStepCard.SwapPair
-  fromSymbol={swap?.sellAsset.symbol.toUpperCase()}
-  toSymbol={swap?.buyAsset.symbol.toUpperCase()}
+  fromSymbol={swap?.sellAsset?.symbol?.toUpperCase()}
+  toSymbol={swap?.buyAsset?.symbol?.toUpperCase()}
   isLoading={isLoading}
 />
 <TxStepCard.Amount
   value={swap?.buyAmountCryptoPrecision}
-  symbol={swap?.buyAsset.symbol.toUpperCase()}
+  symbol={swap?.buyAsset?.symbol?.toUpperCase()}
   isLoading={isLoading}
 />

This prevents potential runtime errors if sellAsset or buyAsset are unexpectedly undefined, though if types guarantee these properties exist when swap is defined, the current code is fine.

apps/agentic-chat/src/hooks/useSwapExecution.tsx (1)

67-70: Clarify intent: approval_skipped is metadata-only, not round-trippable.

The 'approval_skipped' phase is added conditionally but isn't in SWAP_PHASES mapping, so it won't be reconstructed via fromPhases. This appears intentional for tracking purposes only, but consider adding a brief comment to clarify this is one-way metadata.

   const phases = [
     ...SWAP_PHASES.toPhases(state.completedSteps, state.error),
+    // 'approval_skipped' is metadata-only; not reconstructed on hydration
     state.currentStep > SwapStep.APPROVAL && !state.completedSteps.has(SwapStep.APPROVAL) && 'approval_skipped',
   ].filter(Boolean) as string[]
apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx (1)

71-80: Potential division by zero handled, but consider edge case.

The rate calculation guards against division by zero with sellBn.gt(0). However, if both amounts are '0' (default fallback), the rate displays as '0' which may be confusing. Consider showing "N/A" or hiding the rate row when amounts are invalid.

apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (2)

11-28: Consider adding 'presignaturePending' to the status enum.

The schema currently allows filtering by 'open', 'fulfilled', 'cancelled', 'expired', and 'all', but not 'presignaturePending' (which is a valid CoW order status). Orders with this status will be included in 'all' results but users cannot filter specifically for them.

Apply this diff if you want to support filtering by presignaturePending orders:

 export const getLimitOrdersSchema = z.object({
   status: z
-    .enum(['open', 'fulfilled', 'cancelled', 'expired', 'all'])
+    .enum(['open', 'fulfilled', 'cancelled', 'expired', 'presignaturePending', 'all'])
     .optional()
     .default('all')
     .describe('Filter orders by status. Default is "all".'),

93-96: Consider extracting hardcoded testnet ID to a constant.

Line 95 hardcodes the Sepolia testnet chain ID 11155111 for exclusion. While functional, extracting this to a named constant would improve maintainability.

const TESTNET_CHAIN_IDS = [11155111] // Sepolia

// Then in the filter:
.filter(id => !TESTNET_CHAIN_IDS.includes(id))
📜 Review details

Configuration used: CodeRabbit 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 839d0ba and abc898f.

📒 Files selected for processing (33)
  • apps/agentic-chat/src/components/Portfolio/ActivityList.tsx (2 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx (0 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/ActivityRow.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/LimitOrderDetails.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SendDetails.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/index.ts (1 hunks)
  • apps/agentic-chat/src/components/toolUIRegistry.tsx (2 hunks)
  • apps/agentic-chat/src/components/tools/CancelLimitOrderUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/InitiateSwapUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/LimitOrderUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/SendUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/ui/TxStepCard.tsx (3 hunks)
  • apps/agentic-chat/src/hooks/useCancelLimitOrderExecution.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useSendExecution.ts (4 hunks)
  • apps/agentic-chat/src/hooks/useSwapExecution.tsx (4 hunks)
  • apps/agentic-chat/src/hooks/useToolExecutionEffect.ts (1 hunks)
  • apps/agentic-chat/src/lib/activityNormalizer.ts (3 hunks)
  • apps/agentic-chat/src/lib/cow-config.ts (1 hunks)
  • apps/agentic-chat/src/lib/eventHandlers.ts (1 hunks)
  • apps/agentic-chat/src/lib/stepUtils.ts (1 hunks)
  • apps/agentic-chat/src/stores/chatStore.ts (2 hunks)
  • apps/agentic-chat/src/types/activity.ts (2 hunks)
  • apps/agentic-server/src/index.ts (1 hunks)
  • apps/agentic-server/src/lib/cow/index.ts (1 hunks)
  • apps/agentic-server/src/lib/cow/types.ts (1 hunks)
  • apps/agentic-server/src/routes/chat.ts (4 hunks)
  • apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/index.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx
🚧 Files skipped from review as they are similar to previous changes (15)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/index.ts
  • apps/agentic-chat/src/components/toolUIRegistry.tsx
  • apps/agentic-chat/src/components/Portfolio/ActivityList.tsx
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/LimitOrderDetails.tsx
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SendDetails.tsx
  • apps/agentic-chat/src/lib/cow-config.ts
  • apps/agentic-chat/src/lib/eventHandlers.ts
  • apps/agentic-server/src/tools/limitOrder/index.ts
  • apps/agentic-chat/src/stores/chatStore.ts
  • apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx
  • apps/agentic-server/src/routes/chat.ts
  • apps/agentic-server/src/index.ts
  • apps/agentic-chat/src/components/tools/LimitOrderUI.tsx
  • apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts
  • apps/agentic-chat/src/components/tools/CancelLimitOrderUI.tsx
🧰 Additional context used
🧬 Code graph analysis (13)
apps/agentic-chat/src/components/tools/SendUI.tsx (1)
apps/agentic-chat/src/components/ui/TxStepCard.tsx (1)
  • TxStepCard (178-191)
apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx (7)
apps/agentic-chat/src/types/activity.ts (1)
  • SwapActivityDetails (9-26)
apps/agentic-chat/src/lib/explorers.ts (1)
  • getExplorerUrl (1-15)
apps/agentic-chat/src/components/ui/ToolCard.tsx (1)
  • ToolCard (71-78)
apps/agentic-chat/src/components/ui/Amount.tsx (1)
  • Amount (88-92)
apps/agentic-chat/src/lib/eventHandlers.ts (1)
  • stopPropagationHandler (4-6)
apps/agentic-chat/src/lib/utils.ts (1)
  • truncateAddress (9-12)
apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx (1)
  • SwapDetails (30-83)
apps/agentic-chat/src/components/tools/InitiateSwapUI.tsx (1)
apps/agentic-chat/src/components/ui/TxStepCard.tsx (1)
  • TxStepCard (178-191)
apps/agentic-chat/src/components/Portfolio/ActivityRow/ActivityRow.tsx (9)
apps/agentic-chat/src/types/activity.ts (1)
  • ActivityItem (70-70)
apps/agentic-chat/src/lib/explorers.ts (1)
  • getExplorerUrl (1-15)
apps/agentic-chat/src/components/ui/ToolCard.tsx (1)
  • ToolCard (71-78)
apps/agentic-chat/src/lib/eventHandlers.ts (1)
  • stopPropagationHandler (4-6)
apps/agentic-chat/src/lib/utils.ts (1)
  • truncateAddress (9-12)
apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx (1)
  • SwapDetails (13-66)
apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SendDetails.tsx (1)
  • SendDetails (10-24)
apps/agentic-chat/src/components/Portfolio/ActivityRow/components/LimitOrderDetails.tsx (1)
  • LimitOrderDetails (10-43)
apps/agentic-chat/src/components/ui/DrawerListItem.tsx (1)
  • DrawerListItem (13-41)
apps/agentic-chat/src/lib/activityNormalizer.ts (2)
apps/agentic-chat/src/stores/chatStore.ts (1)
  • PersistedToolState (22-31)
apps/agentic-chat/src/types/activity.ts (2)
  • ActivityItem (70-70)
  • LimitOrderActivityDetails (39-52)
apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (3)
apps/agentic-server/src/lib/cow/types.ts (4)
  • CowEIP712Domain (37-42)
  • NETWORK_TO_CHAIN_ID (83-87)
  • CHAIN_ID_TO_NETWORK (90-94)
  • getCowExplorerUrl (100-102)
apps/agentic-server/src/lib/cow/index.ts (2)
  • getCowOrder (193-208)
  • prepareCowOrderCancellation (214-231)
apps/agentic-server/src/utils/walletContextSimple.ts (2)
  • WalletContext (4-6)
  • getAddressForChain (13-26)
apps/agentic-chat/src/lib/stepUtils.ts (3)
apps/agentic-chat/src/hooks/useSendExecution.ts (1)
  • StepStatus (30-30)
apps/agentic-chat/src/hooks/useSwapExecution.tsx (1)
  • StepStatus (36-36)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (23-48)
apps/agentic-chat/src/hooks/useSendExecution.ts (1)
apps/agentic-chat/src/lib/stepUtils.ts (1)
  • createStepPhaseMap (12-36)
apps/agentic-chat/src/hooks/useSwapExecution.tsx (1)
apps/agentic-chat/src/lib/stepUtils.ts (1)
  • createStepPhaseMap (12-36)
apps/agentic-server/src/lib/cow/types.ts (1)
apps/agentic-chat/src/lib/cow-config.ts (1)
  • getCowApiUrl (8-14)
apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (5)
apps/agentic-server/src/lib/cow/types.ts (6)
  • CowOrderStatus (5-5)
  • CHAIN_ID_TO_NETWORK (90-94)
  • CowOrder (7-22)
  • NETWORK_TO_CHAIN_ID (83-87)
  • COW_SUPPORTED_CHAINS (75-80)
  • getCowExplorerUrl (100-102)
packages/types/src/network.ts (1)
  • Network (44-44)
apps/agentic-server/src/utils/walletContextSimple.ts (2)
  • WalletContext (4-6)
  • getAddressForChain (13-26)
apps/agentic-server/src/lib/cow/index.ts (1)
  • getCowOrders (168-188)
packages/utils/src/index.ts (1)
  • fromBaseUnit (38-41)
apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx (8)
apps/agentic-chat/src/lib/utils.ts (2)
  • cn (5-7)
  • truncateAddress (9-12)
apps/agentic-chat/src/components/ui/Amount.tsx (1)
  • Amount (88-92)
apps/agentic-chat/src/lib/eventHandlers.ts (1)
  • stopPropagationHandler (4-6)
apps/agentic-chat/src/stores/chatStore.ts (1)
  • PersistedToolState (22-31)
apps/agentic-chat/src/components/tools/toolUIHelpers.tsx (1)
  • useToolStateRender (10-31)
apps/agentic-server/src/index.ts (1)
  • GetLimitOrdersOutput (102-102)
apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (1)
  • GetLimitOrdersOutput (62-65)
apps/agentic-chat/src/components/ui/ToolCard.tsx (1)
  • ToolCard (71-78)
apps/agentic-server/src/lib/cow/index.ts (1)
apps/agentic-server/src/lib/cow/types.ts (10)
  • CowEIP712Types (44-46)
  • CowEIP712Domain (37-42)
  • CreateCowOrderParams (55-64)
  • CreateCowOrderResult (66-72)
  • isCowSupportedChain (96-98)
  • CowOrderQuote (24-35)
  • CowOrderSigningData (48-53)
  • getCowExplorerUrl (100-102)
  • getCowApiUrl (104-117)
  • CowOrder (7-22)
🪛 GitHub Actions: CI
apps/agentic-chat/src/lib/activityNormalizer.ts

[error] 1-1: TS6196: 'CreateLimitOrderOutput' is declared but never used.


[error] 96-96: TS2339: Property 'summary' does not exist on type '{ summary: { sellAsset: { symbol: string; amount: string; network: string; chainName: string; valueUSD: string; priceUSD: string; }; buyAsset: { symbol: string; estimatedAmount: string; network: string; chainName: string; estimatedValueUSD: string; priceUSD: string; }; exchange: { ...; }; isCrossChain: boolean; }; n...'.


[error] 100-100: TS2339: Property 'summary' does not exist on type '{ summary: { sellAsset: { symbol: string; amount: string; network: string; chainName: string; valueUSD: string; priceUSD: string; }; buyAsset: { symbol: string; estimatedAmount: string; network: string; chainName: string; estimatedValueUSD: string; priceUSD: string; }; exchange: { ...; }; isCrossChain: boolean; }; n...'.


[error] 101-101: TS2339: Property 'summary' does not exist on type '{ summary: { sellAsset: { symbol: string; amount: string; network: string; chainName: string; valueUSD: string; priceUSD: string; }; buyAsset: { symbol: string; estimatedAmount: string; network: string; chainName: string; estimatedValueUSD: string; priceUSD: string; }; exchange: { ...; }; isCrossChain: boolean; }; n...'.


[error] 104-104: TS2339: Property 'summary' does not exist on type '{ summary: { sellAsset: { symbol: string; amount: string; network: string; chainName: string; valueUSD: string; priceUSD: string; }; buyAsset: { symbol: string; estimatedAmount: string; network: string; chainName: string; estimatedValueUSD: string; priceUSD: string; }; exchange: { ...; }; isCrossChain: boolean; }; n...'.


[error] 105-105: TS2339: Property 'summary' does not exist on type '{ summary: { sellAsset: { symbol: string; amount: string; network: string; chainName: string; valueUSD: string; priceUSD: string; }; buyAsset: { symbol: string; estimatedAmount: string; network: string; chainName: string; estimatedValueUSD: string; priceUSD: string; }; exchange: { ...; }; isCrossChain: boolean; }; n...'.


[error] 107-107: TS2339: Property 'summary' does not exist on type '{ summary: { sellAsset: { symbol: string; amount: string; network: string; chainName: string; valueUSD: string; priceUSD: string; }; buyAsset: { symbol: string; estimatedAmount: string; network: string; chainName: string; estimatedValueUSD: string; priceUSD: string; }; exchange: { ...; }; isCrossChain: boolean; }; n...'.


[error] 108-108: TS2339: Property 'summary' does not exist on type '{ summary: { sellAsset: { symbol: string; amount: string; network: string; chainName: string; valueUSD: string; priceUSD: string; }; buyAsset: { symbol: string; estimatedAmount: string; network: string; chainName: string; estimatedValueUSD: string; priceUSD: string; }; exchange: { ...; }; isCrossChain: boolean; }; n...'.


[error] 109-109: TS2339: Property 'summary' does not exist on type '{ summary: { sellAsset: { symbol: string; amount: string; network: string; chainName: string; valueUSD: string; priceUSD: string; }; buyAsset: { symbol: string; estimatedAmount: string; network: string; chainName: string; estimatedValueUSD: string; priceUSD: string; }; exchange: { ...; }; isCrossChain: boolean; }; n...'.


[error] 118-118: TS2339: Property 'summary' does not exist on type '{ summary: { sellAsset: { symbol: string; amount: string; network: string; chainName: string; valueUSD: string; priceUSD: string; }; buyAsset: { symbol: string; estimatedAmount: string; network: string; chainName: string; estimatedValueUSD: string; priceUSD: string; }; exchange: { ...; }; isCrossChain: boolean; }; n...'.


[error] 119-119: TS2339: Property 'summary' does not exist on type '{ summary: { sellAsset: { symbol: string; amount: string; network: string; chainName: string; valueUSD: string; priceUSD: string; }; buyAsset: { symbol: string; estimatedAmount: string; network: string; chainName: string; estimatedValueUSD: string; priceUSD: string; }; exchange: { ...; }; isCrossChain: boolean; }; n...'.

apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx

[error] 1-1: TS6196: 'CreateLimitOrderOutput' is declared but never used.


[error] 159-159: TS2339: Property 'summary' does not exist on type '{ summary: { sellAsset: { symbol: string; amount: string; network: string; chainName: string; valueUSD: string; priceUSD: string; }; buyAsset: { symbol: string; estimatedAmount: string; network: string; chainName: string; estimatedValueUSD: string; priceUSD: string; }; exchange: { ...; }; isCrossChain: boolean; }; n...'.


[error] 160-160: TS2339: Property 'summary' does not exist on type '{ summary: { sellAsset: { symbol: string; amount: string; network: string; chainName: string; valueUSD: string; priceUSD: string; }; buyAsset: { symbol: string; estimatedAmount: string; network: string; chainName: string; estimatedValueUSD: string; priceUSD: string; }; exchange: { ...; }; isCrossChain: boolean; }; n...'.


[error] 161-161: TS2339: Property 'summary' does not exist on type '{ summary: { sellAsset: { symbol: string; amount: string; network: string; chainName: string; valueUSD: string; priceUSD: string; }; buyAsset: { symbol: string; estimatedAmount: string; network: string; chainName: string; estimatedValueUSD: string; priceUSD: string; }; exchange: { ...; }; isCrossChain: boolean; }; n...'.


[error] 162-162: TS2339: Property 'summary' does not exist on type '{ summary: { sellAsset: { symbol: string; amount: string; network: string; chainName: string; valueUSD: string; priceUSD: string; }; buyAsset: { symbol: string; estimatedAmount: string; network: string; chainName: string; estimatedValueUSD: string; priceUSD: string; }; exchange: { ...; }; isCrossChain: boolean; }; n...'.


[error] 163-163: TS2339: Property 'summary' does not exist on type '{ summary: { sellAsset: { symbol: string; amount: string; network: string; chainName: string; valueUSD: string; priceUSD: string; }; buyAsset: { symbol: string; estimatedAmount: string; network: string; chainName: string; estimatedValueUSD: string; priceUSD: string; }; exchange: { ...; }; isCrossChain: boolean; }; n...'.


[error] 165-165: TS2339: Property 'summary' does not exist on type '{ summary: { sellAsset: { symbol: string; amount: string; network: string; chainName: string; valueUSD: string; priceUSD: string; }; buyAsset: { symbol: string; estimatedAmount: string; network: string; chainName: string; estimatedValueUSD: string; priceUSD: string; }; exchange: { ...; }; isCrossChain: boolean; }; n...'.

🔇 Additional comments (32)
apps/agentic-chat/src/components/tools/SendUI.tsx (1)

70-70: LGTM! Clean consolidation of loading state.

The refactor to use TxStepCard.Amount with isLoading={!summary} simplifies the code by delegating loading state handling to the component. This eliminates conditional rendering logic and maintains consistent behavior across the UI.

apps/agentic-chat/src/components/ui/TxStepCard.tsx (3)

5-5: LGTM! New imports properly utilized.

The imports for formatCryptoAmount and Skeleton are correctly added and used throughout the updated components.

Also applies to: 8-8


127-150: LGTM! Excellent loading state implementation.

The updated TxStepCardSwapPair component properly handles three states:

  1. Loading: Renders Skeleton when isLoading is true
  2. Missing data: Renders a dash placeholder when symbols are undefined
  3. Data available: Renders the swap pair display

This provides consistent UX across different data availability scenarios.


152-176: LGTM! Well-structured amount component with proper formatting.

The new TxStepCardAmount component provides a robust implementation:

  1. Loading state: Renders Skeleton when isLoading is true
  2. Missing value: Renders dash placeholder when value is undefined
  3. Formatted display: Uses formatCryptoAmount for consistent number formatting with symbol
  4. Flexible prefix: Supports optional prefix (e.g., "-" for sends)
  5. Consistent styling: Uses green color and tabular-nums for amount displays

The early returns ensure type safety, and TypeScript correctly narrows the value type before formatting.

apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx (1)

1-66: Clean component extraction with proper event handling.

This component correctly extracts the swap details rendering logic with proper handling of optional fields and consistent use of the shared stopPropagationHandler utility. The structure aligns well with similar detail components in the codebase.

apps/agentic-chat/src/hooks/useSwapExecution.tsx (1)

38-44: SWAP_PHASES mapping is well-structured.

The phase mapping correctly covers all actionable steps (QUOTE through SWAP) while excluding the terminal COMPLETE step. The separation allows for clean serialization of step progress.

apps/agentic-chat/src/hooks/useSendExecution.ts (2)

30-36: Consistent phase mapping pattern.

The SEND_PHASES mapping follows the same pattern as SWAP_PHASES, correctly mapping actionable steps while excluding the terminal COMPLETE state. This maintains consistency across execution hooks.


74-82: State hydration is correct.

Setting currentStep to COMPLETE when hydrating from persisted state is appropriate since persisted transactions represent completed flows. The completedSteps reconstruction via fromPhases correctly restores the step completion set.

apps/agentic-chat/src/lib/stepUtils.ts (1)

11-36: Well-designed generic phase mapping utility.

The createStepPhaseMap function provides a clean bidirectional mapping between step enums and phase strings. The generic constraint TStep extends number correctly accommodates TypeScript enum values. Good use of type guards in the filter operations.

apps/agentic-server/src/lib/cow/types.ts (1)

5-72: Type definitions are well-structured.

The CoW Protocol types are comprehensive and correctly model the order lifecycle, EIP-712 signing data, and creation parameters. The use of literal types for kind, class, and status provides good type safety.

apps/agentic-chat/src/types/activity.ts (1)

39-70: LGTM!

The type definitions are well-structured. LimitOrderActivityItem correctly omits txHash from BaseActivityItem since limit orders identify by orderId rather than transaction hash. The estimatedAmount field appropriately reflects that buy amounts are estimates until the order fills.

apps/agentic-chat/src/components/Portfolio/ActivityRow/ActivityRow.tsx (3)

26-35: LGTM!

The formatActivityTitle switch statement exhaustively handles all activity types in the ActivityItem union. TypeScript will enforce this if new types are added to the union.


37-64: LGTM!

The ActivityDetails component correctly handles the absence of txHash for limit orders by conditionally checking activity.type !== 'limit_order'. The type-specific detail components are rendered appropriately.


66-85: LGTM!

Clean component implementation. The DrawerListItem pattern with expandedChildren provides a consistent expandable UI. Icon selection via ACTIVITY_ICONS[activity.type] is type-safe.

apps/agentic-chat/src/hooks/useCancelLimitOrderExecution.tsx (2)

90-109: LGTM!

The submitCancellation function correctly sends the DELETE request to CoW API with proper headers and body structure. Error handling extracts the response text for meaningful error messages.


153-226: Execution flow is well-structured with proper step transitions.

The multi-step flow correctly handles:

  • Wallet validation before proceeding
  • Network switching when needed
  • EIP-712 signing
  • Submission to CoW API
  • State persistence on success and error

The error handler properly captures failedStep via draft.currentStep before the error occurred.

apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (5)

9-15: LGTM!

The schema is well-structured with clear descriptions and appropriate validation for the cancellation flow.


17-32: LGTM!

Type definitions are comprehensive and correctly model the EIP-712 cancellation data structure required by CoW Protocol.


81-90: LGTM!

The status checks properly cover all non-cancellable states (fulfilled, cancelled, expired) with clear error messages for each scenario.


92-106: LGTM!

The cancellation signing data is correctly prepared using prepareCowOrderCancellation and properly augmented with primaryType for EIP-712 compliance.


109-128: LGTM!

The tool export is well-documented with clear constraints and UI guidance for proper usage in the chat flow.

apps/agentic-server/src/lib/cow/index.ts (6)

1-34: LGTM!

Constants are well-documented with clear explanations of their purpose (settlement contracts, vault relayer, default app data).


36-64: LGTM!

EIP-712 type fields and domain construction correctly implement the CoW Protocol signing requirements.


70-114: LGTM!

The limit order preparation correctly constructs the order parameters and EIP-712 signing data. The receiver fallback to userAddress (line 89) is appropriate.


168-188: LGTM!

The getCowOrders function correctly fetches orders with pagination support and proper error handling.


193-208: LGTM!

The getCowOrder function correctly fetches a specific order by ID. Note that error handling doesn't differentiate HTTP status codes, but this is addressed in context of the chain detection function in cancelLimitOrder.ts.


214-259: LGTM!

The cancellation functions correctly implement CoW Protocol's EIP-712 cancellation flow with proper signing data preparation and API submission.

apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (5)

30-60: LGTM!

The OrderInfo interface is comprehensive, including enriched data (token symbols, human-readable amounts) as mentioned in past review feedback. The resolveTokenMetadata helper properly handles missing token data with null returns.


62-73: LGTM!

The calculateFilledPercent function uses BigInt for precise percentage calculation and properly handles the zero sellAmount edge case.


98-106: LGTM!

The use of Promise.allSettled for parallel chain queries is excellent—it allows fetching from multiple chains concurrently while gracefully handling failures. The try-catch for missing wallets (lines 102-106) ensures chains without connected wallets are skipped without breaking the entire operation.

Note: This addresses previous feedback about parallel fetching.


111-140: LGTM!

The order enrichment logic is comprehensive:

  • Proper filtering by status and class (limit orders only)
  • Token metadata resolution with sensible fallbacks (lines 116-119, 128-129)
  • Human-readable amounts using fromBaseUnit
  • Fill percentage calculation and timestamps

This addresses previous feedback about enriching the output with symbols and decimals.


159-184: LGTM!

The tool export provides clear documentation with UI guidance, account scope explanation, and concrete use cases for when to invoke the tool.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/agentic-chat/src/hooks/useSwapExecution.tsx (1)

88-95: failedStep is not persisted or restored, which affects error display after page refresh.

The SwapState.failedStep field is set when an error occurs (line 324) but is not included in the meta object during persistence (lines 78-83) or restored during hydration (lines 88-95). The getStepStatus function explicitly relies on failedStep to determine StepStatus.FAILED (stepUtils.ts line 48), so after a page refresh, the UI cannot determine which specific step failed—it can only infer from completedSteps which steps succeeded.

Apply this diff to persist and restore failedStep:

 function swapStateToPersistedState(
   toolCallId: string,
   state: SwapState,
   conversationId: string,
   swapOutput: InitiateSwapOutput | null,
   networkName?: string
 ): PersistedToolState {
   const phases = [
     ...SWAP_PHASES.toPhases(state.completedSteps, state.error),
     state.currentStep > SwapStep.APPROVAL && !state.completedSteps.has(SwapStep.APPROVAL) && 'approval_skipped',
   ].filter(Boolean) as string[]

   return {
     toolCallId,
     toolType: 'swap',
     conversationId,
     timestamp: Date.now(),
     phases,
     meta: {
       ...(state.approvalTxHash && { approvalTxHash: state.approvalTxHash }),
       ...(state.swapTxHash && { swapTxHash: state.swapTxHash }),
       ...(state.error && { error: state.error }),
+      ...(state.failedStep !== undefined && { failedStep: state.failedStep }),
       ...(networkName && { networkName }),
     },
     ...(swapOutput && { toolOutput: swapOutput }),
   }
 }
 function persistedStateToSwapState(persisted: PersistedToolState): SwapState {
   return {
     currentStep: SwapStep.COMPLETE,
     completedSteps: SWAP_PHASES.fromPhases(persisted.phases),
     approvalTxHash: persisted.meta.approvalTxHash as string | undefined,
     swapTxHash: persisted.meta.swapTxHash as string | undefined,
     error: persisted.meta.error as string | undefined,
+    failedStep: persisted.meta.failedStep as SwapStep | undefined,
   }
 }
♻️ Duplicate comments (2)
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1)

221-221: trackingUrl with placeholder 'pending' may confuse users.

The tracking URL is set to getCowExplorerUrl('pending') which creates a URL like https://explorer.cow.fi/orders/pending. This links to a non-existent order page. Consider either omitting trackingUrl until a real order ID is available, or documenting that the client should update this URL after order submission.

This was flagged in a previous review. Consider making trackingUrl optional in the output type and setting it to undefined here, or returning a generic explorer URL without an order ID.

apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx (1)

166-166: Hardcoded mainnet tracking URL ignores order's network.

The trackingUrl is hardcoded to https://explorer.cow.fi/orders/${orderId} which is the mainnet explorer. For orders on Gnosis or Arbitrum, this will link to the wrong explorer page.

Consider using a network-aware URL construction:

 const toDisplayOrder = (tx: PersistedToolState): DisplayOrder => {
   const output = tx.toolOutput as CreateLimitOrderOutput | undefined
   const orderId = tx.meta.orderId as string
+  const network = output?.summary?.network ?? 'ethereum'
+  const networkPath = network === 'ethereum' ? '' : `/${network}`
   return {
     orderId,
     network: output?.summary?.network ?? 'unknown',
     // ...
-    trackingUrl: `https://explorer.cow.fi/orders/${orderId}`,
+    trackingUrl: `https://explorer.cow.fi${networkPath}/orders/${orderId}`,
     walletAddress: tx.walletAddress,
   }
 }
🧹 Nitpick comments (3)
apps/agentic-chat/src/components/tools/CancelLimitOrderUI.tsx (1)

67-68: Consider icon color semantics for cancellation completion.

The XCircle icon turns green when isComplete is true (cancellation succeeded). While technically correct (the operation succeeded), users might find a green "X" confusing since cancellation is typically associated with red. Consider using CheckCircle with green for success, or keeping XCircle red with a different success indicator.

-            <XCircle className={`h-5 w-5 ${isComplete ? 'text-green-500' : 'text-red-500'}`} />
-            <span className="text-lg font-semibold">{isComplete ? 'Order Cancelled' : 'Cancelling Order'}</span>
+            {isComplete ? (
+              <CheckCircle className="h-5 w-5 text-green-500" />
+            ) : (
+              <XCircle className="h-5 w-5 text-red-500" />
+            )}
+            <span className="text-lg font-semibold">{isComplete ? 'Order Cancelled' : 'Cancelling Order'}</span>

You'd need to add CheckCircle to the imports from lucide-react.

apps/agentic-server/src/routes/chat.ts (1)

164-187: Consider reducing verbosity of tool argument logging.

The console.log statements log the full JSON.stringify(args, null, 2) for each tool call. While helpful for debugging, this could expose user intent/amounts in logs at production level. Consider:

  1. Using a structured logger with log levels
  2. Logging only non-sensitive fields (e.g., network, asset symbols but not amounts)
  3. Redacting sensitive values

This pattern exists for other tools too, so this may be a broader refactor to consider.

apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (1)

84-96: Consider extracting testnet exclusion to a constant.

Line 95 hardcodes the Sepolia testnet ID 11155111. While functional, extracting this to a named constant (e.g., COW_TESTNET_CHAIN_IDS) would improve maintainability and make the exclusion intent clearer.

Apply this diff:

+const COW_TESTNET_CHAIN_IDS = [11155111] // Sepolia
+
 export async function executeGetLimitOrders(
   input: GetLimitOrdersInput,
   walletContext?: WalletContext
 ): Promise<GetLimitOrdersOutput> {
   // ...
   } else {
     chainsToQuery = Object.keys(COW_SUPPORTED_CHAINS)
       .map(Number)
-      .filter(id => id !== 11155111) // Exclude testnet
+      .filter(id => !COW_TESTNET_CHAIN_IDS.includes(id))
   }
📜 Review details

Configuration used: CodeRabbit 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 abc898f and 35c93c7.

📒 Files selected for processing (33)
  • apps/agentic-chat/src/components/Portfolio/ActivityList.tsx (2 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx (0 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/ActivityRow.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/LimitOrderDetails.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SendDetails.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/index.ts (1 hunks)
  • apps/agentic-chat/src/components/toolUIRegistry.tsx (2 hunks)
  • apps/agentic-chat/src/components/tools/CancelLimitOrderUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/InitiateSwapUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/LimitOrderUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/SendUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/ui/TxStepCard.tsx (3 hunks)
  • apps/agentic-chat/src/hooks/useCancelLimitOrderExecution.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useSendExecution.ts (4 hunks)
  • apps/agentic-chat/src/hooks/useSwapExecution.tsx (4 hunks)
  • apps/agentic-chat/src/hooks/useToolExecutionEffect.ts (1 hunks)
  • apps/agentic-chat/src/lib/activityNormalizer.ts (3 hunks)
  • apps/agentic-chat/src/lib/cow-config.ts (1 hunks)
  • apps/agentic-chat/src/lib/eventHandlers.ts (1 hunks)
  • apps/agentic-chat/src/lib/stepUtils.ts (1 hunks)
  • apps/agentic-chat/src/stores/chatStore.ts (2 hunks)
  • apps/agentic-chat/src/types/activity.ts (2 hunks)
  • apps/agentic-server/src/index.ts (1 hunks)
  • apps/agentic-server/src/lib/cow/index.ts (1 hunks)
  • apps/agentic-server/src/lib/cow/types.ts (1 hunks)
  • apps/agentic-server/src/routes/chat.ts (4 hunks)
  • apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/index.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx
🚧 Files skipped from review as they are similar to previous changes (14)
  • apps/agentic-chat/src/components/tools/SendUI.tsx
  • apps/agentic-chat/src/hooks/useToolExecutionEffect.ts
  • apps/agentic-server/src/index.ts
  • apps/agentic-chat/src/types/activity.ts
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/ActivityRow.tsx
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/index.ts
  • apps/agentic-chat/src/lib/stepUtils.ts
  • apps/agentic-chat/src/components/toolUIRegistry.tsx
  • apps/agentic-server/src/lib/cow/types.ts
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SendDetails.tsx
  • apps/agentic-chat/src/hooks/useCancelLimitOrderExecution.tsx
  • apps/agentic-server/src/tools/limitOrder/index.ts
  • apps/agentic-chat/src/components/tools/InitiateSwapUI.tsx
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/LimitOrderDetails.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-22T20:32:10.539Z
Learnt from: kaladinlight
Repo: shapeshift/agentic-chat PR: 76
File: apps/agentic-server/src/mastra/tools/asset/coingecko/constants.ts:1-10
Timestamp: 2025-09-22T20:32:10.539Z
Learning: When cross-app dependencies are identified (like server code importing from chat packages), the user prefers to extract shared constants into dedicated packages in the packages/ directory following the existing pattern of shapeshiftoss/types and shapeshiftoss/utils.

Applied to files:

  • apps/agentic-chat/src/stores/chatStore.ts
🧬 Code graph analysis (10)
apps/agentic-chat/src/hooks/useSwapExecution.tsx (1)
apps/agentic-chat/src/lib/stepUtils.ts (1)
  • createStepPhaseMap (12-36)
apps/agentic-chat/src/components/ui/TxStepCard.tsx (3)
apps/agentic-chat/src/components/ui/Skeleton.tsx (1)
  • Skeleton (7-7)
apps/agentic-chat/src/lib/number.ts (1)
  • formatCryptoAmount (5-5)
apps/agentic-chat/src/lib/utils.ts (1)
  • cn (5-7)
apps/agentic-chat/src/lib/cow-config.ts (1)
apps/agentic-server/src/lib/cow/types.ts (1)
  • getCowApiUrl (104-117)
apps/agentic-chat/src/hooks/useSendExecution.ts (1)
apps/agentic-chat/src/lib/stepUtils.ts (1)
  • createStepPhaseMap (12-36)
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (8)
packages/caip/src/assetId.ts (1)
  • fromAssetId (87-106)
apps/agentic-server/src/utils/transactionHelpers.ts (1)
  • createTransaction (17-33)
apps/agentic-server/src/lib/cow/types.ts (3)
  • CowOrderSigningData (48-53)
  • NETWORK_TO_CHAIN_ID (83-87)
  • getCowExplorerUrl (100-102)
packages/utils/src/index.ts (1)
  • toBaseUnit (43-46)
apps/agentic-server/src/utils/walletContextSimple.ts (2)
  • WalletContext (4-6)
  • getAddressForChain (13-26)
apps/agentic-server/src/utils/assetHelpers.ts (1)
  • resolveAsset (8-25)
apps/agentic-server/src/lib/cow/index.ts (2)
  • COW_VAULT_RELAYER_ADDRESS (30-30)
  • prepareCowLimitOrder (70-114)
apps/agentic-server/src/utils/getAllowance.ts (1)
  • getAllowance (24-57)
apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx (7)
apps/agentic-chat/src/types/activity.ts (1)
  • SwapActivityDetails (9-26)
apps/agentic-chat/src/lib/explorers.ts (1)
  • getExplorerUrl (1-15)
apps/agentic-chat/src/components/ui/ToolCard.tsx (1)
  • ToolCard (71-78)
apps/agentic-chat/src/components/ui/Amount.tsx (1)
  • Amount (88-92)
apps/agentic-chat/src/lib/eventHandlers.ts (1)
  • stopPropagationHandler (4-6)
apps/agentic-chat/src/lib/utils.ts (1)
  • truncateAddress (9-12)
apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx (1)
  • SwapDetails (30-83)
apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx (6)
apps/agentic-chat/src/lib/utils.ts (2)
  • cn (5-7)
  • truncateAddress (9-12)
apps/agentic-chat/src/components/ui/Amount.tsx (1)
  • Amount (88-92)
apps/agentic-chat/src/lib/eventHandlers.ts (1)
  • stopPropagationHandler (4-6)
apps/agentic-chat/src/stores/chatStore.ts (1)
  • PersistedToolState (22-31)
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1)
  • CreateLimitOrderOutput (87-103)
apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (1)
  • GetLimitOrdersOutput (62-65)
apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (2)
apps/agentic-server/src/lib/cow/types.ts (3)
  • CowEIP712Domain (37-42)
  • NETWORK_TO_CHAIN_ID (83-87)
  • CHAIN_ID_TO_NETWORK (90-94)
apps/agentic-server/src/lib/cow/index.ts (2)
  • getCowOrder (193-208)
  • prepareCowOrderCancellation (214-231)
apps/agentic-server/src/routes/chat.ts (5)
apps/agentic-server/src/index.ts (3)
  • createLimitOrderTool (92-92)
  • getLimitOrdersTool (99-99)
  • cancelLimitOrderTool (105-105)
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1)
  • createLimitOrderTool (225-247)
apps/agentic-server/src/tools/limitOrder/index.ts (3)
  • createLimitOrderTool (2-2)
  • getLimitOrdersTool (11-11)
  • cancelLimitOrderTool (19-19)
apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (1)
  • getLimitOrdersTool (159-184)
apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (1)
  • cancelLimitOrderTool (109-128)
apps/agentic-chat/src/components/tools/CancelLimitOrderUI.tsx (4)
apps/agentic-chat/src/components/tools/toolUIHelpers.tsx (1)
  • ToolUIComponentProps (6-8)
apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (1)
  • CancelLimitOrderOutput (26-32)
apps/agentic-chat/src/hooks/useCancelLimitOrderExecution.tsx (1)
  • useCancelLimitOrderExecution (111-247)
apps/agentic-chat/src/components/ui/TruncateText.tsx (1)
  • TruncateText (9-26)
⏰ 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: main
🔇 Additional comments (40)
apps/agentic-chat/src/hooks/useSendExecution.ts (4)

32-36: LGTM!

The phase mapping is well-structured. The omission of SendStep.COMPLETE from the mapping is correct since it represents a terminal state rather than an actionable phase.


51-72: LGTM!

The refactor to use SEND_PHASES.toPhases() correctly delegates phase serialization to the centralized utility. Error handling is properly integrated via the second parameter.


74-82: LGTM!

The hydration logic correctly reconstructs state from persisted phases. Setting currentStep to COMPLETE is appropriate for displaying historical transactions, while error information is preserved separately via failedStep and error fields.


254-270: LGTM with verification pending.

The step status computation is well-structured:

  • Preparation step status is derived from the AI toolState (streaming/availability)
  • Network switch and send steps delegate to getStepStatus utility

This separation is appropriate given the different state sources.

apps/agentic-chat/src/hooks/useSwapExecution.tsx (5)

14-14: LGTM: Centralized step utilities improve maintainability.

The import refactor consolidates StepStatus and step management utilities from @/lib/stepUtils, reducing code duplication across different tool execution hooks (swap, send, limit orders).


36-36: LGTM: Re-export maintains backward compatibility.

The re-export preserves the public API for consumers importing StepStatus from this hook.


38-44: LGTM: SWAP_PHASES mapping is complete and consistent.

The phase mapping correctly covers all execution steps (QUOTE through SWAP) and excludes COMPLETE, which is the terminal state rather than a persisted phase.


67-70: LGTM: Phase construction correctly handles approval skip case.

The logic for adding 'approval_skipped' is correct: it's only included when the swap progressed past the approval step without completing it (i.e., when needsApproval was false).


362-365: LGTM: Consistent use of imported getStepStatus utility.

The refactor correctly delegates step status calculation to the centralized utility, maintaining consistency across different tool execution flows.

apps/agentic-chat/src/components/ui/TxStepCard.tsx (1)

127-176: LGTM! Well-structured loading and empty states.

The updated SwapPair and Amount components handle loading, missing, and present data states cleanly:

  • Skeleton shown during loading
  • Dash placeholder for missing data
  • Formatted output with formatCryptoAmount when data is available

This provides a consistent and polished UX across transaction steps.

apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (3)

106-147: LGTM! Clean CoW API submission logic.

The submitSignedOrder function correctly:

  • Constructs the order payload with all required CoW Protocol fields
  • POSTs to the network-specific API endpoint
  • Handles errors with descriptive messages
  • Strips quotes from the returned orderId

162-176: LGTM! Proper hydration guard prevents duplicate initialization.

The hasHydratedRef and lastToolCallIdRef pattern correctly:

  • Resets hydration state when toolCallId changes
  • Prevents re-hydration if runtime state already exists
  • Fetches persisted state only once per toolCallId

This avoids race conditions and redundant state initialization.


195-328: LGTM! Comprehensive error handling and state persistence.

The execution flow properly:

  • Validates wallet connection and address consistency
  • Steps through each phase with state updates
  • Catches errors at any step and persists the failed state
  • Shows user-friendly toast notifications for success and failure
apps/agentic-chat/src/components/Portfolio/ActivityList.tsx (1)

15-26: LGTM! Limit order activity integration is clean.

The filtering logic correctly includes limit_order alongside swap and send, and the empty state message accurately reflects all three transaction types.

apps/agentic-chat/src/lib/eventHandlers.ts (1)

1-6: LGTM! Simple and reusable event utility.

The stopPropagationHandler provides a clean, type-safe way to prevent event bubbling on clickable elements within interactive rows.

apps/agentic-chat/src/components/tools/LimitOrderUI.tsx (2)

27-37: LGTM! Proper handling of historical skipped executions.

The check for isHistoricalSkipped correctly identifies and displays a message when no persisted data exists for a historical execution, preventing errors downstream.


39-48: LGTM! Defensive guard against incomplete step data.

Validating that all six steps are present before rendering prevents undefined access errors and provides a clear error message if step data is malformed.

apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx (1)

1-66: LGTM! Clean extraction of swap detail rendering.

The SwapDetails component properly:

  • Renders asset amounts with fiat equivalents using the Amount component
  • Conditionally shows fee and approval transaction details
  • Uses stopPropagationHandler to prevent link clicks from triggering parent row handlers
  • Generates network-specific explorer URLs via getExplorerUrl

This extraction improves modularity and follows the pattern established by other activity detail components.

apps/agentic-chat/src/components/tools/CancelLimitOrderUI.tsx (1)

13-124: LGTM!

The component follows existing UI patterns consistently, with proper guard clauses for missing data, good separation of computed values, and appropriate use of the shared TxStepCard primitives. The historical skipped handling and error states are well-implemented.

apps/agentic-chat/src/stores/chatStore.ts (1)

22-31: LGTM!

The type extensions to PersistedToolState are backward-compatible and properly align with the new limit order tooling. The addition of walletAddress enables the history mode functionality in GetLimitOrdersUI.

apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (2)

105-111: LGTM on precision handling.

The calculateBuyAmount function correctly uses BigNumber for all arithmetic, addressing the previous precision concerns. The NaN check via isNaN() provides appropriate validation.


113-186: LGTM!

The executeCreateLimitOrder function is well-structured with clear separation of concerns: asset resolution, chain ID extraction, native token handling, amount calculation, approval checking, and order preparation. The native token validation provides helpful user guidance for wrapping requirements.

apps/agentic-server/src/routes/chat.ts (1)

304-310: LGTM!

The system prompt additions for limit orders are clear and comprehensive, documenting the gasless nature, supported networks, and appropriate tool usage. This will help the AI assistant guide users correctly.

apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx (2)

71-80: LGTM on rate calculation.

Good use of BigNumber for precision-safe division. The trailing zero removal via regex is a nice touch for cleaner display.


174-253: LGTM!

The component cleanly handles both history mode (from persisted transactions) and current mode (from server data). The status validation with fallback, empty state handling, and conditional wallet address display are well-implemented.

apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (6)

1-15: LGTM – Clean schema design with auto-detection.

The schema validation and type inference are well-structured. The optional network parameter with fallback to auto-detection provides good developer experience.


17-32: LGTM – Well-defined type surface.

The type definitions clearly model the cancellation flow. The CancellationSigningData correctly includes primaryType as a literal for EIP-712 compliance.


54-70: LGTM – Solid chain resolution logic.

The chain ID determination handles both explicit network parameters and auto-detection gracefully with clear error messages.


81-90: LGTM – Comprehensive status validation.

The status checks correctly prevent cancellation of fulfilled, already-cancelled, and expired orders with clear user-facing error messages.


92-107: LGTM – Complete cancellation output structure.

The signing data preparation and output assembly are correct. The fallback to 'unknown' at line 95 is defensive programming for unsupported chains.


109-128: LGTM – Clear tool description for LLM consumption.

The tool description provides excellent guidance on UI behavior, constraints, and usage patterns. The note about gasless EIP-712 signatures is helpful context.

apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (5)

1-28: LGTM – Well-designed schema with dual data sources.

The schema elegantly handles both live API data (connected) and local history data with clear descriptions. The status enum and optional network filtering provide good flexibility.


32-73: LGTM – Robust token metadata resolution and fill calculation.

The resolveTokenMetadata function provides sensible fallbacks, and calculateFilledPercent correctly uses BigInt arithmetic to avoid floating-point precision issues.


98-144: LGTM – Excellent parallel fetching pattern.

The use of Promise.allSettled correctly handles per-chain failures without blocking other chains. The token metadata enrichment with address-based fallbacks (lines 128-129) ensures the UI always has displayable data.


146-157: LGTM – Clean result aggregation and sorting.

The result filtering and newest-first sorting provide the expected user experience for order lists.


159-184: LGTM – Comprehensive tool documentation.

The description provides clear guidance on accountScope usage and appropriate invocation contexts, helping the LLM make informed tool choices.

apps/agentic-server/src/lib/cow/index.ts (4)

1-51: LGTM – Well-documented CoW Protocol constants.

The settlement contract addresses, vault relayer, and EIP-712 type definitions align with CoW Protocol specifications. The documentation clearly explains the purpose of each constant.


70-114: LGTM – Solid limit order preparation logic.

The function correctly validates chain support, constructs EIP-712 signing data, and sets sensible defaults. Line 88's partiallyFillable: true is appropriate for limit orders (enables better price execution), though future use cases might benefit from making this configurable.


168-208: LGTM – Clean order retrieval functions.

Both getCowOrders and getCowOrder implement standard REST API patterns with appropriate error handling and type safety.


214-259: LGTM – Correct EIP-712 cancellation implementation.

The cancellation functions correctly implement CoW Protocol's gasless cancellation workflow with proper EIP-712 signing data structure.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/agentic-chat/src/hooks/useSwapExecution.tsx (2)

78-83: Persist failedStep in transaction metadata.

The meta object doesn't include failedStep, which is set during error handling (line 324). Without persisting this field, failed transactions cannot be correctly reconstructed when hydrated from storage, preventing the UI from accurately displaying which step failed.

Apply this diff to persist failedStep:

 meta: {
   ...(state.approvalTxHash && { approvalTxHash: state.approvalTxHash }),
   ...(state.swapTxHash && { swapTxHash: state.swapTxHash }),
   ...(state.error && { error: state.error }),
+  ...(state.failedStep !== undefined && { failedStep: state.failedStep }),
   ...(networkName && { networkName }),
 },

88-96: Reconstruct failure state correctly when hydrating persisted transactions.

The function unconditionally sets currentStep to COMPLETE and doesn't reconstruct failedStep, even when the persisted state contains an error. This causes failed transactions to display as complete when hydrated.

Apply this diff to properly reconstruct failed transaction state:

 function persistedStateToSwapState(persisted: PersistedToolState): SwapState {
+  const completedSteps = SWAP_PHASES.fromPhases(persisted.phases)
+  const failedStep = persisted.meta.failedStep as SwapStep | undefined
+  const hasError = Boolean(persisted.meta.error)
+  
   return {
-    currentStep: SwapStep.COMPLETE,
-    completedSteps: SWAP_PHASES.fromPhases(persisted.phases),
+    currentStep: hasError && failedStep !== undefined ? failedStep : SwapStep.COMPLETE,
+    completedSteps,
     approvalTxHash: persisted.meta.approvalTxHash as string | undefined,
     swapTxHash: persisted.meta.swapTxHash as string | undefined,
     error: persisted.meta.error as string | undefined,
+    ...(failedStep !== undefined && { failedStep }),
   }
 }
♻️ Duplicate comments (15)
apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SendDetails.tsx (1)

19-21: Don't gate Fee row on truthiness (details.fee &&)—it can hide valid "0 fee" cases.

If fee can ever be 0 (number) or an empty-ish value, the row won't render. Prefer a nullish check and (optionally) guard feeSymbol at the same time.

Apply this diff to fix the conditional:

-      {details.fee && (
-        <ToolCard.DetailItem label="Fee" value={<Amount.Crypto value={details.fee} symbol={details.feeSymbol} />} />
-      )}
+      {details.fee != null && details.feeSymbol && (
+        <ToolCard.DetailItem
+          label="Fee"
+          value={<Amount.Crypto value={details.fee} symbol={details.feeSymbol} />}
+        />
+      )}
apps/agentic-chat/src/hooks/useToolExecutionEffect.ts (1)

44-52: Error handling and cleanup concerns remain unaddressed.

The previous review comments about (1) missing cleanup/cancellation support and (2) error handling not updating runtime state are still applicable. Currently:

  • Errors are only logged to console, leaving the UI unaware of failures
  • No AbortController or cleanup function to cancel long-running operations on unmount/re-render

Since this PR focuses on "long running tools" infrastructure, these patterns become more important for limit orders that may take time to process.

apps/agentic-server/src/lib/cow/types.ts (3)

74-95: Inconsistent sepolia support across chain mappings.

COW_SUPPORTED_CHAINS includes sepolia (chainId 11155111), but NETWORK_TO_CHAIN_ID and CHAIN_ID_TO_NETWORK omit it. This causes inconsistent behavior where:

  • isCowSupportedChain(11155111) returns true
  • CHAIN_ID_TO_NETWORK[11155111] returns undefined

Either fully support sepolia by adding it to all mappings, or remove it from COW_SUPPORTED_CHAINS to avoid API-level inconsistency.

 export const NETWORK_TO_CHAIN_ID: Record<string, number> = {
   ethereum: 1,
   gnosis: 100,
   arbitrum: 42161,
+  sepolia: 11155111,
 }

 export const CHAIN_ID_TO_NETWORK: Record<number, string> = {
+  11155111: 'sepolia',
 }

100-102: getCowExplorerUrl ignores chain-specific explorer paths.

CoW Explorer uses network-specific paths (e.g., explorer.cow.fi/gnosis/orders/...). The current implementation always generates mainnet URLs, which will show incorrect data for orders on other networks.

-export function getCowExplorerUrl(orderId: string): string {
-  return `https://explorer.cow.fi/orders/${orderId}`
+export function getCowExplorerUrl(chainId: number, orderId: string): string {
+  const network = CHAIN_ID_TO_NETWORK[chainId]
+  const networkPath = network && network !== 'ethereum' ? `${network}/` : ''
+  return `https://explorer.cow.fi/${networkPath}orders/${orderId}`
 }

104-117: getCowApiUrl silently defaults to mainnet for unknown chains.

Falling back to mainnet could cause orders to be submitted to the wrong network if called with an unsupported chain ID. Consider throwing an error for unsupported chains to fail fast.

     default:
-      return 'https://api.cow.fi/mainnet'
+      throw new Error(`Unsupported chain ID for CoW Protocol: ${chainId}`)
   }
apps/agentic-chat/src/lib/activityNormalizer.ts (1)

92-122: Implementation follows established patterns correctly.

The type assertion on line 93 and overall structure mirrors normalizeSwapActivity and normalizeSendActivity. Good consistency.

However, line 110 hardcodes the mainnet explorer URL format, which will produce incorrect links for orders on Gnosis or Arbitrum. Consider using output.trackingUrl directly if the server provides the correct chain-aware URL, or construct it with the chainId.

-    trackingUrl: `https://explorer.cow.fi/orders/${orderId}`,
+    trackingUrl: output.trackingUrl ?? `https://explorer.cow.fi/orders/${orderId}`,
apps/agentic-chat/src/components/tools/LimitOrderUI.tsx (1)

47-54: completedCount calculation is inconsistent with rendered step statuses when approval is skipped.

The stepper (lines 128-137) renders approval steps with needsApproval ? approvalStep.status : StepStatus.SKIPPED, but completedCount uses the raw status values. When needsApproval is false, the UI shows these steps as SKIPPED (which counts toward completion), but completedCount uses the actual status (likely NOT_STARTED), causing a mismatch in the progress indicator.

Apply this diff to compute completedCount using the effective statuses:

+  const effectiveApprovalStatus = needsApproval ? approvalStep.status : StepStatus.SKIPPED
+  const effectiveApprovalConfirmStatus = needsApproval ? approvalConfirmStep.status : StepStatus.SKIPPED
   const completedCount = [
     prepareStep.status,
     networkStep.status,
-    approvalStep.status,
-    approvalConfirmStep.status,
+    effectiveApprovalStatus,
+    effectiveApprovalConfirmStatus,
     signStep.status,
     submitStep.status,
   ].filter(s => s === StepStatus.COMPLETE || s === StepStatus.SKIPPED).length
apps/agentic-server/src/lib/cow/index.ts (2)

53-64: Dead code: fallback to ethereum prevents error detection.

Line 54 uses COW_SETTLEMENT_CONTRACT[chainId] ?? COW_SETTLEMENT_CONTRACT[1], which means unsupported chains silently fall back to Ethereum's contract instead of throwing an error. This can lead to incorrect EIP-712 domain data for signatures on unsupported chains.

Apply this diff to throw immediately on unsupported chains:

 function getEIP712Domain(chainId: number): CowEIP712Domain {
-  const verifyingContract = COW_SETTLEMENT_CONTRACT[chainId] ?? COW_SETTLEMENT_CONTRACT[1]
+  const verifyingContract = COW_SETTLEMENT_CONTRACT[chainId]
   if (!verifyingContract) {
     throw new Error(`No settlement contract for chain ${chainId}`)
   }

121-163: from field should be the order signer, not receiver.

Line 144 sets from: order.receiver, but the CoW API expects the order owner/signer address in the from field. When the receiver differs from the signer (e.g., sending to another address), this will cause the order submission to fail or be rejected.

The function signature should accept a from parameter for the signer address:

 export async function submitCowOrder(
   chainId: number,
   order: CowOrderQuote,
   signature: string,
-  signingScheme: 'eip712' | 'ethsign' = 'eip712'
+  signingScheme: 'eip712' | 'ethsign' = 'eip712',
+  from: string
 ): Promise<string> {
   // ...
   const orderPayload = {
     // ...
-    from: order.receiver, // owner of the order
+    from, // owner/signer of the order
   }
apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (3)

84-92: Hydration always sets currentStep to COMPLETE, losing progress state.

Line 86 hardcodes currentStep: LimitOrderStep.COMPLETE regardless of which phases are present in persisted state. This means hydrated state will always appear complete even if execution failed midway, preventing the UI from showing the actual failed step.

Derive currentStep from completed phases or persist it explicitly:

 function persistedStateToLimitOrderState(persisted: PersistedToolState): LimitOrderState {
+  const completedSteps = LIMIT_ORDER_PHASES.fromPhases(persisted.phases)
+  let currentStep = LimitOrderStep.PREPARE
+  
+  if (completedSteps.has(LimitOrderStep.SUBMIT)) {
+    currentStep = LimitOrderStep.COMPLETE
+  } else if (completedSteps.has(LimitOrderStep.SIGN)) {
+    currentStep = LimitOrderStep.SUBMIT
+  } else if (completedSteps.has(LimitOrderStep.APPROVAL_CONFIRMATION)) {
+    currentStep = LimitOrderStep.SIGN
+  } else if (completedSteps.has(LimitOrderStep.APPROVAL)) {
+    currentStep = LimitOrderStep.APPROVAL_CONFIRMATION
+  } else if (completedSteps.has(LimitOrderStep.NETWORK_SWITCH)) {
+    currentStep = LimitOrderStep.APPROVAL
+  } else if (completedSteps.has(LimitOrderStep.PREPARE)) {
+    currentStep = LimitOrderStep.NETWORK_SWITCH
+  }
+
   return {
-    currentStep: LimitOrderStep.COMPLETE,
-    completedSteps: LIMIT_ORDER_PHASES.fromPhases(persisted.phases),
+    currentStep,
+    completedSteps,
     orderId: persisted.meta.orderId as string | undefined,
     approvalTxHash: persisted.meta.approvalTxHash as string | undefined,
     error: persisted.meta.error as string | undefined,
+    failedStep: persisted.meta.failedStep as LimitOrderStep | undefined,
   }
 }

247-268: Missing publicClient silently skips approval confirmation.

Lines 252-257 skip waiting for the transaction receipt when publicClient is null, but still mark the APPROVAL_CONFIRMATION step as complete. This could lead to race conditions where the approval hasn't been confirmed on-chain when signing begins.

Consider logging a warning or throwing an error when publicClient is unavailable:

       if (needsApproval && approvalTxHash) {
         const publicClient = getPublicClient(wagmiConfig, {
           chainId: orderParams.chainId,
         })
-        if (publicClient) {
+        if (!publicClient) {
+          console.warn(`[useLimitOrderExecution] No public client for chain ${orderParams.chainId}, skipping receipt confirmation`)
+        } else {
           await publicClient.waitForTransactionReceipt({
             hash: approvalTxHash as `0x${string}`,
             confirmations: 1,
           })
         }

364-364: Hardcoded mainnet tracking URL ignores order's actual network.

Line 364 uses https://explorer.cow.fi/orders/${state.orderId} as a fallback, which assumes mainnet regardless of the order's actual chain. This will produce incorrect links for orders on Gnosis, Arbitrum, or other networks.

Rely solely on orderData?.trackingUrl or construct a network-aware fallback:

-    trackingUrl: state.orderId ? `https://explorer.cow.fi/orders/${state.orderId}` : orderData?.trackingUrl,
+    trackingUrl: orderData?.trackingUrl,
apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (2)

34-48: Chain detection treats all errors as "not found", masking API failures.

Lines 42-44 catch all exceptions from getCowOrder and treat them as "order not on this chain". This conflates genuine 404s (order doesn't exist) with transient failures (API down, network timeout), leading to misleading error messages when the CoW API is unavailable.

Differentiate between 404 (not found) and other errors by checking response status in getCowOrder or propagating distinct error types, then handle 404s separately in the loop while failing fast on transient errors.


77-79: Avoid echoing full order.owner address in error messages.

Line 78 includes the full order.owner address in the error message. This exposes potentially sensitive wallet address information in logs and client-facing error messages.

Mask or omit the owner address:

   if (order.owner.toLowerCase() !== userAddress.toLowerCase()) {
-    throw new Error(`You do not own this order. Order owner: ${order.owner}`)
+    throw new Error(`You do not own this order. Please check the order ID and try again.`)
   }
apps/agentic-chat/src/hooks/useCancelLimitOrderExecution.tsx (1)

70-76: Hydration loses failedStep and forces currentStep to COMPLETE.

Line 72 hardcodes currentStep: CancelOrderStep.COMPLETE and line 74 doesn't restore failedStep from persisted state. This means after a page refresh, the UI can't show which step failed, and the step indicator will always appear complete even if execution failed midway.

Persist and restore both currentStep and failedStep:

 function cancelOrderStateToPersistedState(
   // ...
 ): PersistedToolState {
   return {
     // ...
     meta: {
       ...(orderOutput?.orderId && { orderId: orderOutput.orderId }),
       ...(state.error && { error: state.error }),
+      ...(state.failedStep !== undefined && { failedStep: state.failedStep }),
+      currentStep: state.currentStep,
       ...(networkName && { networkName }),
     },
   }
 }

 function persistedStateToCancelOrderState(persisted: PersistedToolState): CancelOrderState {
   return {
-    currentStep: CancelOrderStep.COMPLETE,
+    currentStep: (persisted.meta.currentStep as CancelOrderStep) ?? CancelOrderStep.COMPLETE,
     completedSteps: CANCEL_ORDER_PHASES.fromPhases(persisted.phases),
     error: persisted.meta.error as string | undefined,
+    failedStep: persisted.meta.failedStep as CancelOrderStep | undefined,
   }
 }
🧹 Nitpick comments (7)
apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx (3)

25-27: Remove unnecessary fragments.

The empty fragments wrapping <Amount.Fiat> components serve no purpose and can be removed for cleaner code.

Apply this diff:

           suffix={
-            <>
-              (<Amount.Fiat value={details.sellAsset.valueUSD} />)
-            </>
+            (<Amount.Fiat value={details.sellAsset.valueUSD} />)
           }
           suffix={
-            <>
-              (<Amount.Fiat value={details.buyAsset.valueUSD} />)
-            </>
+            (<Amount.Fiat value={details.buyAsset.valueUSD} />)
           }

Also applies to: 39-41


48-48: Simplify redundant condition.

Since approvalExplorerUrl is already undefined when details.approval is falsy (line 14), checking both conditions is redundant.

Apply this diff:

-      {details.approval && approvalExplorerUrl && (
+      {approvalExplorerUrl && (
         <ToolCard.DetailItem

52-60: Consider adding an accessible label for the approval link.

The truncated hash alone may not provide sufficient context for screen reader users. Adding an aria-label would improve accessibility.

Apply this diff:

           <a
             href={approvalExplorerUrl}
             target="_blank"
             rel="noopener noreferrer"
+            aria-label={`View approval transaction ${details.approval.txHash} on block explorer`}
             className="font-mono text-sm text-blue-500 hover:text-blue-400 transition-colors"
             onClick={stopPropagationHandler}
           >
apps/agentic-chat/src/components/tools/CancelLimitOrderUI.tsx (2)

66-70: Consider using a semantically appropriate icon for the completed state.

XCircle with green color for "Order Cancelled" is semantically confusing since X typically indicates error or failure. Consider using CheckCircle for the completed state to better convey success, or keep XCircle but maintain red color since cancellation is inherently a "stop" action.

-import { ExternalLink, XCircle } from 'lucide-react'
+import { CheckCircle, ExternalLink, XCircle } from 'lucide-react'
-            <XCircle className={`h-5 w-5 ${isComplete ? 'text-green-500' : 'text-red-500'}`} />
+            {isComplete ? (
+              <CheckCircle className="h-5 w-5 text-green-500" />
+            ) : (
+              <XCircle className="h-5 w-5 text-red-500" />
+            )}

73-87: Consider guarding against undefined networkName in the details section.

If orderId exists but networkName is undefined, the Network detail item will render an empty span. Consider adding a fallback or including networkName in the guard condition.

-      {orderId && (
+      {orderId && networkName && (

Or provide a fallback:

-            <TxStepCard.DetailItem label="Network" value={<span className="capitalize">{networkName}</span>} />
+            <TxStepCard.DetailItem label="Network" value={<span className="capitalize">{networkName ?? 'Unknown'}</span>} />
apps/agentic-chat/src/hooks/useSendExecution.ts (1)

196-207: Minor: Redundant step additions in finalCompletedSteps.

PREPARATION is already added to state.completedSteps at line 144, and SEND is added via draft.completedSteps.add(draft.currentStep) at line 204. The explicit additions at lines 199-200 are redundant since the set already contains these values.

-      // Build final state with all completed steps
-      const finalCompletedSteps = new Set(state.completedSteps)
-      finalCompletedSteps.add(SendStep.PREPARATION)
-      finalCompletedSteps.add(SendStep.SEND)

       setState(draft => {
         draft.sendTxHash = sendTxHash
         draft.completedSteps.add(draft.currentStep)
         draft.currentStep = SendStep.COMPLETE
         draft.error = undefined
       })
+
+      // Use the accumulated completedSteps from state
+      const finalCompletedSteps = new Set(state.completedSteps)
+      finalCompletedSteps.add(SendStep.SEND)

Or simply use state.completedSteps directly in finalState since it should already contain all completed steps after the setState call.

apps/agentic-chat/src/hooks/useSwapExecution.tsx (1)

67-70: Consider clarifying the approval_skipped conditional logic.

The current implementation uses boolean short-circuit evaluation and relies on filter(Boolean) to remove false values. While functionally correct, a more explicit approach would improve readability.

Apply this diff for clearer intent:

-  const phases = [
-    ...SWAP_PHASES.toPhases(state.completedSteps, state.error),
-    state.currentStep > SwapStep.APPROVAL && !state.completedSteps.has(SwapStep.APPROVAL) && 'approval_skipped',
-  ].filter(Boolean) as string[]
+  const phases = [
+    ...SWAP_PHASES.toPhases(state.completedSteps, state.error),
+    ...(state.currentStep > SwapStep.APPROVAL && !state.completedSteps.has(SwapStep.APPROVAL) ? ['approval_skipped'] : []),
+  ]
📜 Review details

Configuration used: CodeRabbit 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 35c93c7 and 8fe318a.

📒 Files selected for processing (34)
  • apps/agentic-chat/src/components/Portfolio/ActivityList.tsx (2 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx (0 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/ActivityRow.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/LimitOrderDetails.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SendDetails.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx (1 hunks)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/index.ts (1 hunks)
  • apps/agentic-chat/src/components/toolUIRegistry.tsx (2 hunks)
  • apps/agentic-chat/src/components/tools/CancelLimitOrderUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/InitiateSwapUI.tsx (3 hunks)
  • apps/agentic-chat/src/components/tools/LimitOrderUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/tools/SendUI.tsx (1 hunks)
  • apps/agentic-chat/src/components/ui/TxStepCard.tsx (3 hunks)
  • apps/agentic-chat/src/hooks/useCancelLimitOrderExecution.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (1 hunks)
  • apps/agentic-chat/src/hooks/useSendExecution.ts (4 hunks)
  • apps/agentic-chat/src/hooks/useSwapExecution.tsx (4 hunks)
  • apps/agentic-chat/src/hooks/useToolExecutionEffect.ts (1 hunks)
  • apps/agentic-chat/src/lib/activityNormalizer.ts (3 hunks)
  • apps/agentic-chat/src/lib/cow-config.ts (1 hunks)
  • apps/agentic-chat/src/lib/eventHandlers.ts (1 hunks)
  • apps/agentic-chat/src/lib/mixpanel.ts (1 hunks)
  • apps/agentic-chat/src/lib/stepUtils.ts (1 hunks)
  • apps/agentic-chat/src/stores/chatStore.ts (2 hunks)
  • apps/agentic-chat/src/types/activity.ts (2 hunks)
  • apps/agentic-server/src/index.ts (1 hunks)
  • apps/agentic-server/src/lib/cow/index.ts (1 hunks)
  • apps/agentic-server/src/lib/cow/types.ts (1 hunks)
  • apps/agentic-server/src/routes/chat.ts (5 hunks)
  • apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (1 hunks)
  • apps/agentic-server/src/tools/limitOrder/index.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx
🚧 Files skipped from review as they are similar to previous changes (12)
  • apps/agentic-chat/src/lib/eventHandlers.ts
  • apps/agentic-chat/src/components/Portfolio/ActivityList.tsx
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/ActivityRow.tsx
  • apps/agentic-chat/src/lib/cow-config.ts
  • apps/agentic-server/src/index.ts
  • apps/agentic-chat/src/components/tools/InitiateSwapUI.tsx
  • apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts
  • apps/agentic-chat/src/lib/stepUtils.ts
  • apps/agentic-chat/src/components/Portfolio/ActivityRow/components/LimitOrderDetails.tsx
  • apps/agentic-chat/src/types/activity.ts
  • apps/agentic-chat/src/components/toolUIRegistry.tsx
  • apps/agentic-chat/src/components/tools/GetLimitOrdersUI.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-22T20:32:10.539Z
Learnt from: kaladinlight
Repo: shapeshift/agentic-chat PR: 76
File: apps/agentic-server/src/mastra/tools/asset/coingecko/constants.ts:1-10
Timestamp: 2025-09-22T20:32:10.539Z
Learning: When cross-app dependencies are identified (like server code importing from chat packages), the user prefers to extract shared constants into dedicated packages in the packages/ directory following the existing pattern of shapeshiftoss/types and shapeshiftoss/utils.

Applied to files:

  • apps/agentic-chat/src/stores/chatStore.ts
🧬 Code graph analysis (11)
apps/agentic-chat/src/components/tools/SendUI.tsx (1)
apps/agentic-chat/src/components/ui/TxStepCard.tsx (1)
  • TxStepCard (178-191)
apps/agentic-chat/src/components/tools/CancelLimitOrderUI.tsx (7)
apps/agentic-chat/src/components/tools/toolUIHelpers.tsx (1)
  • ToolUIComponentProps (6-8)
apps/agentic-server/src/index.ts (1)
  • CancelLimitOrderOutput (108-108)
apps/agentic-server/src/tools/limitOrder/index.ts (1)
  • CancelLimitOrderOutput (23-23)
apps/agentic-chat/src/stores/chatStore.ts (1)
  • useChatStore (76-195)
apps/agentic-chat/src/hooks/useCancelLimitOrderExecution.tsx (1)
  • useCancelLimitOrderExecution (112-253)
apps/agentic-chat/src/components/ui/TxStepCard.tsx (1)
  • TxStepCard (178-191)
apps/agentic-chat/src/components/ui/TruncateText.tsx (1)
  • TruncateText (9-26)
apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SendDetails.tsx (5)
apps/agentic-chat/src/types/activity.ts (1)
  • SendActivityDetails (28-37)
apps/agentic-chat/src/components/ui/ToolCard.tsx (1)
  • ToolCard (71-78)
apps/agentic-chat/src/components/ui/Amount.tsx (1)
  • Amount (88-92)
apps/agentic-chat/src/lib/utils.ts (1)
  • truncateAddress (9-12)
apps/agentic-chat/src/components/Portfolio/ActivityRow.tsx (1)
  • SendDetails (85-99)
apps/agentic-chat/src/lib/activityNormalizer.ts (4)
apps/agentic-chat/src/stores/chatStore.ts (1)
  • PersistedToolState (22-31)
apps/agentic-chat/src/types/activity.ts (1)
  • LimitOrderActivityDetails (39-52)
apps/agentic-server/src/index.ts (1)
  • CreateLimitOrderOutput (95-95)
apps/agentic-server/src/tools/limitOrder/index.ts (1)
  • CreateLimitOrderOutput (6-6)
apps/agentic-chat/src/hooks/useCancelLimitOrderExecution.tsx (11)
apps/agentic-server/src/tools/limitOrder/cancelLimitOrder.ts (1)
  • CancelLimitOrderOutput (26-32)
apps/agentic-chat/src/lib/stepUtils.ts (2)
  • createStepPhaseMap (12-36)
  • getStepStatus (47-53)
apps/agentic-chat/src/stores/chatStore.ts (2)
  • PersistedToolState (22-31)
  • useChatStore (76-195)
apps/agentic-chat/src/hooks/useSendExecution.ts (1)
  • StepStatus (30-30)
apps/agentic-chat/src/hooks/useSwapExecution.tsx (1)
  • StepStatus (36-36)
apps/agentic-chat/src/lib/cow-config.ts (1)
  • getCowApiUrl (8-14)
apps/agentic-server/src/lib/cow/types.ts (1)
  • getCowApiUrl (104-117)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (23-48)
apps/agentic-chat/src/providers/ChatProvider.tsx (1)
  • useChatContext (33-39)
apps/agentic-chat/src/hooks/useToolExecutionEffect.ts (1)
  • useToolExecutionEffect (10-60)
apps/agentic-chat/src/lib/mixpanel.ts (1)
  • analytics (8-72)
apps/agentic-chat/src/hooks/useSendExecution.ts (1)
apps/agentic-chat/src/lib/stepUtils.ts (1)
  • createStepPhaseMap (12-36)
apps/agentic-chat/src/components/tools/LimitOrderUI.tsx (10)
apps/agentic-chat/src/components/tools/toolUIHelpers.tsx (1)
  • ToolUIComponentProps (6-8)
apps/agentic-server/src/index.ts (1)
  • CreateLimitOrderOutput (95-95)
apps/agentic-server/src/tools/limitOrder/index.ts (1)
  • CreateLimitOrderOutput (6-6)
apps/agentic-chat/src/stores/chatStore.ts (1)
  • useChatStore (76-195)
apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (1)
  • useLimitOrderExecution (150-366)
apps/agentic-chat/src/components/ui/TxStepCard.tsx (1)
  • TxStepCard (178-191)
apps/agentic-chat/src/hooks/useSwapExecution.tsx (1)
  • StepStatus (36-36)
apps/agentic-chat/src/components/ui/Skeleton.tsx (1)
  • Skeleton (7-7)
apps/agentic-chat/src/components/ui/Amount.tsx (1)
  • Amount (88-92)
apps/agentic-chat/src/components/ui/TruncateText.tsx (1)
  • TruncateText (9-26)
apps/agentic-chat/src/hooks/useSwapExecution.tsx (1)
apps/agentic-chat/src/lib/stepUtils.ts (1)
  • createStepPhaseMap (12-36)
apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (4)
apps/agentic-server/src/lib/cow/types.ts (6)
  • CowOrderStatus (5-5)
  • CHAIN_ID_TO_NETWORK (90-94)
  • CowOrder (7-22)
  • NETWORK_TO_CHAIN_ID (83-87)
  • COW_SUPPORTED_CHAINS (75-80)
  • getCowExplorerUrl (100-102)
apps/agentic-server/src/utils/walletContextSimple.ts (2)
  • WalletContext (4-6)
  • getAddressForChain (13-26)
apps/agentic-server/src/lib/cow/index.ts (1)
  • getCowOrders (168-188)
packages/utils/src/index.ts (1)
  • fromBaseUnit (38-41)
apps/agentic-server/src/lib/cow/index.ts (2)
apps/agentic-server/src/lib/cow/types.ts (10)
  • CowEIP712Types (44-46)
  • CowEIP712Domain (37-42)
  • CreateCowOrderParams (55-64)
  • CreateCowOrderResult (66-72)
  • isCowSupportedChain (96-98)
  • CowOrderQuote (24-35)
  • CowOrderSigningData (48-53)
  • getCowExplorerUrl (100-102)
  • getCowApiUrl (104-117)
  • CowOrder (7-22)
apps/agentic-chat/src/lib/cow-config.ts (1)
  • getCowApiUrl (8-14)
apps/agentic-chat/src/hooks/useLimitOrderExecution.tsx (9)
apps/agentic-server/src/tools/limitOrder/createLimitOrder.ts (1)
  • CreateLimitOrderOutput (87-103)
apps/agentic-chat/src/lib/stepUtils.ts (2)
  • createStepPhaseMap (12-36)
  • getStepStatus (47-53)
apps/agentic-chat/src/stores/chatStore.ts (2)
  • PersistedToolState (22-31)
  • useChatStore (76-195)
apps/agentic-chat/src/lib/cow-config.ts (1)
  • getCowApiUrl (8-14)
apps/agentic-server/src/lib/cow/types.ts (1)
  • getCowApiUrl (104-117)
apps/agentic-chat/src/hooks/useWalletConnection.ts (1)
  • useWalletConnection (23-48)
apps/agentic-chat/src/providers/ChatProvider.tsx (1)
  • useChatContext (33-39)
apps/agentic-chat/src/hooks/useToolExecutionEffect.ts (1)
  • useToolExecutionEffect (10-60)
apps/agentic-chat/src/lib/mixpanel.ts (1)
  • analytics (8-72)
🔇 Additional comments (14)
apps/agentic-chat/src/components/Portfolio/ActivityRow/components/SwapDetails.tsx (1)

8-11: Verify if SwapDetailsProps should be exported.

The AI summary states that props are "exposed as SwapDetailsProps," but the type is not explicitly exported. If this type is intended for reuse in other components or tests, add an export.

Apply this diff if the type should be exported:

-type SwapDetailsProps = {
+export type SwapDetailsProps = {
   details: SwapActivityDetails
   network: string
 }
apps/agentic-chat/src/components/Portfolio/ActivityRow/index.ts (1)

1-1: LGTM! Clean barrel export following best practices.

The barrel export simplifies imports and supports the refactored directory-based component structure. All imports have been correctly updated to reference the new path.

apps/agentic-chat/src/lib/mixpanel.ts (1)

48-65: LGTM!

The new analytics tracking methods follow the established pattern consistently, with appropriate props for each event type and proper analyticsEnabled guards.

apps/agentic-chat/src/components/tools/SendUI.tsx (1)

70-70: LGTM!

Good simplification by delegating loading state handling to TxStepCard.Amount via the isLoading prop, which is cleaner than separate conditional branches.

apps/agentic-chat/src/stores/chatStore.ts (1)

22-31: LGTM!

Clean type expansion to support the new limit order tools. The addition of walletAddress to PersistedToolState enables proper wallet-sensitive display in activity history.

apps/agentic-chat/src/components/tools/LimitOrderUI.tsx (1)

66-119: LGTM on the header and details rendering.

The conditional rendering with optional chaining, Skeleton loading states, and proper symbol formatting are well implemented. The component handles both loading and error states gracefully.

apps/agentic-chat/src/components/tools/CancelLimitOrderUI.tsx (1)

13-56: LGTM on the component logic and state management.

The step extraction, historical skipped handling, and footer message derivation follow the established pattern from LimitOrderUI. The 4-step flow (prepare, network, sign, submit) is correctly implemented without the approval complexity.

apps/agentic-server/src/tools/limitOrder/index.ts (1)

1-24: LGTM on the barrel file structure.

Clean re-export hub that aggregates all limit order functionality. Consistent naming convention and proper use of type keyword for type-only exports.

apps/agentic-chat/src/hooks/useSendExecution.ts (1)

30-36: LGTM on the SEND_PHASES abstraction.

The createStepPhaseMap usage provides a clean, centralized approach to step-phase serialization/deserialization. Re-exporting StepStatus maintains backward compatibility for consumers.

apps/agentic-chat/src/components/ui/TxStepCard.tsx (2)

127-150: LGTM on the SwapPair loading and empty state handling.

Good defensive programming with early returns for loading and missing data states. The em dash fallback provides clear visual indication of missing data.


152-176: LGTM on the Amount component refactor.

The component now properly handles loading states with Skeleton, undefined values with a dash fallback, and uses formatCryptoAmount for consistent number formatting. The optional prefix prop adds flexibility for rendering contexts that need it.

apps/agentic-server/src/routes/chat.ts (1)

28-28: LGTM! Clean integration of limit order tools.

The limit order tools are properly imported, wrapped with wallet context, and documented in the system prompt. The integration is consistent with the existing tool patterns.

Also applies to: 115-117, 249-256

apps/agentic-server/src/tools/limitOrder/getLimitOrders.ts (1)

75-157: LGTM! Solid multi-chain order aggregation with proper error handling.

The implementation correctly:

  • Uses Promise.allSettled for parallel per-chain fetches (lines 98-144)
  • Enriches orders with token metadata and human-readable amounts
  • Handles missing wallets gracefully with try-catch (lines 102-106)
  • Filters and sorts results appropriately
apps/agentic-chat/src/hooks/useSwapExecution.tsx (1)

362-365: No compatibility issues found between getStepStatus and SwapState.

The getStepStatus function from @/lib/stepUtils is compatible with SwapState. The function's generic StepState<TStep> interface requires currentStep, completedSteps, error, and failedStep properties—all of which are present in SwapState with compatible types. The extra properties in SwapState (approvalTxHash, swapTxHash) are not used by the function and do not cause issues.

@premiumjibles
Copy link
Contributor Author

Regarding the CodeRabbit feedback on useToolExecutionEffect.ts:

Error handling updating runtime state: Not necessary - errors ARE already being captured in state. The execute callbacks passed to useToolExecutionEffect (in useLimitOrderExecution.tsx, useSwapExecution.tsx, etc.) all have their own try/catch blocks that set draft.error = errorMessage. The hook's catch block is just a fallback for unexpected throws.

Add cleanup and cancellation support: Not worth implementing for this context:

  • The hasRuntimeState(toolCallId) check already prevents re-execution
  • Tool executions involve wallet signatures which are user-blocking interactions - you can't cancel a MetaMask popup
  • The actual async operations (API calls) are quick
  • Adding AbortController adds complexity without practical benefit

@premiumjibles premiumjibles merged commit bdb0b79 into main Dec 16, 2025
2 of 4 checks passed
@premiumjibles premiumjibles deleted the limit-orders branch December 16, 2025 06:52
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