Skip to content

[PLAN] AI Credits Widget: Buy AI coding credits with G$ #62

Description

@L03TJ3

[DRAFT][PLAN] AI Credits Widget: Buy AI coding credits with G$

Sub-issue of #61 — do not execute until [DRAFT] is removed from the title.


Reference Files

GoodWidget (this repo)

Purpose Path
Widget pattern to mirror packages/citizen-claim-widget/src/CitizenClaimWidget.tsx
Adapter pattern packages/citizen-claim-widget/src/adapter.ts
Runtime contract / props packages/citizen-claim-widget/src/widgetRuntimeContract.ts
Integration manifest packages/citizen-claim-widget/src/integration.ts
Web-component bridge packages/citizen-claim-widget/src/element.ts, register.ts
Multi-step timeline reference packages/staking-migration-widget/src/MigrationProgressTimeline.tsx
Reusable Stepper packages/ui/src/components/Stepper.tsx
Reusable Card, Button, TokenAmount, Toast, Heading, Text packages/ui/src/components/
createComponent (named sub-theme targets) packages/ui/src/createComponent.ts
Provider + wallet hooks packages/core/src/provider.tsx, packages/core/src/hooks.ts
Storybook fixture (custodial) examples/storybook/src/fixtures/custodialEip1193.ts
Storybook fixture (injected) examples/storybook/src/fixtures/injectedEip1193.ts
Story organisation example examples/storybook/src/stories/citizen-claim-widget/
Playwright test example tests/widgets/staking-migration-widget/states.spec.ts

Cross-repo (read-only reference)

  • GoodWallet / GoodProtocolUI – integration targets; embed widget via <ai-credits-widget> web-component or React import.
  • AntseedBuyerOperator contract (Base) – depositFor(buyerKey, amount) called by backend after Celo payment settles.
  • EIP-712 operator consent signed by buyer key: AntseedBuyerOperator set as deposits operator.

Required States, Flows, and Behaviours

Widget states

ID Name Description
S1 disconnected No wallet connected; show connect CTA
S2 connected_empty Wallet connected; G$ balance = 0; show balance + warn
S3 quote_ready G$ balance > 0; user has set deposit/stream amounts ≥ min; show cost breakdown + bonus badge
S4 payment_pending Celo buy tx submitted; spinner active
S5 payment_confirmed Celo tx mined; backend settling USDC on Base
S6 has_credits Credits landed on Base; show balance card + setup snippet
S7 usage_empty Credits = 0 after prior purchase; upsell
S8 usage_active Credits > 0, usage log visible
S9 insufficient_g_balance G$ balance < minimum; show top-up guidance
S10 insufficient_ai_credits API rejected; credits exhausted
S11 payment_failed Celo tx reverted or backend error
S12 backend_unavailable Mock/real backend unreachable
S13 unsupported_chain Wallet on wrong chain; show switch CTA

Happy-path flow

  1. Connectdisconnectedconnected_empty / quote_ready
  2. GoodID badge – adapter reads GoodID verification; shows "20% streaming bonus" badge when verified.
  3. Buyer key – user generates (random keypair in-widget) or pastes existing buyer key; must copy + confirm if generated.
  4. Operator consent – buyer key signs EIP-712 message setting AntseedBuyerOperator as deposits operator (done in-browser, no custody).
  5. Amount picker – choose one-time deposit (G$, min ~$1 equivalent, +10% bonus) and/or monthly stream (G$, min ~$1/month, +20% bonus with GoodID). Totals shown in G$ and USD equivalent.
  6. Pay – payer wallet confirms single Celo tx → payment_pending.
  7. Settle – backend polls/webhook; backend calls depositFor on Base → payment_confirmedhas_credits.
  8. Setup card – shows AntSeed API key / base URL snippet copyable for Cursor, Cline, etc.
  9. History – accordion usage log per session.

Edge / error behaviours

  • Switching from generated key without copying → block with modal confirmation.
  • Backend unavailable → show retry toast, keep UI interactive.
  • Tx reverted → payment_failed with reason string from receipt.
  • Unsupported chain → "Switch to Celo" CTA using switchChain action.
  • GoodID not verified → show 10% deposit bonus only; hide stream bonus badge.

Execution Plan

1 — Package scaffold (packages/ai-credits-widget)

  • Copy packages/citizen-claim-widget structure.
  • package.json: name @goodwidget/ai-credits-widget, workspace deps @goodwidget/core, @goodwidget/ui, @goodwidget/embed, viem.
  • Exports: ".", "./element", "./register" (same pattern).

2 — Runtime contract (widgetRuntimeContract.ts)

Define and export:

  • AiCreditsWidgetStatus union (all 13 states above).
  • AiCreditsWidgetPrimaryAction union: connect | switch_chain | generate_key | sign_consent | pay | retry | refresh | none.
  • AiCreditsWidgetAdapterState — includes: status, address, chainId, gBalance, aiCreditsBalance, isGoodIdVerified, buyerKey, depositAmount, streamAmount, bonusPercent, quote, setupSnippet, usageLog[], error.
  • AiCreditsWidgetAdapterActionsconnect, switchChain, generateBuyerKey, pasteBuyerKey, signOperatorConsent, setDepositAmount, setStreamAmount, pay, refresh, retry.
  • AiCreditsWidgetPropsprovider?, environment?, backendUrl?, themeOverrides?, config?, defaultTheme?, onPaySuccess?, onPayError?.

