You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Build the first packages/goodreserve-widget package in GoodWidget: a reserve swap UI that uses @goodsdks/good-reserve as the protocol/runtime base, GoodWalletV2's swap flow as the UI and interaction reference, and GoodSDKs apps/demo-reserve-swap as the SDK behavior reference.
Why this matters
The GoodReserve Widget is the first swap-oriented widget in GoodWidget, proving that the framework can power protocol-backed financial interactions beyond simple claim flows. It establishes a reusable execution contract for quote-driven transaction flows, reserve-specific error handling, and buy/sell direction UIs. Completing this widget creates the second SDK-backed widget pattern alongside the Citizen Claim Widget, making the framework's multi-widget capability concrete and demonstrable.
Bounty tier
Legendary
Bounty type
Widget feature / SDK integration
Target package
packages/goodreserve-widget
Required base branch
copilot/sub-pr-6 (current GoodWidget branch with agent-ready bounty setup)
Agent execution instructions
Required references
The agent and contributor must inspect these before implementation:
GoodWidget (this repo):
AGENTS.md — always-read operating guide
ARCHITECTURE.md — package boundaries and data flow
⚠️If any cross-repo reference is unavailable or the SDK API surface has not been released yet, stop and comment on this issue before writing any code.
Missing references
The following files are in external repositories and could not be read during spec authoring. Their content must be verified before implementation begins:
Whether useGoodReserve or useReserveSwapQuote-style hooks exist and are exported
apps/demo-reserve-swap/src/components/*.ts
GoodSDKs
Full orchestration pattern, quote debounce, balance loading, error boundary behavior
GoodWalletV2 swap components
GoodWalletV2
Exact layout structure, CSS class names, visual hierarchy, style values to map into Tamagui tokens
SDK release status
GoodSDKs
Whether @goodsdks/good-reserve and @goodsdks/react-hooks are published on npm or branch-only
Package scaffold decision
packages/goodreserve-widget does not exist yet.
This bounty includes package scaffolding. The implementer must create the package structure before any UI work begins. The scaffolding must follow the exact pattern of packages/citizen-claim-widget:
package.json with name @goodwidget/goodreserve-widget
The package must depend on @goodwidget/core and @goodwidget/ui (workspace), and declare @goodsdks/good-reserve (and optionally @goodsdks/react-hooks) as dependencies. It must be added to pnpm-workspace.yaml and the turbo.json pipeline.
Wire into useReserveSwapQuote and useReserveSwapTx hooks
Follow demo pattern for SDK init, chain check, balance loading
Primitive extraction plan
Already in packages/ui — reuse directly, do not recreate
Existing primitive
Used for
Button
Primary swap action button, direction toggle, slippage confirm
TokenInput (components-test)
Base for ReserveAmountInput; extend with reserve-specific balance/max
Drawer
Token selector bottom sheet
Dialog
Swap confirmation modal
Card
Reserve route stats card
TokenAmount
Quote amount display
Spinner
Loading overlays
Alert (components-test)
Gas warning, reserve warning, error states
Text, Heading, Separator
Layout and typography
Toast
Success/error notification after tx completes
TransactionButton (components-test)
Final swap execute button (pending/success/error states)
New primitives that belong in packages/ui — generic, reusable beyond this widget
Only add to packages/ui if the component has no reserve-specific logic and is clearly reusable by other widgets:
Candidate
Justification
Decision
DirectionToggle (buy ↔ sell flip button)
Generic buy/sell toggle with no SDK coupling; could be reused in any swap widget
Add to packages/ui if the implementer confirms it has zero domain logic
SlippageInput (percent input with presets)
Generic slippage control; could appear in any DeFi widget
Add to packages/ui only if no reserve-specific preset values leak into it
⚠️ When in doubt about packages/ui candidacy, keep the component in packages/goodreserve-widget. Adding to packages/ui expands the public override surface. Ask first.
Components local to packages/goodreserve-widget — keep here, do not move to packages/ui
GoodReserveWidget — root widget component with provider boundary
ReserveSwapView — main screen orchestration
ReserveAmountInput — amount input with reserve-specific balance display, token label, and MAX
ReserveAssetPair — from/to asset pair display + direction selector
ReserveRouteStats — reserve price, spread, and liquidity stats card
Initialize with provider + chainId inside widget hooks
sdk.getReserveStats() or equivalent
Load reserve price, spread, liquidity on mount and on refresh
sdk.getQuote(direction, fromAmount, token) or equivalent
Debounced quote loading on amount/direction change
sdk.buy(params) / sdk.sell(params)
Execute swap transaction
sdk.getBalance(address, token)
Load token balances for display and validation
sdk.getSupportedTokens() or reserve pair constants
Populate the asset selector with valid reserve pairs
Error types from errors.ts
Classify and display reserve-specific errors
Hook vs direct SDK
Preferred: Use useGoodReserve from @goodsdks/react-hooks if the hook provides quote, balance, buy/sell, and reserve stats in one stable API. If the hooks package does not yet provide these capabilities, use the GoodReserveSDK class directly via useReserveSwapQuote.ts and useReserveSwapTx.ts (following the demo pattern).
The choice between hooks and direct SDK must be confirmed by inspecting packages/react-hooks/README.md in the GoodSDKs repo before implementation.
Supported chains
Verify against packages/good-reserve/README.md. Expected: Celo mainnet (42220) and/or Fuse (122). The widget must check chainId at runtime and render the "unsupported chain" state for any chain not in the supported list.
Slippage
Default to the SDK's recommended slippage value (inspect demo-reserve-swap). Expose a slippage setting sheet that allows the user to choose from preset values (0.1%, 0.5%, 1%) or enter a custom value. Never hardcode slippage without checking the SDK's defaults.
Package version and dependency check
Required check before implementation:
Confirm @goodsdks/good-reserve is published on npm and at what version.
Confirm @goodsdks/react-hooks is published and whether it exports reserve-specific hooks.
If either package is branch-only or unpublished, report the version/capability gap as a blocker before working around it.
Confirm the mock/fixture pattern used in apps/demo-reserve-swap is usable for Storybook without requiring a live network connection.
Scope
Must change:
Create packages/goodreserve-widget/ with full package scaffold (package.json, tsconfig, tsup, src/index.ts)
Debounce timer starts; no quote request until debounce clears
Play function test or Storybook AmountEditing
balance_loaded
SDK returns balance for connected address
Show formatted balance next to amount input; enable MAX button
Storybook controls/args
quote_loading
Debounce clears after amount change
Show spinner/skeleton in quote area; swap button disabled
Storybook QuoteLoading story
quote_ready
SDK returns a valid quote
Show output amount, price impact, and estimated fee; swap button enabled
Storybook QuoteReady story
quote_error
SDK returns quote error
Show inline error message; swap button disabled
Storybook QuoteError story
insufficient_balance
Input amount > wallet balance
Show "Insufficient balance" message; swap button disabled
Storybook InsufficientBalance story
low_liquidity_warning
SDK signals reserve stress or high price impact
Show warning banner above swap button; button still enabled with confirmation step
Storybook LowLiquidityWarning story
slippage_selection
User opens slippage settings
Show slippage sheet with presets and custom input; selection persists
Play function test
confirm_dialog
User taps swap button with valid quote
Show confirmation dialog: output amount, slippage, estimated fee, reserve address
Play function test
swap_pending
User confirms in dialog; tx submitted
Show spinner on button; disable all inputs; show pending state
Storybook SwapPending story
swap_success
Tx confirmed onchain
Show success message or Toast; reset input to idle state; update balance
Storybook SwapSuccess story
swap_error
Tx reverted or SDK error
Show user-readable error mapped through errors.ts; allow retry
Storybook SwapError story
refresh_quote
Quote expired or user taps refresh
Re-trigger quote loading from idle_buy/idle_sell state
Play function test
refresh_reserve_context
User taps refresh on reserve stats
Re-load reserve stats from SDK; show stats loading briefly
Play function test
SDK, dependency, and cross-repo checks
Required SDK/package assumptions (must be verified before implementation):
@goodsdks/good-reserve — reserve swap SDK. Assumed version: latest published on main or a designated branch. Must confirm: is it on npm? Which version?
@goodsdks/react-hooks — React hook layer. Must confirm: does it export useGoodReserve, useReserveSwapQuote, or equivalent hooks?
wagmi / viem — SDK peer deps may require these. Confirm whether GoodWidget's existing wagmi integration (packages/core/src/wagmi.ts) satisfies the SDK requirements or whether new peer deps are needed.
If any command cannot run (e.g., SDK not yet published), explain exactly what was run instead and what was verified manually.
Pull request requirements
The PR description must include:
Reference to this issue number
Summary of changes made
Source-to-target mapping (Table 1 + Table 2 from above)
Primitive extraction decisions made (what went to packages/ui vs widget-local)
SDK dependency version used and how it was sourced (npm published, local path, etc.)
Acceptance criteria checklist (mirrored from this issue)
Commands run and their output or pass/fail summary
Storybook links, screenshots, or recordings for all required stories
Any intentional deviations from this spec with justification
Known risks and follow-up items
Known risks and follow-ups
SDK release gap:@goodsdks/good-reserve may not be published on npm at the time of implementation. If the package is branch-only, the implementer must report this as a blocker rather than using a path dependency without approval.
Storybook mock depth: The demo-reserve-swap uses live Celo RPC. Mocking the SDK for Storybook requires stub implementations of quote, balance, and stats methods. The implementer must produce deterministic stubs; do not skip mocking and rely on live network in CI.
TransactionButton maturity:packages/ui/src/components-test/TransactionButton.tsx exists but may not cover all swap tx states. The implementer should assess whether it can be used directly or whether a widget-local ReserveSwapButton is needed.
GoodWalletV2 CSS → Tamagui translation: GoodWalletV2 uses CSS modules; the implementer must translate layout, spacing, and color values into Tamagui token references and semantic theme keys, not into inline pixel values.
Slippage default: If the GoodReserve SDK has a recommended default slippage, use it. Do not pick an arbitrary default without checking.
Follow-up bounty candidates: token selector with search/filter, reserve stats refresh timer, multi-widget theming demo, and Expo/React Native compatibility.
Human reviewer checklist
I reviewed the issue before reviewing the diff.
I checked whether the PR solves the stated goal, not just a related problem.
I checked scope boundaries and unrelated file changes.
I checked architecture constraints (SDK in widget, not in packages/ui; no bypass of provider model).
I reviewed Storybook screenshots or recordings for all required stories.
I checked verification command output or reproduced the checks.
I left concrete review comments or fixed blockers directly.
Spec readiness check
Required references are listed and accessible (GoodWidget files verified; cross-repo files listed and flagged for pre-implementation inspection).
Scope and non-goals are clear.
Source-to-target mapping is complete (both GoodWalletV2 → widget and demo-reserve-swap → widget).
SDK/version assumptions are checked — implementer must verify before starting.
Acceptance criteria are testable.
Storybook/Playwright expectations are clear.
Verification commands are listed.
This issue is ready for Copilot execution — pending SDK version check and cross-repo reference access confirmation.
Human summary
Build the first
packages/goodreserve-widgetpackage in GoodWidget: a reserve swap UI that uses@goodsdks/good-reserveas the protocol/runtime base, GoodWalletV2's swap flow as the UI and interaction reference, and GoodSDKsapps/demo-reserve-swapas the SDK behavior reference.Why this matters
The GoodReserve Widget is the first swap-oriented widget in GoodWidget, proving that the framework can power protocol-backed financial interactions beyond simple claim flows. It establishes a reusable execution contract for quote-driven transaction flows, reserve-specific error handling, and buy/sell direction UIs. Completing this widget creates the second SDK-backed widget pattern alongside the Citizen Claim Widget, making the framework's multi-widget capability concrete and demonstrable.
Bounty tier
Legendary
Bounty type
Widget feature / SDK integration
Target package
packages/goodreserve-widgetRequired base branch
copilot/sub-pr-6(current GoodWidget branch with agent-ready bounty setup)Agent execution instructions
Required references
The agent and contributor must inspect these before implementation:
GoodWidget (this repo):
AGENTS.md— always-read operating guideARCHITECTURE.md— package boundaries and data flowdocs/demo-environment.md— Storybook, Playwright, stories, fixturesdocs/architecture/theming-contract.md— Tamagui config, tokens, themes, naming rulespackages/ui/src/components/— current production-aligned UI primitivespackages/ui/src/components-test/— transitional primitives includingTokenInput,TransactionButton,Alert,Spinnerpackages/ui/src/createComponent.ts— named component + manifest registration wrapperpackages/ui/src/manifest.ts— runtime theme manifestpackages/ui/src/presets.ts— GoodWalletV2 token/theme presetpackages/citizen-claim-widget/src/widgetRuntimeContract.ts— SDK-backed widget contract patternpackages/citizen-claim-widget/src/integration.ts— SDK integration descriptor patternpackages/core/src/hooks.ts—useWallet(),useHost(),useGoodWidget()packages/core/src/types.ts—WalletState, provider propsexamples/storybook/src/stories/— existing story structure and fixture patternsexamples/storybook/src/fixtures/mockEip1193.ts— mock EIP-1193 providerGoodSDKs repo (cross-repo, must be accessed before implementation):
packages/good-reserve/README.md— GoodReserve SDK overview, public API surface, supported chainspackages/good-reserve/— SDK source:GoodReserveSDKclass, reserve stats, quote, buy/sellpackages/react-hooks/README.md— React hooks layer for GoodSDKsapps/demo-reserve-swap/src/components/ReserveSwap.tsx— full orchestration referenceapps/demo-reserve-swap/src/components/useReserveSwapQuote.ts— quote hook behaviorapps/demo-reserve-swap/src/components/useReserveSwapTx.ts— transaction execution hook behaviorapps/demo-reserve-swap/src/utils/errors.ts— reserve error classification and displayGoodWalletV2 repo (cross-repo, UI/UX reference, must be accessed before implementation):
src/sections/Swap/SwapView.tsx— main swap screen layout and orchestrationsrc/sections/Swap/swapStore.ts— swap state machinesrc/sections/Swap/swapOverlayStore.ts— overlay/modal state (slippage, token selector)src/sections/Swap/lifiUtils.ts— LiFi quote/route utilities (reference for SDK integration pattern, not for migration)src/app/[locale]/@home/(home)/(bottomsheet)/swap/page.tsx— swap entry point and routesrc/sections/Home/components/WalletSection.tsx— balance/wallet headersrc/sections/Swap/components/AmountInputBox/AmountInputBox.tsx— amount input UIsrc/sections/Swap/components/AmountInputBox/AmountInputBox.module.css— amount input stylessrc/sections/Swap/components/AssetSelectBox/AssetSelectBox.tsx— asset selector UIsrc/sections/Swap/components/AssetSelectBox/AssetSelectBox.module.csssrc/sections/Swap/components/RouteSlider/RouteSlider.tsx— route display slidersrc/sections/Swap/components/RouteSlider/RouteSlider.module.csssrc/sections/Swap/components/RouteBox/RouteBox.tsx— route stats boxsrc/sections/Swap/components/RouteBox/RouteBox.module.csssrc/sections/Swap/components/TokenInfoSlider/TokenInfoSlider.tsx— token info panelsrc/sections/Swap/components/TokensDrawer/TokensDrawer.tsx— token selector drawersrc/sections/Swap/components/SwapDialog/ConfirmSwapDialog.tsx— confirmation dialogsrc/sections/Swap/components/SwapDialog/swapDialogStore.ts— dialog statesrc/sections/Swap/components/OutOfGasWarn/OutOfGasWarn.tsx— gas warningsrc/components/Form/RoundButton/RoundButton.tsx— round action buttonMissing references
The following files are in external repositories and could not be read during spec authoring. Their content must be verified before implementation begins:
packages/good-reserve/GoodReserveSDKclass,useGoodReservehook, quote/buy/sell method signatures, supported chains, slippage parameterspackages/react-hooks/README.mduseGoodReserveoruseReserveSwapQuote-style hooks exist and are exportedapps/demo-reserve-swap/src/components/*.ts@goodsdks/good-reserveand@goodsdks/react-hooksare published on npm or branch-onlyPackage scaffold decision
packages/goodreserve-widgetdoes not exist yet.This bounty includes package scaffolding. The implementer must create the package structure before any UI work begins. The scaffolding must follow the exact pattern of
packages/citizen-claim-widget:package.jsonwith name@goodwidget/goodreserve-widgettsconfig.jsonandtsconfig.build.jsontsup.config.tssrc/index.ts(public exports)src/widgetRuntimeContract.ts(state/action/props types)src/integration.ts(integration descriptor)README.mdThe package must depend on
@goodwidget/coreand@goodwidget/ui(workspace), and declare@goodsdks/good-reserve(and optionally@goodsdks/react-hooks) as dependencies. It must be added topnpm-workspace.yamland theturbo.jsonpipeline.Source-to-target mapping
Table 1 — GoodWalletV2 swap UI → GoodReserve Widget sections
SwapView.tsxReserveSwapViewinpackages/goodreserve-widget/src/ReserveSwapView.tsxswapStore.ts(state machine)reserveSwapStore.tsinpackages/goodreserve-widget/src/swapOverlayStore.ts(overlays)reserveOverlayStore.tsinpackages/goodreserve-widget/src/lifiUtils.ts(quote/route)packages/goodreserve-widget/src/utils/reserveUtils.tsuseReserveSwapQuote.tspattern, not from LiFiAmountInputBox.tsxReserveAmountInputinpackages/goodreserve-widget/src/components/TokenInputfrom@goodwidget/uiAssetSelectBox.tsxReserveAssetPairinpackages/goodreserve-widget/src/components/Selectfrom@goodwidget/uiRouteSlider.tsxRouteBox.tsxReserveRouteStatsinpackages/goodreserve-widget/src/components/Cardfrom@goodwidget/uiTokenInfoSlider.tsxReserveTokenInfoinpackages/goodreserve-widget/src/components/TokensDrawer.tsxReserveAssetPairusingDrawerfrom@goodwidget/uiDrawerConfirmSwapDialog.tsx+swapDialogStore.tsReserveConfirmDialoginpackages/goodreserve-widget/src/components/Dialogfrom@goodwidget/uiOutOfGasWarn.tsxReserveGasWarninpackages/goodreserve-widget/src/components/Alertfrom@goodwidget/ui/components-testRoundButton.tsxButtonfrom@goodwidget/uiWalletSection.tsx(balance header)useWallet()from@goodwidget/coreswap/page.tsx(entry + route)GoodReserveWidgetroot inpackages/goodreserve-widget/src/GoodReserveWidget.tsxTable 2 — GoodSDKs demo-reserve-swap → GoodReserve Widget behavior
ReserveSwap.tsx(orchestration)ReserveSwapView.tsxin widgetuseReserveSwapQuote.ts(quote hook)useReserveSwapQuote.tsinpackages/goodreserve-widget/src/hooks/useReserveSwapTx.ts(tx hook)useReserveSwapTx.tsinpackages/goodreserve-widget/src/hooks/errors.ts(error mapping)packages/goodreserve-widget/src/utils/errors.tsGoodReserveSDKoruseGoodReserveuseReserveSwapQuoteanduseReserveSwapTxhooksPrimitive extraction plan
Already in
packages/ui— reuse directly, do not recreateButtonTokenInput(components-test)ReserveAmountInput; extend with reserve-specific balance/maxDrawerDialogCardTokenAmountSpinnerAlert(components-test)Text,Heading,SeparatorToastTransactionButton(components-test)New primitives that belong in
packages/ui— generic, reusable beyond this widgetOnly add to
packages/uiif the component has no reserve-specific logic and is clearly reusable by other widgets:DirectionToggle(buy ↔ sell flip button)packages/uiif the implementer confirms it has zero domain logicSlippageInput(percent input with presets)packages/uionly if no reserve-specific preset values leak into itComponents local to
packages/goodreserve-widget— keep here, do not move topackages/uiGoodReserveWidget— root widget component with provider boundaryReserveSwapView— main screen orchestrationReserveAmountInput— amount input with reserve-specific balance display, token label, and MAXReserveAssetPair— from/to asset pair display + direction selectorReserveRouteStats— reserve price, spread, and liquidity stats cardReserveTokenInfo— optional reserve token metadata panelReserveConfirmDialog— swap confirmation modal with reserve-specific fee/slippage summaryReserveGasWarn— gas/low-balance warning overlayreserveSwapStore.ts— widget state machine (direction, input amounts, quote, tx state)reserveOverlayStore.ts— slippage sheet and token selector overlay stateuseReserveSwapQuote.ts— debounced quote hook wrapping SDKuseReserveSwapTx.ts— transaction lifecycle hook wrapping SDKutils/errors.ts— reserve error classificationGoodReserve SDK integration plan
Expected SDK APIs
Based on
apps/demo-reserve-swapas the reference:GoodReserveSDKclass or factorysdk.getReserveStats()or equivalentsdk.getQuote(direction, fromAmount, token)or equivalentsdk.buy(params)/sdk.sell(params)sdk.getBalance(address, token)sdk.getSupportedTokens()or reserve pair constantserrors.tsHook vs direct SDK
Preferred: Use
useGoodReservefrom@goodsdks/react-hooksif the hook provides quote, balance, buy/sell, and reserve stats in one stable API. If the hooks package does not yet provide these capabilities, use theGoodReserveSDKclass directly viauseReserveSwapQuote.tsanduseReserveSwapTx.ts(following the demo pattern).The choice between hooks and direct SDK must be confirmed by inspecting
packages/react-hooks/README.mdin the GoodSDKs repo before implementation.Supported chains
Verify against
packages/good-reserve/README.md. Expected: Celo mainnet (42220) and/or Fuse (122). The widget must checkchainIdat runtime and render the "unsupported chain" state for any chain not in the supported list.Slippage
Default to the SDK's recommended slippage value (inspect demo-reserve-swap). Expose a slippage setting sheet that allows the user to choose from preset values (0.1%, 0.5%, 1%) or enter a custom value. Never hardcode slippage without checking the SDK's defaults.
Package version and dependency check
Scope
Must change:
packages/goodreserve-widget/with full package scaffold (package.json, tsconfig, tsup, src/index.ts)GoodReserveWidgetroot component withprovider,config,themeOverrides,environment,onSwapSuccess,onSwapErrorpropsReserveSwapViewand all required child components listed in the source-to-target mappinguseReserveSwapQuoteanduseReserveSwapTxhooks inside the widget packagereserveSwapStoreandreserveOverlayStorefor widget state@goodsdks/good-reserveSDK into the quote and transaction hookswidgetRuntimeContract.tsandintegration.tsfiles following citizen-claim-widget patternspnpm-workspace.yamlandturbo.jsonGoodReserveWidgetinexamples/storybook/src/stories/examples/storybook/src/fixtures/tests/demo/smoke.spec.tsMay change:
packages/ui/src/components/— only to addDirectionToggleorSlippageInputif confirmed generic per the primitive extraction decision abovepackages/ui/src/presets.ts— only if new widget-agnostic theme keys are required (ask first)examples/storybook/src/fixtures/mockEip1193.ts— only to extend to Celo mainnet (42220) if not already presentMust not change:
packages/core/(unless a genuine gap in wallet context API is found and approved)packages/embed/packages/claim-widget/packages/citizen-claim-widget/packages/ui/src/theme.ts(unless new generic token seeds are strictly required)packages/ui/src/presets.tsthemes already defined for other widgetsexamples/react-web/,examples/html/,examples/expo/(no changes unless explicitly approved)Non-goals
Do not include:
packages/uiprimitive migrations unrelated to this widgetpackages/coreArchitecture constraints
packages/ui.packages/goodreserve-widget.GoodWidgetProvider.Acceptance criteria
packages/goodreserve-widgetexists with a complete package scaffold following the citizen-claim-widget pattern.GoodReserveWidgetrenders without errors when given a mock EIP-1193 provider (Celo chain ID 42220).GoodReserveWidgetrenders the "unsupported chain" state when the provider reports a non-reserve chain.GoodReserveWidgetrenders the "not connected" / "no provider" state when no provider is passed.errors.ts.GoodReserveWidgetacceptsconfigandthemeOverridesprops that apply through the standard GoodWidget theming pipeline.widgetRuntimeContract.tsandintegration.tsexist and accurately describe the widget's SDK dependencies, states, events, and chains.packages/goodreserve-widgetuse semantic theme keys from the GoodWalletV2 preset, not hardcoded colors.packages/uihas acreateComponent()name, manifest registration, and uses the standard theming decision checklist.pnpm buildpasses for the full workspace.pnpm test:storybookpasses.pnpm test:demopasses (smoke test for new story).Required states, flows, and behaviors
sdk_initializingSdkInitializingstoryno_providerproviderprop is undefined or nullNoProviderstoryunsupported_chainUnsupportedChainstoryreserve_stats_loadingStatsLoadingstoryidle_buyDefault(ConnectedBuy) storyidle_sellConnectedSellstoryamount_editingAmountEditingbalance_loadedquote_loadingQuoteLoadingstoryquote_readyQuoteReadystoryquote_errorQuoteErrorstoryinsufficient_balanceInsufficientBalancestorylow_liquidity_warningLowLiquidityWarningstoryslippage_selectionconfirm_dialogswap_pendingSwapPendingstoryswap_successSwapSuccessstoryswap_errorerrors.ts; allow retrySwapErrorstoryrefresh_quoterefresh_reserve_contextSDK, dependency, and cross-repo checks
Required SDK/package assumptions (must be verified before implementation):
@goodsdks/good-reserve— reserve swap SDK. Assumed version: latest published onmainor a designated branch. Must confirm: is it on npm? Which version?@goodsdks/react-hooks— React hook layer. Must confirm: does it exportuseGoodReserve,useReserveSwapQuote, or equivalent hooks?wagmi/viem— SDK peer deps may require these. Confirm whether GoodWidget's existing wagmi integration (packages/core/src/wagmi.ts) satisfies the SDK requirements or whether new peer deps are needed.Cross-repo dependencies:
packages/good-reserve,packages/react-hooks,apps/demo-reserve-swapRequired checks:
@goodsdks/good-reserveand@goodsdks/react-hooksare already published, branch-only, or local-only.Storybook requirements
examples/storybook/src/stories/GoodReserveWidget.stories.tsx.examples/storybook/src/fixtures/mockReserveSDK.ts(no live network calls; all state pre-seeded).createMockEip1193Providerfrom existing fixture; wire to Celo mainnet (chain ID 42220) or extend the fixture to support it.data-testidvalues for all primary interactive elements following theComponentName-variantconvention.tests/demo/smoke.spec.tsfor at least theDefaultstory.Required stories/states:
data-testidrequiredDefault(ConnectedBuy)GoodReserveWidget-defaultConnectedSellGoodReserveWidget-sellQuoteReadyGoodReserveWidget-quote-readyQuoteLoadingGoodReserveWidget-quote-loadingInsufficientBalanceGoodReserveWidget-insufficient-balanceQuoteErrorGoodReserveWidget-quote-errorSwapPendingGoodReserveWidget-swap-pendingSwapSuccessGoodReserveWidget-swap-successSwapErrorGoodReserveWidget-swap-errorNoProviderGoodReserveWidget-no-providerUnsupportedChainGoodReserveWidget-unsupported-chainLowLiquidityWarningGoodReserveWidget-low-liquidityPlay function tests required for:
SlippageSelection— open slippage sheet → select a preset → verify selection is reflectedConfirmDialog— enter amount with valid mock quote → press swap → verify confirm dialog appearsDirectionToggle— press direction toggle → verify buy/sell labels swapVisual and UX requirements
Required visible sections:
Required responsive checks:
Screenshots or recordings required (in PR):
Default,QuoteReady,SwapSuccess,SwapError,NoProviderstory screenshotsVerification commands
Run and report in the PR body:
pnpm install pnpm build pnpm lint pnpm storybook & sleep 15 pnpm test:storybook pnpm test:demoIf any command cannot run (e.g., SDK not yet published), explain exactly what was run instead and what was verified manually.
Pull request requirements
The PR description must include:
packages/uivs widget-local)Known risks and follow-ups
@goodsdks/good-reservemay not be published on npm at the time of implementation. If the package is branch-only, the implementer must report this as a blocker rather than using a path dependency without approval.TransactionButtonmaturity:packages/ui/src/components-test/TransactionButton.tsxexists but may not cover all swap tx states. The implementer should assess whether it can be used directly or whether a widget-localReserveSwapButtonis needed.Human reviewer checklist
packages/ui; no bypass of provider model).Spec readiness check