Skip to content

Wire GovernanceWidget runtime to GoodDaoHouses - #77

Draft
L03TJ3 with Copilot wants to merge 9 commits into
mainfrom
copilot/plan-wire-governancewidget-to-gooddaohouses
Draft

Wire GovernanceWidget runtime to GoodDaoHouses#77
L03TJ3 with Copilot wants to merge 9 commits into
mainfrom
copilot/plan-wire-governancewidget-to-gooddaohouses

Conversation

Copilot AI commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Implements the reviewed GovernanceWidget plan by adding a contract-correct app-level runtime boundary for GoodDaoHouses membership, onboarding, dashboard, Alignment voting states, and live funding totals. The widget remains mockable for Storybook/Playwright while keeping contract and SDK logic out of presentational cards.

  • Runtime adapter + SDK layer

    • Added final GoodDaoHouses ABI coverage, Celo constants, address resolution, viem client helpers, contract mappers, GoodID root verification, HoA eligibility reads, receipt-aware transaction helpers, and Superfluid funding aggregation.
    • Split runtime concerns across contract reads/mappers, membership transactions, voting state/actions, and Superfluid funding reads.
    • Added useGovernanceAdapter with mockable adapter-factory contract.
  • App-level GovernanceWidget

    • Composes header, dashboard, onboarding, pending Alignment, restake, unsupported-chain, friendly error, active-member footer, and vote detail routes.
    • Preserves existing card/onboarding visuals while adding real loading, empty, error, transaction, and read-only execution states where needed.
  • Governance flows

    • Loads membership, identity, HoA eligibility, chain, voting, and funding state through the adapter.
    • Stores raw house stake requirements as bigint values and derives labels only for display.
    • Gates House of Alignment signup through getHoaEligibility(account) while keeping GoodID verification as a separate onboarding requirement with an actionable verification button.
    • Registers and restakes through G$ transferAndCall, waits for receipts, and reflects wallet-confirmation, submitted, confirmed, rejected, and reverted states.
    • Derives voting from isVotingPeriod, getCurrentVoteId, getVoteConfig, getVoteRecipients, active HoA members, getHasVoted, and finalized units.
    • Allows eligible active members of both houses to vote, uses the GoodID root for Citizen duplicate-vote checks, requires exactly 10,000 bps allocations, and shows already-voted/executed states as read-only.
  • Funding received so far

    • Reads flowSplitterConfig.poolAddress as the Superfluid receiver.
    • Queries the Celo Superfluid subgraph for inbound G$ streams with pagination.
    • Calculates cumulative streamed amounts with bigint arithmetic and displays the live total without inventing project-allocation breakdowns.
  • QA coverage

    • Added deterministic Storybook runtime fixtures for disconnected, loading, onboarding, pending, active, upcoming/open/already-voted/executed voting, empty recipients, funding unavailable, unsupported-chain, restake, and friendly error states.
    • Added focused Playwright coverage for ABI mappers, transaction receipt handling, restaking, registration payloads, funding aggregation/pagination/failures, and runtime smoke states with screenshot evidence.
<GovernanceWidget
  provider={provider}
  adapterFactory={mockGovernanceAdapterFactory}
  defaultTheme="dark"
/>

Copilot AI linked an issue Jul 8, 2026 that may be closed by this pull request
7 tasks
Copilot AI and others added 3 commits July 8, 2026 19:18
Co-authored-by: L03TJ3 <6606028+L03TJ3@users.noreply.github.com>
Co-authored-by: L03TJ3 <6606028+L03TJ3@users.noreply.github.com>
Co-authored-by: L03TJ3 <6606028+L03TJ3@users.noreply.github.com>
Copilot AI changed the title [WIP] Wire GovernanceWidget functionality to GoodDaoHouses Wire GovernanceWidget runtime to GoodDaoHouses Jul 8, 2026
Copilot finished work on behalf of L03TJ3 July 8, 2026 19:27
Copilot AI requested a review from L03TJ3 July 8, 2026 19:27
@L03TJ3

L03TJ3 commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

@copilot Please read below review thoroughly and follow up on each point.
its not done until all points are addresses/can be checked off (or reasonable feedback/open-ended question is raised).
don't invent workarounds when instruction does not match reality of local widget / external smart-contract.

pull-request 299 is referring to this: GoodDollar/GoodProtocol#299

Follow-up: GovernanceWidget first-pass fix (v2)

Update GoodWidget PR #77 so its runtime is contract-correct, maintainable, and free of production mock data.

Work only in the governance-widget package, its stories, and its tests. Keep the existing visual design unless a real loading, empty, error, or transaction state requires different copy.

1. Make the package build and establish clean boundaries

  • Add viem as a direct @goodwidget/governance-widget dependency.
  • Replace the handwritten GoodDaoHouses ABI with the final PR #299 ABI. Include the complete MemberRecord, VoteConfig, flowSplitterConfig, and HoaEligibilityRecord shapes.
  • Add mapper tests using tuples that match the real ABI.
  • Refactor useGovernanceAdapter into a thin composition hook. Keep these concerns separate:
    • contract reads and mappers;
    • membership/onboarding transactions;
    • voting state and actions;
    • Superfluid funding reads.
  • Do not create trivial one-line modules or move contract logic into UI components.

Checkpoint: the package builds declarations and ABI/mapping tests pass.

2. Fix membership and onboarding

  • Store both house minimum stakes as raw bigint values. Derive labels only for display.
  • Selecting a house must update both the displayed stake and the raw amount submitted.
  • Read getHoaEligibility(account). Enable HoA signup only when isEligible is true; do not use GoodID as the HoA eligibility check.
  • Keep GoodID verification as its own onboarding requirement and provide an actionable verification button.
  • Register through G$ transferAndCall and wait for the transaction receipt before showing success.
  • Restake an existing member through G$ transferAndCall(houses, amount, '0x'), unless the final contract explicitly requires approval plus stake.
  • Show clear wallet-confirmation, submitted, confirmed, rejected, and reverted states.

Checkpoint: an eligible HoA wallet and a Citizen wallet can complete their correct mocked-RPC onboarding paths, and failed receipts never show success.

3. Replace mock voting with contract-derived states

Read:

  • isVotingPeriod
  • getCurrentVoteId
  • getVoteConfig
  • getVoteRecipients
  • getActiveMembers(House.Alignment)
  • getHasVoted
  • getFinalizedUnits

Then implement:

  • Closed window: show Upcoming Alignment vote using the contract schedule.
  • No active HoA recipients: show No House of Alignment members have been assigned yet. Voting will open shortly.
  • Open window: use real recipient addresses. Before the first ballot creates a recipient snapshot, use current active HoA members as the provisional list.
  • Allow eligible active members of both houses to vote. Alignment Voting allocates to HoA recipients; it is not restricted to HoA voters.
  • For Citizens, use the GoodID root when reading duplicate-vote status.
  • Require allocations to total exactly 10,000 basis points.
  • After a vote, show the already-voted state and do not offer ballot editing.
  • After execution, show finalized units as read-only data.
  • Remove runtime mock vote IDs, recipients, labels, and percentages. Storybook may inject clearly labelled fixture data.

Checkpoint: every voting state is derived from mocked contract responses, and submitted recipients are valid addresses.

4. Add live “funding received so far”

  1. Read flowSplitterConfig from GoodDaoHouses and use poolAddress as the Superfluid stream receiver.

  2. Query https://subgraph-endpoints.superfluid.dev/celo-mainnet/protocol-v1 for G$ streams matching that receiver and the G$ Super Token.

  3. Paginate with first: 1000 and increasing skip until the returned page contains fewer than 1000 rows.

  4. Calculate every stream’s cumulative amount with bigint arithmetic:

    streamedUntilUpdatedAt + currentFlowRate * max(0, now - updatedAtTimestamp)

  5. Sum all stream amounts and format the result with 18 decimals.

  6. Refresh the calculated total while the screen is open.

Use this exact query:

query FundingStreams($receiver: String!, $token: String!, $first: Int!, $skip: Int!) {
  streams(
    first: $first
    skip: $skip
    where: { receiver: $receiver, token: $token }
  ) {
    sender { id }
    currentFlowRate
    streamedUntilUpdatedAt
    updatedAtTimestamp
  }
}
  • Show loading, empty, and unavailable/error states.
  • Do not use a fake pool address or infer money amounts from vote units.
  • Do not invent a project-allocation breakdown from inbound streams. Show the live total without a breakdown until an outgoing-distribution data source exists.
  • Storybook may receive clearly labelled mock funding props for visual QA only.

Checkpoint: subgraph fixtures cover active, stopped, multiple, empty, paginated, and failed stream queries.

5. Finish QA and evidence

  • Add focused tests for house stake selection, HoA eligibility, identity action, transaction receipts, restaking, both-house voting eligibility, address mapping, 10,000-bps validation, and funding aggregation.
  • Keep Storybook states for disconnected, loading, onboarding, pending, active, upcoming vote, empty recipients, open vote, already voted, executed vote, funding unavailable, unsupported chain, restake, and friendly errors.
  • Exercise the real adapter through mocked RPC/subgraph responses; static injected-state stories are not sufficient on their own.
  • Keep transient Playwright output uncommitted. Put intentional canonical screenshots under the Storybook governance-widget screenshots folder.

Run:

pnpm install
pnpm build
pnpm lint
pnpm test:demo tests/widgets/governance-widget

Document unrelated root lint failures instead of changing unrelated packages.

Done when

  • The governance-widget package builds from a clean install.
  • Runtime data is contract/subgraph-derived or shown as loading, empty, or unavailable—never silently replaced with fixtures.
  • Registration, restaking, and voting wait for and reflect real transaction outcomes.
  • The adapter has clear maintainable boundaries.
  • The affected governance-widget tests pass with reproducible evidence.

Co-authored-by: L03TJ3 <6606028+L03TJ3@users.noreply.github.com>

Copilot AI commented Jul 13, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Please read below review thoroughly and follow up on each point.
its not done until all points are addresses/can be checked off (or reasonable feedback/open-ended question is raised).
don't...

Addressed in 55ba33a. Updated the governance-widget runtime to use the final GoodDaoHouses ABI/mappers, split contract/transaction/voting/funding concerns, use HoA eligibility separately from GoodID, wait for transferAndCall receipts for registration/restake, derive voting/funding from contract/subgraph data, and added focused mapper/transaction/funding tests plus refreshed affected screenshots. Validation: pnpm build, pnpm --filter @goodwidget/governance-widget lint, pnpm test:demo tests/widgets/governance-widget passed; root pnpm lint still fails only on pre-existing packages/embed/src/createMiniAppElement.tsx:94 unused _.

…99)

* feat(governance): finalize membership lifecycle

* fix(governance): harden transaction lifecycle (#80)

Guard registration, unstake, and voting receipts by wallet scope and prevent duplicate submissions. Enforce current house stake thresholds and chain-time locks, expand real-adapter coverage, and stabilize screenshot evidence.

* fix(governance): address review feedback (#80)

* fix(governance): remove obsolete HoA eligibility gate (#80)
@L03TJ3
L03TJ3 deployed to internal August 17, 2026 12:30 — with GitHub Actions Active

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.

Pull request overview

This PR introduces a production-style runtime boundary for @goodwidget/governance-widget that wires the GovernanceWidget to GoodDaoHouses contracts (via viem + SDK helpers), while keeping the widget mockable for Storybook and testable via Playwright.

Changes:

  • Added a governance runtime adapter layer (contract address resolution, reads/mappers, transactions, identity verification link generation, and Superfluid funding aggregation).
  • Added an app-level GovernanceWidget composed of runtime-aware states (onboarding/membership/voting/funding/unstake, including transaction state handling and guarded single-flight transactions).
  • Expanded QA coverage with Storybook runtime fixtures plus Playwright runtime + adapter-logic tests and deterministic screenshot capture.

Reviewed changes

Copilot reviewed 32 out of 80 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/widgets/governance-widget/runtime.spec.ts Adds end-to-end runtime smoke coverage over Storybook runtime fixtures, including RPC/subgraph mocking and screenshots.
tests/widgets/governance-widget/onboarding.spec.ts Updates onboarding Playwright tests for new copy/flow controls and more deterministic screenshots (animations disabled + retries).
tests/widgets/governance-widget/adapter-logic.spec.ts Adds Playwright-run logic tests for mappers, receipt handling, vote validation, funding aggregation, and membership/voting edge cases.
pnpm-lock.yaml Locks new governance-widget dependencies (@goodsdks/citizen-sdk, viem).
packages/governance-widget/src/widgetRuntimeContract.ts Defines the public adapter state/actions contract for the runtime widget boundary.
packages/governance-widget/src/types.ts Extends onboarding + funding props to support house-specific stake labels and identity verification callbacks.
packages/governance-widget/src/sdks/transactions.ts Implements receipt-aware membership/vote transaction helpers (transferAndCall, unstake, castVote).
packages/governance-widget/src/sdks/identity.ts Adds GoodID SDK wrapper + verification link helper.
packages/governance-widget/src/sdks/funding.ts Implements Superfluid subgraph pagination + bigint funding aggregation and formatting.
packages/governance-widget/src/sdks/contracts.ts Adds contract ABIs, address resolution, mappers, receipt helper, and Celo switch helper.
packages/governance-widget/src/sdks/contractReads.ts Implements membership/schedule/vote/flow config reads and vote window derivation.
packages/governance-widget/src/onboarding/steps/WelcomeStepContent.tsx Wires identity verification CTA callback into the welcome step.
packages/governance-widget/src/onboarding/steps/StakeStepContent.tsx Adjusts stake step layout to match updated shell copy and simplified header.
packages/governance-widget/src/onboarding/steps/ProfileStepContent.tsx Removes a now-obsolete CTA comment.
packages/governance-widget/src/onboarding/steps/HouseStepContent.tsx Moves to per-house stake labels and removes disabled-house behavior.
packages/governance-widget/src/onboarding/OnboardingIdentityCard.tsx Adds a dedicated “Verify with GoodID” CTA when unverified.
packages/governance-widget/src/onboarding/HouseSelectionCard.tsx Simplifies UI (removes disabled + “Selected” badge) and adjusts heading level.
packages/governance-widget/src/onboarding/GovernanceOnboardingFlow.tsx Adds runtime callbacks (house change/profile submit/identity verify), updates copy, and gates “Continue to success” until steps complete.
packages/governance-widget/src/onboarding/copy.ts Updates per-house labels used in selection UI.
packages/governance-widget/src/index.ts Exports GovernanceWidget, adapter contract types, and SDK helpers publicly.
packages/governance-widget/src/hooks/useGovernanceVoting.ts Adds voting state derivation, ballot validation, guarded vote submission, and schedule-based labels.
packages/governance-widget/src/hooks/useGovernanceTransactionGuard.ts Adds single-flight transaction guard keyed by account/chain/contract scope.
packages/governance-widget/src/hooks/useGovernanceMembership.ts Adds membership runtime reads, onboarding state, registration/unstake flows, and identity verification start logic.
packages/governance-widget/src/hooks/useGovernanceFunding.ts Adds funding runtime state + periodic refresh behavior backed by subgraph reads.
packages/governance-widget/src/GovernanceWidget.tsx Adds the app-level runtime widget UI that routes between runtime states and composes dashboard/onboarding/vote detail.
packages/governance-widget/src/GovernanceOnboardingWidget.tsx Updates onboarding widget prop plumbing for house stake labels and runtime callbacks.
packages/governance-widget/src/FundingDistributionChart.tsx Adds optional stateLabel rendering to explain funding refresh/availability states.
packages/governance-widget/src/adapter.ts Implements useGovernanceAdapter composing membership/voting/funding hooks into a single adapter contract.
packages/governance-widget/package.json Adds @goodsdks/citizen-sdk and viem as runtime dependencies.
examples/storybook/src/stories/governance-widget/GovernanceRuntime.stories.tsx Adds runtime fixture stories covering disconnected/loading/onboarding/active/voting/funding/unstake/error states.
examples/storybook/src/stories/governance-widget/GovernanceOnboarding.stories.tsx Tightens story frame typing/layout and sets initial house for interactive onboarding story.
examples/storybook/src/fixtures/governanceRuntimeMock.ts Adds an RPC-read mock encoder used by runtime Playwright tests.
AGENTS.md Updates QA summary to reflect tracked per-widget Playwright screenshot output location.
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +344 to +347
onboardingStepId: 'stake',
profileDraft,
transactionSteps: createTransactionSteps('failed', error),
transaction: { kind: 'registration', status: 'failed', hash: null, error },
Comment on lines +139 to +147
function readConfiguredAddress(key: keyof GovernanceEnvironmentConfig, envNames: string[]): Address | undefined {
const runtimeGlobal = globalThis as RuntimeGlobal
const explicitAddress = runtimeGlobal.__GOODWIDGET_GOVERNANCE__?.[key]
if (explicitAddress) return explicitAddress

const publicEnv = runtimeGlobal.process?.env
const configuredValue = envNames.map((envName) => publicEnv?.[envName]).find(Boolean)
return configuredValue as Address | undefined
}
Comment on lines +82 to +93
publicClient.readContract({
address: housesAddress,
abi: GOODDAO_HOUSES_ABI,
functionName: 'getActiveMembers',
args: [houseToContractValue('citizenship')],
}),
publicClient.readContract({
address: housesAddress,
abi: GOODDAO_HOUSES_ABI,
functionName: 'getActiveMembers',
args: [houseToContractValue('alignment')],
}),
Comment on lines +188 to +212
if (rawRecipients.length === 0 && isVotingPeriod && voteStartTime) {
// Before the first ballot creates the on-chain snapshot, mirror the
// contract rule so late-joining HoA members are never submitted.
const provisionalRecords = await Promise.all(
activeAlignment.map(async (recipient) => ({
recipient,
member: mapMemberRecord(
await publicClient.readContract({
address: housesAddress,
abi: GOODDAO_HOUSES_ABI,
functionName: 'getMember',
args: [recipient],
}),
),
})),
)
recipients = provisionalRecords
.filter(({ member }) =>
member.status === 'active' &&
member.house === 'alignment' &&
member.joinedAt !== null &&
member.joinedAt <= voteStartTime,
)
.map(({ recipient }) => recipient)
}
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.

[PLAN] Wire GovernanceWidget functionality to GoodDaoHouses

4 participants