feat(frontend): fix and harden order recovery from coordinator after reload - #228
Open
dykdee wants to merge 1 commit into
Open
feat(frontend): fix and harden order recovery from coordinator after reload#228dykdee wants to merge 1 commit into
dykdee wants to merge 1 commit into
Conversation
…reload
The frontend already attempted to recover pending/refundable swaps from
the coordinator on mount, but the request was silently broken: it sent
?eth=&stellar= query params while the coordinator's /api/orders/history
route only accepts a single `address` param (matched against either
side of the order). Every recovery request hit the address_required
400 path and fell back to local-only state, so recovery never actually
worked after a reload.
- Extract recovery logic into frontend/src/lib/orderRecovery.ts:
- fetchCoordinatorOrders() issues one correctly-shaped request per
connected address, tolerates one side failing, and only throws
(triggering the local-cache fallback) when every request fails.
- mergeTransactions() dedupes local and recovered orders by
hashlock / on-chain order id / tx hash (falling back to id),
letting the coordinator's authoritative record win on conflicts.
- mapCoordinatorOrderToTransaction()/isRealHash()/isRealTransaction()
moved out of the component so they're independently testable.
- Wire TransactionHistory.tsx to the fixed service.
- Add unit tests for mapping, dedup rules, per-address fetch fanout,
partial/total coordinator failure, and fake-hash filtering.
- Add component tests covering: recovery after reconnecting a wallet,
duplicate suppression between local and recovered orders, and
fallback to the local cache when the coordinator is unreachable.
Closes #415
|
@dykdee is attempting to deploy a commit to the karagoz's projects Team on Vercel. A member of the Team first needs to authorize it. |
Author
|
Hello repo maintainer, please can you approve the workflows quickly? the issue is fixed but you have not attended to the case. |
Author
|
Hi repo maintainer, please can you check that this issue is resolved and close it ASAP. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The frontend already attempted to recover pending/refundable swaps from the coordinator on mount (
TransactionHistory.tsx), but the request was silently broken: it queried/api/orders/history?eth=...&stellar=..., while the coordinator's route (coordinator/src/server/routes/orders.ts) only accepts a singleaddressquery param (matched against either side of the order viasrc_address OR dst_address). Every recovery request hit theaddress_required400 path, was swallowed by the catch block, and silently fell back to local-only state — so recovery never actually worked after a reload in production.This PR fixes that bug and hardens the recovery path per the issue's acceptance criteria.
Changes
frontend/src/lib/orderRecovery.ts(new) — small, testable service for order recovery:fetchCoordinatorOrders(apiBase, { ethAddress, stellarAddress })— issues one correctly-shaped request per connected address (since the coordinator only supports a singleaddressfilter), tolerates one side failing, and only throws (triggering the local-cache fallback) when every request fails.mergeTransactions(local, remote)— de-dupes local and recovered orders by hashlock / on-chain order id / tx hash (falling back toid), letting the coordinator's authoritative record win when both sides describe the same order.mapCoordinatorOrderToTransaction,isRealHash,isRealTransaction— moved out of the component so they're independently testable, withhashlocknow carried through the mapping.frontend/src/components/TransactionHistory.tsx— wired to the fixed service;refreshFromCoordinatornow uses the corrected request shape andmergeTransactionsinstead of a naiveid-onlyMap.onChainOrderId/htlcContractAddress/timelockUnixSecondsoff the mappedTransaction, which recovered orders now populate correctly since the request actually succeeds.Tests added
frontend/src/lib/orderRecovery.test.ts(17 tests): mapping coordinator orders → UI transactions, dedup rules across hashlock/order id/tx hash/id, per-address fetch fanout, partial vs. total coordinator failure, fake/demo hash filtering.frontend/src/components/TransactionHistory.test.tsx(4 tests): recovery renders after reconnecting a wallet, duplicate suppression between a locally-pending order and its coordinator-recovered counterpart, fallback to the local cache when the coordinator is unreachable, and no coordinator call when no wallet is connected.Verification
tsc --noEmit— cleanvite build— succeedsvitest run(frontend) — all new tests pass (21/21); pre-existing failures inApp.test.tsx(5,DeploymentSelfCheckmock issue) are unrelated and present onmasterprior to this change (verified viagit stash).vitest run(coordinator) —http-routes.test.ts(20 tests) passes unmodified; no backend changes were required.Closes #415