Short description of the new GoodWidget
Build the first packages/goodreserve-widget package in GoodWidget: a reserve swap widget backed by @goodsdks/good-reserve, using GoodWalletV2’s swap UX as the UI reference and GoodSDKs’ reserve demo as the behavior reference.
This widget should prove the GoodWidget framework can support a quote-driven swap flow, reserve-specific validation/error handling, and reusable widget packaging beyond the existing claim flows.
Target package: packages/goodreserve-widget
Network context: GoodDollar-related flows should target Celo (42220) and XDC (50).
Which repos and packages the AI should work with
Cross-repo references
GoodSDKs
packages/good-reserve/README.md
packages/good-reserve/
packages/react-hooks/README.md
apps/demo-reserve-swap/src/components/ReserveSwap.tsx
apps/demo-reserve-swap/src/components/useReserveSwapQuote.ts
apps/demo-reserve-swap/src/components/useReserveSwapTx.ts
apps/demo-reserve-swap/src/utils/errors.ts
GoodWalletV2
src/sections/Swap/SwapView.tsx
src/sections/Swap/swapStore.ts
src/sections/Swap/swapOverlayStore.ts
src/sections/Swap/components/AmountInputBox/
src/sections/Swap/components/AssetSelectBox/
src/sections/Swap/components/RouteBox/
src/sections/Swap/components/TokenInfoSlider/
src/sections/Swap/components/TokensDrawer/
src/sections/Swap/components/SwapDialog/ConfirmSwapDialog.tsx
src/sections/Swap/components/OutOfGasWarn/OutOfGasWarn.tsx
src/components/Form/RoundButton/RoundButton.tsx
Scope
- Create
packages/goodreserve-widget with the standard package scaffold.
- Add widget runtime files (
index.ts, widgetRuntimeContract.ts, integration.ts).
- Implement widget-local swap view, state, hooks, and reserve-specific UI.
- Wire the widget to
@goodsdks/good-reserve.
- Add Storybook coverage under
examples/storybook/src/stories/goodreserve-widget/.
- Add any widget-specific screenshots under the same widget story folder.
- Add verification coverage in
tests/demo/.
Non-goals
- No migration of GoodWalletV2’s LiFi swap engine.
- No unrelated
packages/ui refactors.
- No new wallet/provider abstraction layer.
Source-to-target mapping
- GoodWalletV2
SwapView → widget-local ReserveSwapView
- GoodWalletV2 swap state/overlay stores → widget-local reserve stores
- GoodSDKs reserve quote/tx hooks → widget-local reserve hooks
- GoodSDKs reserve error utilities → widget-local reserve error mapping
- Existing
@goodwidget/ui primitives should be reused where possible; only add new generic primitives if they are clearly reusable beyond this widget
UI implementation reference
There is an interactive demo on stitch:
https://stitch.withgoogle.com/preview/1645756043403511215?node-id=1d5c2d1b8fcc445f9a060ce226a5d495
And for exact colors, structure, spacing check the figma
https://www.figma.com/design/xsk5EiF6CvStA9mtdbA9OR/GoodWidget-Library?node-id=2311-2&t=3MMOUiTScwCmxTQp-1
Use GoodWalletV2 as the visual reference:
- amount input layout
- asset pair selection
- direction toggle (buy/sell)
- reserve stats / route summary area
- confirmation dialog
- warning/error presentation
- primary CTA states
Use GoodSDKs apps/demo-reserve-swap as the behavior reference for:
- SDK initialization
- quote loading/debounce
- transaction execution lifecycle
- reserve stats loading
- error classification and display
Main swap view reference:

Confirm swap drawer:

Swap success screen:

