Skip to content

fix(explorer): solver winner selection fix#7234

Merged
fairlighteth merged 7 commits intodevelopfrom
fix/solver-winner-explorer
Apr 6, 2026
Merged

fix(explorer): solver winner selection fix#7234
fairlighteth merged 7 commits intodevelopfrom
fix/solver-winner-explorer

Conversation

@alfetopito
Copy link
Copy Markdown
Collaborator

@alfetopito alfetopito commented Mar 31, 2026

Summary

Fix bug reported by Bram in the solver winner selection.

On production, this order incorrectly showns Rizzolver as a winning solver for one of the fills

image

Since the introduction of combinatorial auctions, a single settlement can have more than one winning solution.

Thus, we also need to check for the inclusion of the order in a given winning solution:

image

To Test

  1. Load this order 0x03060706bc82e134fc9bf8c3941711cf50aa8364dbc3e8811cf5b60bd27d7047b1acdb57a218069f6c7308e2dc90828fbf486e0269ee46d1
  2. Check the order fills tab
  • All of the solvers displayed should be Kipseli

Summary by CodeRabbit

  • Bug Fixes
    • Solver selection for trades now correctly ties solver info to the specific order shown in transaction details, improving accuracy of the solved badge and loading behavior.
  • Tests
    • Added and adjusted tests to validate order-specific solver matching and the case where a competition winner does not match the requested order.

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 31, 2026

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

Project Deployment Actions Updated (UTC)
cowfi Ready Ready Preview Apr 6, 2026 3:58pm
explorer-dev Ready Ready Preview Apr 6, 2026 3:58pm
swap-dev Ready Ready Preview Apr 6, 2026 3:58pm
widget-configurator Ready Ready Preview Apr 6, 2026 3:58pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
cosmos Ignored Ignored Apr 6, 2026 3:58pm
sdk-tools Ignored Ignored Preview Apr 6, 2026 3:58pm

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 31, 2026

Walkthrough

The PR threads orderId through the solver resolution path: component → hook → shared resolver, and refines winner selection to only accept competition solutions that include the specified order ID. Tests and mocks are updated to provide and validate the new parameter.

Changes

Cohort / File(s) Summary
Component
apps/explorer/src/components/orders/OrderDetails/FillsTableRow.tsx
Destructure orderId from trade and pass orderId into TradeSolverCell; TradeSolverCell signature now accepts { txHash, orderId }.
Hooks & Resolver
apps/explorer/src/hooks/useTradeSolver.ts, apps/explorer/src/hooks/orderSolverShared.ts
useTradeSolver signature extended to (txHash, orderId) and guards/keys updated to include orderId. resolveSolverByTxHash now requires orderId and getWinnerSolverFromCompetition filters winners to solutions whose orders include the specified orderId.
Tests & Mocks
apps/explorer/src/test/hooks/useOrderSolver.test.tsx, apps/explorer/src/test/hooks/useTradeSolver.test.tsx
Test helpers and mocks updated to accept orderId; test invocations of useTradeSolver pass orderId; added a test ensuring mismatched orderId results in no selected solver.

Sequence Diagram(s)

sequenceDiagram
  participant UI as Client (FillsTableRow)
  participant Hook as useTradeSolver
  participant Resolver as orderSolverShared.resolveSolverByTxHash
  participant API as Solver Competition API

  rect rgba(173,216,230,0.5)
  UI->>Hook: call useTradeSolver(txHash, orderId)
  Hook->>Resolver: resolveSolverByTxHash(networkId, txHash, orderId)
  Resolver->>API: fetch competition by txHash
  API-->>Resolver: competition data
  Resolver->>Resolver: getWinnerSolverFromCompetition(competition, orderId)
  alt matching winner found
    Resolver-->>Hook: solverInfo
  else no matching winner
    Resolver-->>Hook: undefined
  end
  Hook-->>UI: solver state / metadata
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 I carried orderId along the trail,
Through hooks and queries without fail,
Winners now must show their claim,
No stray solver hides its name —
Hoppity hops, the match is hale!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: fixing the solver winner selection logic in the explorer component.
Description check ✅ Passed The description includes a summary with issue context, screenshots, and testing steps, though it lacks explicit 'Background' section and some formatting follows the template loosely.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/solver-winner-explorer

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.

@alfetopito
Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 31, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

if (!competition?.solutions?.length || !orderId) return undefined

const winner = competition.solutions.find((s) => s.isWinner)
const winner = competition.solutions.find((s) => s.isWinner && s.orders?.find((o) => o?.id === orderId))
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This is the main fix. The rest is boilerplate to pass down the orderId to this point.

@alfetopito alfetopito self-assigned this Mar 31, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (2)
apps/explorer/src/test/hooks/useTradeSolver.test.tsx (1)

74-134: ⚠️ Potential issue | 🟡 Minor

Add a mismatch orderId regression test.