3 — Mock backend client (mockBackendClient.ts)

  • Interface AiCreditsBackendClient with methods: getQuote(address, depositG$, streamG$), getCreditsBalance(buyerKey), getUsageLog(buyerKey).
  • Mock implementation returns deterministic fake data so stories and Playwright work without a live Worker.
  • Production implementation will call backendUrl REST endpoints (stubbed).

4 — Adapter hook (adapter.ts)

useAiCreditsAdapter({ environment, backendUrl }):

  • Uses useWallet() from @goodwidget/core for wallet state.
  • Reads G$ balance on Celo via viem public client.
  • Reads GoodID verification status (mock for now).
  • Manages local state machine for the 13 widget states.
  • Exposes all AiCreditsWidgetAdapterActions.
  • Buyer key stored in component state (never leaves browser for signing).

5 — New components in packages/ai-credits-widget/src/

All built with createComponent from @goodwidget/ui to participate in the sub-theme system.

Component Description Reuse from packages/ui?
AiCreditsHeroCard G$ amount input + bonus badge No – widget-specific layout
BuyerKeyPanel Generate/paste buyer key + copy-confirm guard No – widget-specific
OperatorConsentStep EIP-712 sign prompt + status No – widget-specific
AmountPicker Deposit + stream sliders/inputs + totals No – widget-specific
CreditsBalanceCard Shows AI credits balance + usage bar No – widget-specific
SetupSnippetCard Copyable API key / base URL block No – widget-specific
UsageLog Accordion list of usage entries No – widget-specific
AiCreditsFlowStepper Wraps Stepper from packages/ui with widget-specific step config Wraps Stepper
AiCreditsStatusNotice Error / warning banners Wraps Text + Card from packages/ui

Stepper, Card, Button, TokenAmount, Heading, Text, Toast*, Spinner, XStack, YStack, Separator, Anchor come from @goodwidget/ui — do not duplicate them.

6 — Main widget component (AiCreditsWidget.tsx)

  • Outer: GoodWidgetProvider wrapper (same pattern as CitizenClaimWidget).
  • Inner (AiCreditsWidgetInner): state-driven render — hero → stepper (steps: connect, buyer key, sign, pick amount, pay) → balance/setup card → usage log.
  • Toast notifications for pay events via createToast / updateToast.

7 — Web-component bridge

  • element.ts — defines <ai-credits-widget> custom element via @goodwidget/embed.
  • register.ts — auto-registers the element.
  • index.ts — re-exports AiCreditsWidget + types.

8 — Integration manifest (integration.ts)

export const aiCreditsIntegration = {
  id: 'ai-credits',
  chains: [42220],          // Celo (payer side)
  settlementChains: [8453], // Base (buyer credits)
  states: [ /* all 13 state IDs */ ],
  events: ['pay-success', 'pay-error'],
} as const

9 — Storybook stories (examples/storybook/src/stories/ai-credits-widget/)

  • AiCreditsWidget.mdx — overview doc.
  • AiCreditsWidgetShowcase.stories.tsx — per-state stories using custodialEip1193 and injectedEip1193 fixtures; mock adapter via adapterFactory prop pattern (same as staking-migration-widget).
  • AiCreditsWidgetQA.stories.tsx — interactive happy-path story.
  • Cover all 13 states as individual story variants.

10 — Playwright smoke tests (tests/widgets/ai-credits-widget/)

  • states.spec.ts — one test() per widget state; visits the Storybook story, takes page.screenshot().
  • Screenshots saved to tests/widgets/ai-credits-widget/test-results/.
  • Cover: disconnected, connected_empty, quote_ready, payment_pending, has_credits, payment_failed, backend_unavailable, unsupported_chain.

11 — GoodWallet / GoodProtocolUI integration notes (not in scope of this plan)

  • Once widget is published, consuming apps import @goodwidget/ai-credits-widget or @goodwidget/ai-credits-widget/register for the web-component.
  • Props: backendUrl, provider, environment.

Acceptance Criteria

  • packages/ai-credits-widget builds cleanly with pnpm run build from repo root.
  • All 13 widget states are reachable via Storybook stories (custodial and injected).
  • AiCreditsFlowStepper advances through all steps in the happy-path QA story.
  • Buyer key generation requires copy-and-confirm before proceeding.
  • GoodID-verified badge shows 20% bonus; unverified shows 10% deposit-only bonus.
  • payment_failed, backend_unavailable, unsupported_chain states render correct error UI.
  • Playwright smoke tests pass for all covered states with screenshots in tests/widgets/ai-credits-widget/test-results/.
  • No components duplicated from packages/ui; all reused via import.
  • Web component <ai-credits-widget> renders correctly in the examples/html demo.
  • pnpm run lint passes with no new errors.

Human-Reviewer Checklist

  • Widget package follows citizen-claim-widget structure exactly (same file list, same exports).
  • widgetRuntimeContract.ts exports are complete and typed — no any.
  • Adapter does not hold private keys; buyer key never sent to backend unencrypted.
  • EIP-712 signing uses buyer key locally in-browser; payer wallet only signs Celo tx.
  • Mock backend client is clearly separated from production path (no if (mock) sprinkled in adapter).
  • createComponent used for every custom layout element (enables theme overrides).
  • All new public component names documented as API surface.
  • Storybook stories include both custodialEip1193 and injectedEip1193 fixture variants.
  • Playwright screenshots committed to tests/widgets/ai-credits-widget/test-results/.
  • PR description mirrors this acceptance criteria checklist.

Metadata

Metadata

Labels

No labels
No labels

Type

No fields configured for Task.

Projects

Status
In Progress

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions