Skip to content

fix(bridging-widget): correct chain-aware bridge flow and history - #266

Draft
edehvictor wants to merge 9 commits into
GoodDollar:feat/gw243-bridging-widgetfrom
edehvictor:fix/bridging-correctness-257
Draft

edehvictor wants to merge 9 commits into
GoodDollar:feat/gw243-bridging-widgetfrom
edehvictor:fix/bridging-correctness-257

Conversation

@edehvictor

@edehvictor edehvictor commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Follow-up to #251 for issue #257. This draft PR makes the bridge flow chain-aware and addresses review feedback in the current branch.

  • Apply chain-specific G$ decimals to bridge amounts, fees, and history, including 2-decimal Fuse amounts.
  • Keep wallet network and selected source separate; refresh the quote before submission and invalidate preparation when the account or source changes.
  • Preserve an already-submitted transaction across account/source changes and keep pending History polling active after a failed refresh.
  • Improve loading, error, approval, and history-detail states. Keep Review actions reachable on short mobile screens.
  • Add route dropdowns, route-aware provider selection, clearer surface contrast, and a single bridge-status view with source, provider, and destination tracking links.
  • Expand Storybook fixtures and Playwright coverage, including a real-adapter submit flow with wallet/SDK boundaries mocked.

Issue #257 checklist

The checked items below describe implementation and local QA. The separate funded manual check is documented below.

  • Chain-specific decimals, including Fuse source and destination fixtures
  • Visible disconnected Bridge UI, wallet action, and placeholder balances
  • Independent source selection with network switch deferred until submission
  • Source/target dropdowns, route-aware provider selection, and readable chain names
  • Buffered provider fee displayed separately from protocol fee
  • Stale quotes blocked during loading; retry obtains a fresh quote
  • Account/source resets and in-flight preparation cancellation
  • History polling and status-failure regressions
  • Interactive submit flow through the real adapter with mocked wallet/SDK boundaries
  • Axelar/Fuse route and wrong-chain fixture corrections
  • Unified transaction progress with source, provider, and destination links

Verification

  • Bridging-widget changed-file lint passed locally. Direct builds of the core, embed, and bridging-widget packages passed after their dependencies were built.
  • Focused bridging-widget Playwright suite: 33/33 passed locally on 882534a with one worker and no retries.
  • The earlier scripted adapter recording exercises the real adapter with mocked wallet/SDK boundaries. It predates the latest visual changes and is not the requested manual wallet video.
  • Current desktop and 390 x 504 mobile fixture captures are shown below. They are automated screenshots, not live fee or delivery evidence.

Manual live-wallet check

  • Developer-recorded manual test (Loom): a separate funded MetaMask account uses the Storybook Injected Wallet flow, selects Celo to Ethereum via Axelar, reviews 50 G$, confirms, and reaches source submission. This is not the scripted Playwright recording.
  • Celo source transaction succeeded with 5.93686445 CELO sent as the bridge provider fee. Axelar's execution record reports executed. The Ethereum destination transaction succeeded and minted 49.95 G$ to the test account.
  • The Loom captured the browser tab only, so the separate MetaMask confirmation window is not visible. It ends while destination delivery is still in progress; the public transaction records establish its later success. This limitation is disclosed rather than presented as signing footage.

Reference versus result

These compare the lead's designs with the current 882534a UI captured in deterministic Storybook/Playwright fixtures. Routes, amounts, fees, and delivery states differ between reference and result. Fixture fees are mocked; these images do not establish live fees or pixel parity.

Screen Reference Current result Assessment
Main bridge Reference: main bridge screen Current: disconnected bridge Current: route ready The current UI has source/target dropdowns, route-aware provider selection, raised amount input, and a wallet gate. The two result images show different connection states; the reference uses a different route and amount.
Confirm Reference: confirm bridge Current: Review drawer Route, provider, estimated fees, and amount received are visible. The reference has a fuller From/To summary; the current fixture is Fuse to Celo, not the Celo to Ethereum reference route.
Transaction progress Reference: transaction progress Current: in-progress mobile footer Current: delivered status One status view keeps source, provider tracking, and destination explorer links together. The reference depicts a more detailed four-step journey; these fixtures show in-progress and delivered states, not a real transfer.

Mobile access checks: Review actions and progress tracking and background action at 390 x 504.

Verification status

  • Full-workspace pnpm build and pnpm lint remain uncertified in this sandbox: its pnpm 11/package-linking restriction blocks the repository's pnpm 9.15 entrypoints. Direct UI build reports an unrelated TS2322 in packages/ui/src/components-test/Select.tsx; direct workspace lint reports an unrelated unused governance import. Bridging-widget lint passes.
  • Upstream Playwright CI has not run on the latest head: playwright-demo was skipped and authorize-tests is waiting for maintainer authorization. Local Playwright success does not substitute for green CI.
  • The funded manual transfer and on-chain delivery are documented above. The Loom does not capture the wallet popup, so it is not a through-signing recording. The reference comparison screenshots remain fixture captures with mocked fee values.
  • The lead's dropdown, provider-selection, contrast, and combined-progress feedback is reflected in the current result captures above. Remaining reference differences are stated in the table; no visual parity is claimed. This PR remains draft with no review requested.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Submission preparation can outlive account changes, and failed history refreshes can prevent subsequent polling results from updating pending entries.

3 open issues
What changed in this PR

Updates the bridging widget from #251 to address #257’s chain-aware amounts, wallet selection, quote freshness, and history requirements.

Changes:

  • Uses chain-specific G$ decimals and displays buffered provider fees.
  • Separates source selection from the wallet network and refreshes quotes before submission.
  • Revises history polling and expands Storybook fixtures, flow checks, and screenshot capture.
File Description
tests/​widgets/​bridging-widget/​states.spec.ts Adds decimal and interactive-flow checks; improves screenshots.
packages/​bridging-widget/​tests/​historyTransactions.test.mjs Tests history pairing and status-failure handling.
packages/​bridging-widget/​src/​widgetRuntimeContract.ts Separates wallet and selected-source state.
packages/​bridging-widget/​src/​components/​shared.tsx Lists supported chains in protocol labels.
packages/​bridging-widget/​src/​components/​ReviewScreen.tsx Displays chain-aware amounts and charged fees.
packages/​bridging-widget/​src/​components/​HistoryTab.tsx Formats history amounts and preserves entries on refresh errors.
packages/​bridging-widget/​src/​components/​FeeBreakdown.tsx Uses destination decimals and buffered provider fees.
packages/​bridging-widget/​src/​components/​BridgingWidgetView.tsx Keeps bridge UI visible and adds wallet controls.
packages/​bridging-widget/​src/​components/​BridgeTab.tsx Adds source selection and clearer connection states.
packages/​bridging-widget/​src/​components/​BridgeHistoryDetailModal.tsx Formats history-detail amounts by source chain.
packages/​bridging-widget/​src/​components/​AmountEntry.tsx Updates balance formatting and disconnected display.
packages/​bridging-widget/​src/​BridgingWidget.tsx Supplies preview wallet identity overrides.
packages/​bridging-widget/​src/​adapter/​useBridgeSubmission.ts Loads fresh quotes and guards submission callbacks.
packages/​bridging-widget/​src/​adapter/​useBridgeQuote.ts Parses source decimals and hides stale quotes.
packages/​bridging-widget/​src/​adapter/​useBridgeHistory.ts Separates pending-status polling from history scans.
packages/​bridging-widget/​src/​adapter/​useBridgeConfig.ts Hides config from previous routes or accounts.
packages/​bridging-widget/​src/​adapter/​historyTransactions.ts Extracts history normalization and retains unresolved entries.
packages/​bridging-widget/​src/​adapter/​chains.ts Adds chain-decimal and native-fee helpers.
packages/​bridging-widget/​src/​adapter.ts Coordinates source selection, resets, and fresh-quote submission.
examples/​storybook/​src/​stories/​helpers/​bridgingWidgetStories.tsx Updates fixtures and adds decimal and interactive scenarios.
examples/​storybook/​src/​stories/​bridging-widget/​BridgingWidgetQA.stories.tsx Exposes the new QA stories.

Review effort: Balanced

Comment thread packages/bridging-widget/src/adapter.ts Outdated
setSelectedHistoryTransaction(null)
submission.reset()
}, [isReady])
if (submission.step === 'idle' || submission.step === 'failed') submission.reset()

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.

Thanks, fixed in f53387c. Account or source changes now invalidate in-flight submission preparation, and the captured operation/account is checked before doBridge(). Once submission has started, the transaction progress is preserved. Added regressions for account changes during the switch, source changes during the fresh quote, and account changes after submission begins.

active = false
clearInterval(intervalId)
}
}, [sdk, address, state.transactions])

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.

Thanks, fixed in f53387c. Pending-status polling now follows each history scan's request identity, so a failed refresh cannot leave later status updates discarded. Added a regression that fails a refresh while a transfer is pending and then verifies that delivery still updates.

Comment on lines +275 to +276
test('BridgingWidget completes the interactive route-to-submit flow', async ({ page }) => {
await gotoStory(page, 'interactive-submit')

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.

Agreed. I kept the presentation test and added a real-adapter Storybook fixture plus Playwright flow in f53387c, mocking only the wallet/SDK boundaries. It asserts confirmation switches to the selected source, obtains a fresh quote, and passes that quote to doBridge(). The focused bridge suite passed 27/27 locally without retries; the committed recording is scripted, not a real signed transfer.

@pheobeayo

Copy link
Copy Markdown

@edehvictor A review can only be done when the following conditions are satisfied:

  • You have tested with proof. (some proof/evidence, a video is usually the easiest to verify manual testing)
  • the UI/UX was compared against the reference.
  • Automated QA passes.
  • UI/UX related PRs include reference-vs-result screenshots + happy-path video.
  • Known limitations or untested areas are stated.

@edehvictor

Copy link
Copy Markdown
Collaborator Author

@pheobeayo, thank you. I'm still working on it. When I'm done. I'll let you know

@L03TJ3
L03TJ3 marked this pull request as draft October 23, 2026 05:45
@L03TJ3

L03TJ3 commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

@edehvictor @pheobeayo lets try to keep hygiene around the stages of how we work on bounties.
what I think works is:

  • Initial pull-request always opened as draft
  • await at least copilot reviews and follow up on them with questions, fixes or counter-points
  • We will going forward have a 'bounty-lead' and that is the one assigned to the [Feature] issue. Contributor should wait before claiming 'ready for review'. like @pheobeayo shared, there are some things that a contributor needs to confirm and take care off.
  • in the middle review can be requested, but it should be a focused review request. things you are unsure about, things that might have 3 solutions and you need to pick one. or just a larger task and you want to make sure that you are on track with the bounty.

Only when the initial checks are met, confirmed by bounty-lead, should turn this into a ready for review PR and the group of reviewers can be assigned.

@L03TJ3

L03TJ3 commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

@edehvictor per request, below the related design references.
while we try to follow it, it should be within the boundaries of the existing design system.
Likely there are things that can be looked at for what we have in the good-reserve flow when it comes to swapping UX. we also have a for transaction progress the component Stepper: https://github.com/GoodDollar/GoodWidget/blob/main/packages/ui/src/components/Stepper.tsx

you can see in other widgets how its used and applied.

Main bridge screen:

image

Notes:

  • It should be aligned for at least input fields using the design system and presentation as is used for GoodReserve Widget
  • Screen reference shows only a bridge fee. actuality:
    • There is a protocol fee, charged in G$’s. taken from your send amount. limits should be read from contract
    • There is bridge provider fee, this is based on the API endpoint and is charged in native tokens
  • The bridge layerzero should not say ‘multi-chain’, it should show all available chains for the given provider, like we do for the axelar bridge
  • The tab ‘activity’ should be named ‘history’

Confirm transaction screen:

image

Notes:

  • No estimated time
  • There is a protocol fee, charged in G$’s. taken from your send amount. limits should be read from contract
  • There is bridge provider fee, this is based on the API endpoint and is charged in native tokens

Transaction confirmed:

image

Notes:

  • Should be either rendered in drawer, or at least as overlay/modal over the main widget
  • It should use the existing stepper and visualization as is used for ai-credits-widget and governance widget (Stepper from packages/ui)
  • pending transactions should show up in the history tab and retrigger this modal when interacted with
  • Icon should just be a loader/circular icon, no need for custom icon

edehvictor commented Oct 24, 2026 •

Copy link
Copy Markdown
Collaborator Author

Update on draft PR #266: pushed f53387c (the three Copilot fixes and regression coverage) and 23e7f7f (Review actions reachable on short mobile screens). I replied on each Copilot thread with the specific fix and test.

Local verification: bridging-widget lint passed; focused Playwright suite passed 27/27, one worker, no retries. Evidence: scripted real-adapter happy-path recording, result screenshot, and 390 x 504 Review-footer screenshot. The mobile drawer was also manually checked for scrolling.

The recording uses mocked wallet/SDK boundaries; it is not a signed live transfer. Live wallet fees/delivery and a reference-versus-result design sign-off remain open. Full-workspace build/lint are not certified because of unrelated existing errors, detailed in the updated PR description. Current CI has a waiting test authorization and a skipped Playwright job. I'm keeping this PR draft, as requested, and am not requesting review.

edehvictor commented Oct 24, 2026 •

Copy link
Copy Markdown
Collaborator Author

@pheobeayo @L03TJ3 I compared Lewis's three references with the current result while keeping #266 draft. The #257 correctness flow is verified locally (27/27 focused Playwright tests; bridging-widget lint passes), but I do not want to claim visual parity yet.

Screen Reference Current result Difference
Main / disconnected Reference: main and disconnected Current: disconnected bridge Functional wallet gate and separate fees are present; chain/provider and amount-input presentation differ.
Confirm Reference: confirm bridge Current: Review drawer Fees/route are shown, but there is no equivalent full From/To summary. #257 lists explicit From/To rows as a follow-up, while parent #243 includes them.
Transaction progress Reference: transaction progress Current: submission result / Current: History detail Both use the shared Stepper, but the current states do not present the reference's full destination journey in one view.

Could you confirm whether these remaining design/feature differences belong in this #257 follow-up, the parent #251 feature work, or a separate issue? I'll keep #266 draft and avoid broad UI changes until you confirm scope. The scripted happy-path video mocks wallet/SDK boundaries; no funded transfer was made.

edehvictor commented Oct 24, 2026 •

Copy link
Copy Markdown
Collaborator Author

@pheobeayo, kindly review

@pheobeayo

pheobeayo commented Oct 25, 2026 •

Copy link
Copy Markdown

@edehvictor Thanks for the thorough update and for closing out the Copilot threads. Before this can go to a review:

  • Automated QA: CI hasn’t run yet (authorize-tests is pending, Playwright skipped). We need a green CI run, not just local results.
  • Manual proof: The video is a scripted run with mocked wallet/SDK. Please add a short manual happy-path recording with a real connected wallet (testnet or a small amount is fine), at least through Review → Confirm → signing.
  • History decimals bug: HistoryTab.tsx and BridgeHistoryDetailModal.tsx format transaction. amount with source-chain decimals. But SDK history amounts come from the event’s normalizedAmount, which is always 18 decimals. ---Fuse/Ethereum-sourced entries would show ~10¹⁶× inflated. Please format history with 18 decimals and update the fixtures (G$Fuse(...) in history stories) to match what the SDK actually returns.
  • Reference comparison: Please embed the reference-vs-result screenshots inline. On the scope question (From/To rows, full-journey progress view, input styling matching GoodReserve).

@pheobeayo

Copy link
Copy Markdown

@edehvictor Thanks — 42f6243 fixes the history decimals correctly. Formatting at 18 decimals matches the SDK’s normalizedAmount, and the fixture and test updates look good. I ran the unit tests and lint locally on the new head; both pass.

  • Still needed before final review:

  • CI green on the latest commit. Playwright hasn’t run in CI yet.

  • A manual happy-path video with a real connected wallet (testnet or a small amount), at least through Review → Confirm → wallet signature. The current recording mocks the wallet/SDK.

  • Reference-vs-result screenshots shown inline in the PR description, not just linked.

  • Minor, optional: the route-limit fixtures still use G$Fuse(...), but the SDK documents limits as normalized 18-decimal values. They aren’t displayed, so this is just for consistency.

edehvictor commented Oct 26, 2026 •

Copy link
Copy Markdown
Collaborator Author

@pheobeayo Thanks for the review. I’ve added the three reference/result image pairs directly to the PR description and kept the remaining visual differences explicit.

The latest local bridge Playwright run passed 27/27 with one worker and no retries, but the external-fork Playwright check has not run in CI. Could you authorize or trigger that workflow (or point me to whoever can)?

I also fixed the optional route-limit fixture inconsistency in 4873552: both Storybook fixtures now use the SDK’s normalized 18-decimal limits, while token balances remain chain-specific. The commit is pushed; changed-file lint and the focused bridge Playwright suite passed locally (27/27, one worker, no retries) after this fix.

For the requested real-wallet recording through Review → Confirm → wallet signing, the current widget routes are configured for mainnet. Could you confirm a supported testnet setup, or provide a small test allowance for G$ and source-chain gas so I can record the flow safely with a separate test account? I will review and sign the wallet request myself. The existing scripted video uses mocked wallet/SDK boundaries and is not a live transfer.

I’ll keep the PR draft until CI and the manual evidence are ready, then ask for your go-ahead before marking it ready for review.

@pheobeayo

Copy link
Copy Markdown

@edehvictor Thanks — the limit fixtures are now correctly normalized, and the Ethereum RPC fix with its explanatory comment makes sense. I ran the unit tests (5/5) and bridging-widget lint on 4873552; both pass.

One question on 8d8f242: removing the revert rule fixes the misleading message for read-call reverts, but it also drops it for actual doBridge reverts, which now show only “Bridge transaction failed.” Was that intended, or should the revert hint stay for the submission path only?

@L03TJ3 is this good enough for review now?

Copy link
Copy Markdown
Collaborator Author

@pheobeayo Thanks for catching that. Dropping the hint for an actual doBridge revert was not intended. I pushed a4c0681: the on-chain revert hint now applies only after doBridge starts; a failed fresh quote gets a preparation error instead. Added regression cases for both paths. The two error-mapper unit tests, changed-file lint, and focused bridging-widget Playwright suite (29/29, one worker, no retries) pass locally. Keeping the PR draft while @L03TJ3 considers review readiness.

@L03TJ3

L03TJ3 commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

@edehvictor we requested a happy-path video alongside automated playwright tests screenshots.
Can you confirm that the video you posted is not you testing it, but an playwright output?
If you confirm, can you post a video from yourself testing it

The request is: test it yourself. manually. make a video.
playwright is good for first pass reviews, regression reviews.

but all of this will end up being used by real users. so we need a critical review by the developer to make sure things work. not based only on tests.

@edehvictor

Copy link
Copy Markdown
Collaborator Author

Hi @L03TJ3,
Yes, you're right. The video I posted is Playwright output using mocked wallet and SDK boundaries, not a manual test. I can record a manual happy-path run, but the widget is currently configured for mainnet. Could you provide a small test amount of G$ and the required source-chain gas, or point me to a supported testnet setup? I’ll use a separate test wallet and post the recording once I can run it safely.

@L03TJ3

L03TJ3 commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

@edehvictor
But before this is ready for review, I am going to request some more critical assesment and alignment with the provided design references as what is currently pushed is not aligned and might even surface bugs

  1. can you confirm where the screenshot references protocol fee comes from? is this hardcoded for screenshot purposes, or is this real tested output?
  2. similar to provider fee, seems not accurate. again, is this mocked only or is this a real live test output?
  3. route and provider, does not make sense to show like this.
  4. what happened with provider selection?
  5. what happend with the requested dropdowns for source/target chain/network?
  6. The input field and in general the containers/cards lack contrast. please review the explanation in Card.tsx how we apply surface > raised > elevated. you can compare it visually against the goodreserve and see how this is applied. code-wise, likely ai-credits is the more recent example of how surface > raised is used.
  7. transaction progress and your comment: yes its expected to have a single view for the progression, included links to the relevant explorers. layerzero/axelar have their pages to track status of transactions too.

edehvictor commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator Author
test @L03TJ3 I completed the requested **developer-run manual wallet test**, separate from the earlier Playwright recording. Here is the [Loom recording](https://www.loom.com/share/94776e052d0548f0b68891098fc6b154): I used a funded MetaMask test account for a 50 G$ Celo -> Ethereum bridge via Axelar, went through Review and Confirm, and observed the source submission.

The recording captured the browser tab only, so it does not show the separate MetaMask confirmation popup, and it ends while delivery is still in progress. I don't want to imply otherwise. The public records confirm the actual signed transfer and later delivery: Celo source transaction succeeded, Axelar reports executed, and the Ethereum destination transaction succeeded with 49.95 G$ delivered to the test account. I updated the PR description to separate this live evidence from the mocked fixture screenshots.

Could you confirm whether this evidence meets the manual-test requirement despite the popup not appearing in the tab recording? The PR remains draft. Upstream Playwright CI is still skipped on the latest head, so maintainer authorization/a green CI run is also outstanding.

This branch is waiting to be deployed

1 waiting deployment
external — 1a97cb3e Waiting Oct 27, 2026 by edehvictor via authorize-preview #492
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.

[GoodBounty] Fix per-chain decimals, wallet-gate, and chain-selection bugs in Bridging GoodWidget

4 participants