Current tests only assert matching orderId paths. Please add one case where the winner solution contains a different order id and assert solver stays undefined.

Suggested test addition
+  it('ignores winner solutions for a different orderId', async () => {
+    mockedGetSolverCompetitionByTxHash.mockResolvedValueOnce(
+      mockSolverCompetitionResponse('projectblanc', '0xother-order'),
+    )
+    mockedFetchSolversInfo.mockResolvedValueOnce(MOCK_SOLVERS)
+
+    const { result } = renderHook(() => useTradeSolver('0xtx123', '0xrequested-order'))
+
+    await waitFor(() => expect(result.current.isLoading).toBe(false))
+    expect(result.current.solver).toBeUndefined()
+  })

As per coding guidelines, "When changing interface: search all usages with rg, update every call, remove dead imports; refresh dependency arrays, test edge cases, ensure type safety."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/explorer/src/test/hooks/useTradeSolver.test.tsx` around lines 74 - 134,
Add a regression test to useTradeSolver that verifies a mismatch between the
winner solution's orderId and the requested orderId yields undefined: arrange
mockedGetSolverCompetitionByTxHash to resolve to a SolverCompetitionResponse
whose winning solution has a different orderId than the one passed to
useTradeSolver (use mockSolverCompetitionResponse or construct a response with
auctionId and solutions where solution.orderId !== the test orderId), mock
mockedFetchSolversInfo as before, renderHook(() => useTradeSolver(<txHash>,
<orderId>Mismatch)), wait for loading to finish, and assert
result.current.solver is undefined; reference useTradeSolver,
mockedGetSolverCompetitionByTxHash, mockSolverCompetitionResponse, and
mockedFetchSolversInfo to locate where to add the test.
apps/explorer/src/hooks/useTradeSolver.ts (1)

14-40: ⚠️ Potential issue | 🟠 Major

currentKey must include orderId to avoid stale solver state.

At Line 14 and Line 42, loading/completion tracking is keyed only by networkId:txHash, but Line 40 now re-runs on orderId changes. Same tx hash + different order id can display stale solver data without loading state.

Suggested fix
-  const currentKey = txHash && networkId ? `${networkId}:${txHash}` : null
+  const currentKey = txHash && networkId && orderId ? `${networkId}:${txHash}:${orderId}` : null

   useEffect(() => {
-    if (!networkId || !txHash || !currentKey) {
+    if (!networkId || !txHash || !orderId || !currentKey) {
       setSolver(undefined)
       setDoneFor(null)
       return
     }

     let cancelled = false

-    resolveSolverByTxHash(networkId, txHash, orderId || '')
+    resolveSolverByTxHash(networkId, txHash, orderId)

As per coding guidelines, "When changing interface: search all usages with rg, update every call, remove dead imports; refresh dependency arrays, test edge cases, ensure type safety."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/explorer/src/hooks/useTradeSolver.ts` around lines 14 - 40, The
loading/completion key currentKey must incorporate orderId to avoid showing
stale solver state when orderId changes; update the key creation (currentKey) to
include orderId (e.g., `${networkId}:${txHash}:${orderId || ''}`) so
resolveSolverByTxHash results and the setDoneFor marker are unique per order,
keep the same nulling behavior when any required value is missing, and ensure
the useEffect dependency array still includes networkId, txHash, currentKey, and
orderId so the effect re-runs correctly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@apps/explorer/src/hooks/useTradeSolver.ts`:
- Around line 14-40: The loading/completion key currentKey must incorporate
orderId to avoid showing stale solver state when orderId changes; update the key
creation (currentKey) to include orderId (e.g.,
`${networkId}:${txHash}:${orderId || ''}`) so resolveSolverByTxHash results and
the setDoneFor marker are unique per order, keep the same nulling behavior when
any required value is missing, and ensure the useEffect dependency array still
includes networkId, txHash, currentKey, and orderId so the effect re-runs
correctly.

In `@apps/explorer/src/test/hooks/useTradeSolver.test.tsx`:
- Around line 74-134: Add a regression test to useTradeSolver that verifies a
mismatch between the winner solution's orderId and the requested orderId yields
undefined: arrange mockedGetSolverCompetitionByTxHash to resolve to a
SolverCompetitionResponse whose winning solution has a different orderId than
the one passed to useTradeSolver (use mockSolverCompetitionResponse or construct
a response with auctionId and solutions where solution.orderId !== the test
orderId), mock mockedFetchSolversInfo as before, renderHook(() =>
useTradeSolver(<txHash>, <orderId>Mismatch)), wait for loading to finish, and
assert result.current.solver is undefined; reference useTradeSolver,
mockedGetSolverCompetitionByTxHash, mockSolverCompetitionResponse, and
mockedFetchSolversInfo to locate where to add the test.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b99416ef-00b2-4c79-967c-d40038cb5d60

📥 Commits

Reviewing files that changed from the base of the PR and between 306ee92 and 3bd40a7.

📒 Files selected for processing (5)
  • apps/explorer/src/components/orders/OrderDetails/FillsTableRow.tsx
  • apps/explorer/src/hooks/orderSolverShared.ts
  • apps/explorer/src/hooks/useTradeSolver.ts
  • apps/explorer/src/test/hooks/useOrderSolver.test.tsx
  • apps/explorer/src/test/hooks/useTradeSolver.test.tsx

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
apps/explorer/src/test/hooks/useTradeSolver.test.tsx (1)

136-160: Add a multi-order winner case to harden inclusion logic.

Current mismatch coverage is good, but it won’t catch regressions where code only checks the first order. Add a case where the requested order appears later in the winner’s orders array and assert solver resolution succeeds.

✅ Suggested test addition
+  it('resolves solver when requested orderId is present in winner orders (non-first position)', async () => {
+    const requestedOrderId = '0xrequestedOrder999'
+
+    mockedGetSolverCompetitionByTxHash.mockResolvedValueOnce({
+      auctionId: 1,
+      solutions: [
+        {
+          solver: 'projectblanc',
+          isWinner: true,
+          solverAddress: '0xsolver',
+          ranking: 1,
+          orders: [{ id: '0xotherOrder111' }, { id: requestedOrderId }],
+        } as unknown as NonNullable<SolverCompetitionResponse['solutions']>[0],
+      ],
+    } as SolverCompetitionResponse)
+    mockedFetchSolversInfo.mockResolvedValueOnce(MOCK_SOLVERS)
+
+    const { result } = renderHook(() => useTradeSolver('0xtx999', requestedOrderId))
+    await waitFor(() => expect(result.current.isLoading).toBe(false))
+
+    expect(result.current.solver).toEqual({
+      solverId: 'projectblanc',
+      displayName: 'Project Blanc',
+      image: 'https://example.com/blanc.png',
+    })
+  })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/explorer/src/test/hooks/useTradeSolver.test.tsx` around lines 136 - 160,
Add a new test in useTradeSolver.test.tsx that covers a multi-order winner: mock
mockedGetSolverCompetitionByTxHash to return a solution where the winning
solution (in the solutions array) has an orders array with multiple entries and
the requestedOrderId appears not in position 0 but later (e.g., orders: [{ id:
'other1' }, { id: requestedOrderId }, ...]); call renderHook(() =>
useTradeSolver(txHash, requestedOrderId)), wait for isLoading false, then assert
result.current.solver resolves to the expected solver object (not undefined) and
mockedFetchSolversInfo was called; this ensures the matching logic in
useTradeSolver iterates the orders array rather than only checking the first
order.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/explorer/src/test/hooks/useTradeSolver.test.tsx`:
- Around line 136-160: Add a new test in useTradeSolver.test.tsx that covers a
multi-order winner: mock mockedGetSolverCompetitionByTxHash to return a solution
where the winning solution (in the solutions array) has an orders array with
multiple entries and the requestedOrderId appears not in position 0 but later
(e.g., orders: [{ id: 'other1' }, { id: requestedOrderId }, ...]); call
renderHook(() => useTradeSolver(txHash, requestedOrderId)), wait for isLoading
false, then assert result.current.solver resolves to the expected solver object
(not undefined) and mockedFetchSolversInfo was called; this ensures the matching
logic in useTradeSolver iterates the orders array rather than only checking the
first order.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: d94b205a-8888-48e0-8952-a659325d8641

📥 Commits

Reviewing files that changed from the base of the PR and between 3bd40a7 and 51771e6.

📒 Files selected for processing (2)
  • apps/explorer/src/hooks/useTradeSolver.ts
  • apps/explorer/src/test/hooks/useTradeSolver.test.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/explorer/src/hooks/useTradeSolver.ts

Copy link
Copy Markdown
Contributor

@limitofzero limitofzero left a comment

Choose a reason for hiding this comment

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

works as expected:

Image

Copy link
Copy Markdown
Contributor

@fairlighteth fairlighteth left a comment

Choose a reason for hiding this comment

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

Looks good. One small nit:

One non-blocking test gap remains: apps/explorer/src/test/hooks/useTradeSolver.test.tsx:136 covers the mismatch case, but not the positive case where the requested order appears later in winner.orders[]. The code uses .find, so I don’t see a correctness issue, but that would harden the regression coverage.

@fairlighteth fairlighteth enabled auto-merge (squash) April 6, 2026 15:55
@fairlighteth fairlighteth merged commit cdbfea4 into develop Apr 6, 2026
14 of 15 checks passed
@fairlighteth fairlighteth deleted the fix/solver-winner-explorer branch April 6, 2026 16:00
@github-actions github-actions bot locked and limited conversation to collaborators Apr 6, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants