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
Existing viem-style read helpers in packages such as /home/runner/work/GoodWidget/GoodWidget/packages/ai-credits-widget/src/vaultMinimums.ts
Existing adapter-factory pattern in /home/runner/work/GoodWidget/GoodWidget/packages/ai-credits-widget/src/widgetRuntimeContract.ts
Existing G$ address sourcing pattern from other widgets; if current widgets hardcode the G$ address, hardcode it here too, otherwise follow the same existing pattern.
GoodDollar Identity usage in the citizen claim widget; replicate its @goodsdks/citizen-sdk / identitySdk usage for identity verification.
GoodProtocol contract references from PR #299:
contracts/governance/GoodDaoHouses.sol
contracts/governance/IFlowSplitter.sol
contracts/mocks/MockFlowSplitter.sol
test/governance/GoodDaoHouses.test.ts
Resolved implementation decisions
GoodDaoHouses production address: load the Celo Mainnet contract address from environment config.
G$ token address and ABI: follow the existing GoodWidget pattern used by other widgets. If existing widgets hardcode G$, hardcode it here; if they resolve it through another shared source, use that same source.
Registration path: use G$ transferAndCall as the primary one-transaction registration path.
HoA eligibility: assume the contract will expose a House of Alignment whitelist registry. Disable Alignment selection before registration for non-whitelisted connected accounts; show it greyed out in onboarding for everyone else.
Alignment approval: pending Alignment-member copy can use lorem ipsum placeholder text for now.
Identity verification: use GoodDollar Identity by following the citizen claim widget's @goodsdks/citizen-sdk / identitySdk integration pattern.
Dashboard impact metrics: hardcode the Impact Card numbers for now; these metrics will be followed up later.
Balance cards: only show active members for v1.
Active governance card: open a new governance detail and voting page. The detailed UI is not done yet, so a very simple mocked placeholder is acceptable for now.
Ballot replacement: hide edit/update affordances and show an already-voted state because PR #299 rejects duplicate votes with Already voted.
Funding distribution timing/source: base FundingDistributionChart on live funding details read from the pool.
FlowSplitter details: read funding distribution data directly from the FlowSplitter pool rather than relying only on GoodDaoHouses reads. Since the actual pool is not deployed yet, use a mocked/fake pool address until the real environment config is available.
Footer member details: no additional footer fields were provided in the resolved answers; keep the footer scoped to the already planned member details such as joinedAt, house, and status.
Revoked/unstaked member UX: allow users to restake a house at any time. House of Alignment remains whitelist-gated: it is available when a whitelisted address connects and shown greyed out during onboarding for everyone else.
Unsupported chain UX: actively request a switch to Celo Mainnet. Celo Mainnet should be the default requested chain, and the widget should always request the switch when needed.
Error reporting: translate contract errors into clear, friendly human-language widget copy instead of showing raw errors verbatim.
Smart-contract interface map for the frontend
Use the actual PR #299 implementation details rather than the older planning assumptions where they differ.
minimumStake(House) for stake labels and validation.
getMember(address) for member detection, member footer, and onboarding routing.
getActiveMembers(House) / paginated overload for dashboard member counts and Alignment recipients.
cycleStartTime, termDuration, votingTermLength, isVotingPeriod(), getCurrentVoteId(), and getVoteConfig(voteId) for active governance state.
getVoteRecipients(voteId), getHasVoted(voteId, voter), and getFinalizedUnits(voteId, recipient) for Alignment voting and finalized distribution displays.
flowSplitterConfig() for configured pool state if the dashboard needs to link or validate distribution execution.
User-write methods:
G$ transferAndCall(housesContract, amount, encodedRegistrationData) as the primary single-transaction registration path.
registerAndStake(house, name, socialLinks, projectWebpage, missionStatement, distributionStrategy) only as an explicit fallback strategy if needed by the SDK layer.
stake(amount) for existing members topping up/restaking.
castVote(recipients, allocations) for Alignment Vote allocation submission.
unstake() if the widget exposes member exit in scope.
Committee/admin methods should not be exposed as part of the governance UI:
getPoolById(uint256 poolId) returns (Pool) reads pool metadata by id.
getPoolByAdminRole(bytes32 adminRole) returns (Pool) reads pool metadata by admin role when the role is available.
getPoolNameById(uint256 poolId) and getPoolSymbolById(uint256 poolId) read display metadata.
isPoolAdmin(uint256 poolId, address account) can validate admin status if the UI needs to display configured/admin state.
Pool includes id, poolAddress, token, metadata, and adminRole.
Member includes account and units; use this shape when mapping funding units in tests/mocks and any future write-facing admin tooling.
PoolCreated(poolId, poolAddress, token, metadata) can be used as a reference event for deployed pool discovery if needed later.
Implementation constraints:
The widget should not create FlowSplitter pools.
The widget should not expose FlowSplitter admin writes such as createPool, updateMembersUnits, addPoolAdmin, removePoolAdmin, updatePoolAdmins, or updatePoolMetadata as normal user actions.
Until the actual pool is deployed, use a mocked/fake pool address and mocked pool data in Storybook/Playwright states.
Funding distribution UI should read live funding details directly from the pool-facing integration path, with GoodDaoHouses reads used only where they are still needed for governance/vote context.
Required states, flows, and behaviors
No connected wallet
Render the dashboard overview freely without blocking scroll or presentational interactions.
Show header/title and connect action.
Do not force the onboarding flow while disconnected.
Use safe placeholder/loading/empty copy for contract-backed values that require an account or RPC.
Wallet connected
Show a loading state while resolving account, chain, contract reads, identity state, and member record.
Request a switch to Celo Mainnet whenever the connected wallet is on an unsupported chain.
Read getMember(address).
If status is None or no usable member record exists, route into onboarding.
If status is Pending, show the relevant pending Alignment state with placeholder lorem ipsum copy until final copy is supplied.
If status is Active, show the dashboard and add a footer bar with member details such as house, joined date, and status.
If status is Revoked or Unstaked, show a clear restake/re-register state.
Onboarding flow
Reuse the existing wizard UI and step structure as much as possible.
Replace mocked transaction-step state with runtime state from actual reads/writes.
Load stake amount from minimumStake(selectedHouse).
Use GoodDollar Identity via the citizen claim widget's identitySdk pattern for identity verification.
Validate profile fields according to house-specific contract metadata:
For Alignment registration, check the expected HoA whitelist registry once available; disable and grey out Alignment selection for non-whitelisted accounts.
For Alignment registration, communicate that the contract status becomes Pending and requires committee approval.
For Citizens registration, communicate that successful registration activates membership immediately.
Submit registration primarily through G$ transferAndCall.
Show transaction progress, friendly error copy, retry, and confirmation states.
Active governance section showing Alignment Voting for now.
Funding distribution from live pool details.
Connected active-member footer bar.
Keep existing component styling intact; only add props/data adapters where needed.
Drive active governance from contract voting schedule and vote reads.
Drive funding distribution from the pool-facing integration path, using mocked pool data until the real pool is deployed.
Include empty, loading, error, and unavailable states for all contract-backed dashboard blocks.
Alignment voting flow
The active governance card should open a new governance detail/voting page.
Use a very simple mocked placeholder for the detail/voting page until final UI is available.
Use active Alignment recipients from the vote snapshot or active Alignment members, depending on whether the current vote record exists.
Collect recipient allocations that sum to exactly 10,000 basis points.
Disable voting for ineligible, inactive, pending, or already-voted users.
Reflect that current contract behavior does not allow ballot replacement by showing an already-voted state and hiding edit/update affordances.
Surface execution/final units as read-only distribution information after the voting window closes and execution completes.
Execution plan
Add a widget-level runtime contract in packages/governance-widget/src/sdks/.
Include contract ABI/address inputs, environment-config address loading, chain constants, viem client setup, read helpers, write helpers, and pure mappers.
Keep blockchain, formatting, and state orchestration out of presentational UI components.
Add a governance adapter layer.
Follow the existing adapter-factory style used by other widget packages so Storybook can inject mock states and production can use real contract reads/writes.
Keep hooks focused: one hook should not own all membership, dashboard, vote, form, and transaction logic.
Add the app-like GovernanceWidget composition component.
Use GovernanceWidgetProvider and existing dashboard/onboarding components.
Own high-level routing between disconnected dashboard, loading, onboarding, pending membership, active dashboard, restake/re-register, unsupported-chain switching, and error states.
Add small widget-local components only where needed.
Likely widget-local: header/connect state, member footer bar, loading/error/empty state surfaces, active governance section wrapper, and placeholder vote detail surface.
Do not move anything to packages/ui unless it is clearly reusable across multiple widgets.
Wire onboarding to contract-backed membership creation.
Load minimumStake by selected house.
Resolve G$ address/ABI using the existing repository pattern.
Submit registration primarily via G$ transferAndCall.
Keep any fallback direct registerAndStake strategy explicit in the SDK layer, not buried inside UI components.
Use GoodDollar Identity via @goodsdks/citizen-sdk / identitySdk following the citizen claim widget pattern.
Wire dashboard reads.
Fetch member record, active members, voting schedule/window, vote config, recipients, vote status, and finalized distribution units where relevant.
Hardcode Impact Card metrics for now.
Show active members as the v1 balance metric.
Read live funding details directly from the FlowSplitter pool-facing integration path, using mocked pool address/data until the actual pool is deployed.
Map available values into existing ImpactCard, BalanceCard, AlignmentVotingProposalCard, and FundingDistributionChart prop shapes.
Wire Alignment Voting interactions.
Add a placeholder governance detail/voting page opened from the active governance card.
Ensure allocations are validated as basis points and match contract expectations.
Show already-voted state instead of ballot edit/update behavior.
Add Storybook coverage.
Keep existing presentational stories.
Add runtime/mock stories for disconnected, loading, onboarding required, HoA unavailable/greyed out, pending Alignment, active Citizens, active Alignment, vote open, already voted, vote closed/executed, empty recipients, pool unavailable/mocked, unsupported chain switch request, restake/re-register, and friendly contract error states.
Include both custodial and injected fixture flows using the existing Storybook fixture files.
Add Playwright smoke coverage.
Add/extend tests under tests/widgets/governance-widget/.
Capture screenshots for the key runtime states listed above.
Keep screenshot paths consistent with the repository's current Playwright test-results convention.
Validate the package.
Run the repository build/lint/test commands required by the issue and any package-specific scripts.
At minimum, validate build/lint and the Storybook/Playwright paths affected by the widget changes.
Coding patterns and rules for this task
Do excessive implementation comments as you work.
Use clear declarative names for contract state, adapter state, transaction state, and UI state.
Modularize large hooks and utilities into maintainable boundaries:
contract ABI/address constants
environment config/address resolution
G$ token resolution
read helpers
write helpers
FlowSplitter pool helpers
mappers/formatters
membership hook
identity verification hook
dashboard data hook
onboarding transaction hook
voting hook
Do not split logic into single-line helper files just to appear modular.
Do not build one oversized hook that owns all state and all contract interactions.
Prefer available libraries and repository patterns over localized solutions, especially viem utilities for ABI parsing, encoding, contract reads/writes, and EIP-1193 wallet interaction.
Keep smart-contract and SDK/core logic inside packages/governance-widget/src/sdks/ or similarly scoped widget-local runtime files.
Keep presentational components mostly presentational; add props where needed, but avoid embedding contract calls in card components.
Preserve current UI styling unless the functionality requires a small prop or state addition.
Do not add new public theme targets unless they are intentional, stable, and reviewed.
Acceptance criteria
A real GovernanceWidget app-level component exists and composes existing dashboard and onboarding UI without changing their visual design unnecessarily.
Wallet connection state is supported through existing GoodWidget provider patterns.
Disconnected users can browse the dashboard and interact with safe presentational elements.
Connected users see loading, member detection, identity-verification, onboarding-required, pending, active dashboard, restake/re-register, unsupported-chain switch request, and friendly error states as appropriate.
Membership reads and writes map to the actual GoodDaoHouses PR #299 interface.
Onboarding uses contract-backed stake requirements and submits contract-backed registration/staking through the primary G$ transferAndCall path.
Dashboard impact metrics are hardcoded for v1, active members are shown as the v1 balance metric, and funding distribution reads from the pool-facing integration path with mocked pool data until deployment.
Alignment Voting reflects the current contract behavior, including fixed weights, schedule-based voting windows, no ballot replacement, already-voted state, and basis-point allocation validation.
Active governance opens a placeholder governance detail/voting page.
Core logic, data fetching, and contract interactions are modularized under the governance widget package and are not embedded in presentational cards.
Storybook includes interactive mocked runtime states for custodial and injected wallet flows.
Playwright smoke tests cover the main runtime states and include screenshots.
Build/lint/test commands relevant to the package and Storybook smoke coverage pass or have documented unrelated blockers.
Human-reviewer checklist
Confirm the frontend should target the current PR #299 contract behavior rather than the earlier #298 plan where they differ.
Confirm the exact environment config names and production values for GoodDaoHouses, the HoA whitelist registry, and the FlowSplitter pool once deployed.
Confirm the existing repository pattern selected for G$ token address/ABI resolution.
Replace lorem ipsum pending Alignment copy before production release if final copy is available.
Confirm the placeholder governance detail/voting page is acceptable for this implementation slice.
Confirm no shared packages/ui components are needed beyond already existing primitives.
Confirm Storybook/Playwright screenshot states before implementation starts.
[PLAN] Wire GovernanceWidget functionality to GoodDaoHouses
Parent: #75
Planning-only task. Do not implement until this issue is reviewed, approved, and the
[DRAFT]prefix is removed.Context reviewed
/home/runner/work/GoodWidget/GoodWidget/ARCHITECTURE.md/home/runner/work/GoodWidget/GoodWidget/docs/widget-author-instructions.md/home/runner/work/GoodWidget/GoodWidget/docs/demo-environment.mdRelevant files to use as implementation references
GoodWidget local package:
/home/runner/work/GoodWidget/GoodWidget/packages/governance-widget/src/GovernanceWidgetProvider.tsx/home/runner/work/GoodWidget/GoodWidget/packages/governance-widget/src/GovernanceOnboardingWidget.tsx/home/runner/work/GoodWidget/GoodWidget/packages/governance-widget/src/onboarding/GovernanceOnboardingFlow.tsx/home/runner/work/GoodWidget/GoodWidget/packages/governance-widget/src/types.ts/home/runner/work/GoodWidget/GoodWidget/packages/governance-widget/src/ImpactCard.tsx/home/runner/work/GoodWidget/GoodWidget/packages/governance-widget/src/BalanceCard.tsx/home/runner/work/GoodWidget/GoodWidget/packages/governance-widget/src/AlignmentVotingProposalCard.tsx/home/runner/work/GoodWidget/GoodWidget/packages/governance-widget/src/FundingDistributionChart.tsx/home/runner/work/GoodWidget/GoodWidget/packages/governance-widget/src/format.ts/home/runner/work/GoodWidget/GoodWidget/examples/storybook/src/stories/governance-widget/GovernanceDashboard.stories.tsx/home/runner/work/GoodWidget/GoodWidget/examples/storybook/src/stories/governance-widget/GovernanceOnboarding.stories.tsx/home/runner/work/GoodWidget/GoodWidget/tests/widgets/governance-widget/dashboard.spec.ts/home/runner/work/GoodWidget/GoodWidget/tests/widgets/governance-widget/onboarding.spec.tsReusable wallet/runtime references:
/home/runner/work/GoodWidget/GoodWidget/packages/core/src/provider.tsx/home/runner/work/GoodWidget/GoodWidget/packages/core/src/hooks.ts/home/runner/work/GoodWidget/GoodWidget/packages/core/src/wagmi.ts/home/runner/work/GoodWidget/GoodWidget/packages/ai-credits-widget/src/vaultMinimums.ts/home/runner/work/GoodWidget/GoodWidget/packages/ai-credits-widget/src/widgetRuntimeContract.ts@goodsdks/citizen-sdk/identitySdkusage for identity verification.GoodProtocol contract references from PR #299:
contracts/governance/GoodDaoHouses.solcontracts/governance/IFlowSplitter.solcontracts/mocks/MockFlowSplitter.soltest/governance/GoodDaoHouses.test.tsResolved implementation decisions
transferAndCallas the primary one-transaction registration path.@goodsdks/citizen-sdk/identitySdkintegration pattern.Already voted.FundingDistributionCharton live funding details read from the pool.GoodDaoHousesreads. Since the actual pool is not deployed yet, use a mocked/fake pool address until the real environment config is available.joinedAt, house, and status.Smart-contract interface map for the frontend
Use the actual PR #299 implementation details rather than the older planning assumptions where they differ.
Contract model:
House.Citizens = 0maps to widgetcitizenship.House.Alignment = 1maps to widgetalignment.MemberStatus:None,Pending,Active,Revoked,Unstaked.MemberRecordcontainshouse,status,stakedAmount,joinedAt,updatedAt,unstakedAt,name,socialLinks,projectWebpage,missionStatement, anddistributionStrategy.Frontend-readable contract methods:
minimumStake(House)for stake labels and validation.getMember(address)for member detection, member footer, and onboarding routing.getActiveMembers(House)/ paginated overload for dashboard member counts and Alignment recipients.cycleStartTime,termDuration,votingTermLength,isVotingPeriod(),getCurrentVoteId(), andgetVoteConfig(voteId)for active governance state.getVoteRecipients(voteId),getHasVoted(voteId, voter), andgetFinalizedUnits(voteId, recipient)for Alignment voting and finalized distribution displays.flowSplitterConfig()for configured pool state if the dashboard needs to link or validate distribution execution.User-write methods:
transferAndCall(housesContract, amount, encodedRegistrationData)as the primary single-transaction registration path.registerAndStake(house, name, socialLinks, projectWebpage, missionStatement, distributionStrategy)only as an explicit fallback strategy if needed by the SDK layer.stake(amount)for existing members topping up/restaking.castVote(recipients, allocations)for Alignment Vote allocation submission.unstake()if the widget exposes member exit in scope.Committee/admin methods should not be exposed as part of the governance UI:
approveAlignmentMember,revokeMember,executeVote,setStakeRequirement,setVotingSchedule,configureFlowSplitter,pause,unpause.Important contract behavior from the PR conversation:
executeVoteupdates FlowSplitter units after the voting window closes.Already voted.cycleStartTime,termDuration, and the current timestamp.castVotelazily creates the vote record and snapshots active Alignment recipients.GoodDaoHouses; the contract expects an existing configured pool whereGoodDaoHousesis pool admin.FlowSplitter integration notes
Use the FlowSplitter interface documented at https://docs.flowstate.network/developers/IFlowSplitter for pool reads and future admin/write boundaries.
Relevant IFlowSplitter functions and structures:
getPoolById(uint256 poolId) returns (Pool)reads pool metadata by id.getPoolByAdminRole(bytes32 adminRole) returns (Pool)reads pool metadata by admin role when the role is available.getPoolNameById(uint256 poolId)andgetPoolSymbolById(uint256 poolId)read display metadata.isPoolAdmin(uint256 poolId, address account)can validate admin status if the UI needs to display configured/admin state.Poolincludesid,poolAddress,token,metadata, andadminRole.Memberincludesaccountandunits; use this shape when mapping funding units in tests/mocks and any future write-facing admin tooling.PoolCreated(poolId, poolAddress, token, metadata)can be used as a reference event for deployed pool discovery if needed later.Implementation constraints:
createPool,updateMembersUnits,addPoolAdmin,removePoolAdmin,updatePoolAdmins, orupdatePoolMetadataas normal user actions.Required states, flows, and behaviors
No connected wallet
Wallet connected
getMember(address).Noneor no usable member record exists, route into onboarding.Pending, show the relevant pending Alignment state with placeholder lorem ipsum copy until final copy is supplied.Active, show the dashboard and add a footer bar with member details such as house, joined date, and status.RevokedorUnstaked, show a clear restake/re-register state.Onboarding flow
minimumStake(selectedHouse).identitySdkpattern for identity verification.name,socialLinks.name,projectWebpage,missionStatement,distributionStrategy.Pendingand requires committee approval.transferAndCall.Dashboard flow
Alignment voting flow
10,000basis points.Execution plan
Add a widget-level runtime contract in
packages/governance-widget/src/sdks/.Add a governance adapter layer.
Add the app-like
GovernanceWidgetcomposition component.GovernanceWidgetProviderand existing dashboard/onboarding components.Add small widget-local components only where needed.
packages/uiunless it is clearly reusable across multiple widgets.Wire onboarding to contract-backed membership creation.
minimumStakeby selected house.transferAndCall.registerAndStakestrategy explicit in the SDK layer, not buried inside UI components.@goodsdks/citizen-sdk/identitySdkfollowing the citizen claim widget pattern.Wire dashboard reads.
ImpactCard,BalanceCard,AlignmentVotingProposalCard, andFundingDistributionChartprop shapes.Wire Alignment Voting interactions.
Add Storybook coverage.
Add Playwright smoke coverage.
tests/widgets/governance-widget/.Validate the package.
Coding patterns and rules for this task
packages/governance-widget/src/sdks/or similarly scoped widget-local runtime files.Acceptance criteria
GovernanceWidgetapp-level component exists and composes existing dashboard and onboarding UI without changing their visual design unnecessarily.GoodDaoHousesPR #299 interface.transferAndCallpath.Human-reviewer checklist
packages/uicomponents are needed beyond already existing primitives.