UI notes:
- Keep reserve-specific logic inside
packages/goodreserve-widget.
- Reuse existing
@goodwidget/ui primitives before creating new ones.
- Only move a new component into
packages/ui if it is generic and reusable.
- Storybook stories must follow the existing per-widget organization.
User flows, states and behaviours
Required states and flows
no_provider: no provider passed; swap UI blocked with connect prompt
unsupported_chain: provider is not on Celo Mainnet or XDC ; show switch-network state
sdk_initializing: widget is mounting SDK/runtime data
idle_buy: buy flow visible, empty input, CTA disabled
amount_editing: user input is changing and quote debounce is active
quote_loading: quote request in progress
quote_ready: valid quote returned and CTA enabled
quote_error: quote failed with user-readable error
insufficient_balance: input exceeds wallet balance and CTA is disabled
slippage_selection: slippage settings sheet/dialog is open and persisted
confirm_dialog: user reviews amount, price/slippage/fee summary before submit
swap_pending: tx submitted, interaction blocked
swap_success: success feedback shown and state reset/refreshed
swap_error: tx failed with mapped reserve-specific error
Functional expectations
- The widget must support reserve buy and sell directions.
- The widget must read wallet/provider state through the existing GoodWidget runtime path.
- The widget must validate supported chain, balances, and reserve warnings before execution.
- The widget must use deterministic Storybook-friendly mocks instead of requiring live network behavior in CI.
- Storybook should use the existing fixture patterns in
examples/storybook/src/fixtures/; reserve-specific SDK mocking should stay separate from wallet-provider fixtures.
Acceptance criteria
packages/goodreserve-widget exists with the expected scaffold.
GoodReserveWidget renders for connected, disconnected, and unsupported-chain states.
- Buy and sell flows both support quote loading, quote success, and quote error states.
- Confirmation, pending, success, and error transaction states are represented.
- Insufficient-balance and reserve-warning states are represented.
config and themeOverrides flow through the standard GoodWidget theming/runtime contract.
widgetRuntimeContract.ts and integration.ts accurately describe widget states, events, and dependencies.
- Storybook covers the required states under the widget-specific story folder.
- Workspace build/test/lint expectations are defined before implementation.
Verification commands
pnpm install
pnpm build
pnpm lint
pnpm storybook &
pnpm test:storybook
pnpm test:demo
If the SDK or cross-repo dependencies are unavailable, that must be reported as a blocker instead of worked around silently.
Human-reviewer checklist
Short description of the new GoodWidget
Build the first
packages/goodreserve-widgetpackage in GoodWidget: a reserve swap widget backed by@goodsdks/good-reserve, using GoodWalletV2’s swap UX as the UI reference and GoodSDKs’ reserve demo as the behavior reference.This widget should prove the GoodWidget framework can support a quote-driven swap flow, reserve-specific validation/error handling, and reusable widget packaging beyond the existing claim flows.
Target package:
packages/goodreserve-widgetNetwork context: GoodDollar-related flows should target Celo (
42220) and XDC (50).Which repos and packages the AI should work with
Cross-repo references
GoodSDKs
packages/good-reserve/README.mdpackages/good-reserve/packages/react-hooks/README.mdapps/demo-reserve-swap/src/components/ReserveSwap.tsxapps/demo-reserve-swap/src/components/useReserveSwapQuote.tsapps/demo-reserve-swap/src/components/useReserveSwapTx.tsapps/demo-reserve-swap/src/utils/errors.tsGoodWalletV2
src/sections/Swap/SwapView.tsxsrc/sections/Swap/swapStore.tssrc/sections/Swap/swapOverlayStore.tssrc/sections/Swap/components/AmountInputBox/src/sections/Swap/components/AssetSelectBox/src/sections/Swap/components/RouteBox/src/sections/Swap/components/TokenInfoSlider/src/sections/Swap/components/TokensDrawer/src/sections/Swap/components/SwapDialog/ConfirmSwapDialog.tsxsrc/sections/Swap/components/OutOfGasWarn/OutOfGasWarn.tsxsrc/components/Form/RoundButton/RoundButton.tsxScope
packages/goodreserve-widgetwith the standard package scaffold.index.ts,widgetRuntimeContract.ts,integration.ts).@goodsdks/good-reserve.examples/storybook/src/stories/goodreserve-widget/.tests/demo/.Non-goals
packages/uirefactors.Source-to-target mapping
SwapView→ widget-localReserveSwapView@goodwidget/uiprimitives should be reused where possible; only add new generic primitives if they are clearly reusable beyond this widgetUI implementation reference
There is an interactive demo on stitch:
https://stitch.withgoogle.com/preview/1645756043403511215?node-id=1d5c2d1b8fcc445f9a060ce226a5d495
And for exact colors, structure, spacing check the figma
https://www.figma.com/design/xsk5EiF6CvStA9mtdbA9OR/GoodWidget-Library?node-id=2311-2&t=3MMOUiTScwCmxTQp-1
Use GoodWalletV2 as the visual reference:
Use GoodSDKs
apps/demo-reserve-swapas the behavior reference for:Main swap view reference:

Confirm swap drawer:

Swap success screen:

UI notes:
packages/goodreserve-widget.@goodwidget/uiprimitives before creating new ones.packages/uiif it is generic and reusable.User flows, states and behaviours
Required states and flows
no_provider: no provider passed; swap UI blocked with connect promptunsupported_chain: provider is not on Celo Mainnet or XDC ; show switch-network statesdk_initializing: widget is mounting SDK/runtime dataidle_buy: buy flow visible, empty input, CTA disabledamount_editing: user input is changing and quote debounce is activequote_loading: quote request in progressquote_ready: valid quote returned and CTA enabledquote_error: quote failed with user-readable errorinsufficient_balance: input exceeds wallet balance and CTA is disabledslippage_selection: slippage settings sheet/dialog is open and persistedconfirm_dialog: user reviews amount, price/slippage/fee summary before submitswap_pending: tx submitted, interaction blockedswap_success: success feedback shown and state reset/refreshedswap_error: tx failed with mapped reserve-specific errorFunctional expectations
examples/storybook/src/fixtures/; reserve-specific SDK mocking should stay separate from wallet-provider fixtures.Acceptance criteria
packages/goodreserve-widgetexists with the expected scaffold.GoodReserveWidgetrenders for connected, disconnected, and unsupported-chain states.configandthemeOverridesflow through the standard GoodWidget theming/runtime contract.widgetRuntimeContract.tsandintegration.tsaccurately describe widget states, events, and dependencies.Verification commands
pnpm install pnpm build pnpm lint pnpm storybook & pnpm test:storybook pnpm test:demoIf the SDK or cross-repo dependencies are unavailable, that must be reported as a blocker instead of worked around silently.
Human-reviewer checklist
packages/uiunless explicitly justified.