Skip to content

feat(treasury): approval/rejection voting UI for multisig proposals (#132)#255

Open
Jaydams wants to merge 1 commit into
codebestia:mainfrom
Jaydams:approval-rejection-voting-ui
Open

feat(treasury): approval/rejection voting UI for multisig proposals (#132)#255
Jaydams wants to merge 1 commit into
codebestia:mainfrom
Jaydams:approval-rejection-voting-ui

Conversation

@Jaydams

@Jaydams Jaydams commented Jun 27, 2026

Copy link
Copy Markdown

Closes #132 — builds the full approval/rejection voting flow for multisig
treasury proposals, from the database layer through the API to the UI.

Backend

  • Schema (apps/backend/src/db/schema.ts): extended treasury_proposals
    with recipient, amount, token, and threshold columns so proposal
    cards can render useful detail; added proposal_vote_type enum and a new
    proposal_votes table (unique on (treasury_proposal_id, user_id)) that
    records each signer's vote and optional Freighter signature; added Drizzle
    relations for both tables.

  • Migration (drizzle/0008_treasury_multisig_voting.sql): creates the
    treasury_proposals table (first migration for it), adds the four new
    columns, and creates proposal_votes with FK constraints and a unique
    partial index to prevent double-voting at the DB level.

  • Treasury router (src/routes/treasury.ts):

    • POST /treasury/propose — now persists proposals to the DB (was a stub
      returning TTL only); accepts optional conversationId and threshold.
    • GET /treasury/proposals?conversationId= — returns all proposals,
      optionally filtered by conversation; annotates each row with hasVoted
      and myVote for the authenticated user via a single IN-query on
      proposal_votes.
    • POST /treasury/proposals/:id/approve and .../reject — validates the
      proposal is still active, inserts a proposal_votes row, and returns
      409 on a unique-constraint violation (duplicate vote) or on an inactive
      proposal.

Frontend

  • ProposalCard component (src/components/treasury/ProposalCard.tsx):
    shows proposal ID, truncated recipient address, amount + token, a colour-coded
    status badge (Pending / Approved / Rejected / Executed / Expired), an
    approval progress bar (approvalsCount / threshold), and Approve/Reject
    buttons. Buttons are disabled when hasVoted is true or status !== "active".
    On click, Freighter signs "approve:<proposalId>" / "reject:<proposalId>"
    before submitting to the API; a toast is shown if signing is cancelled or the
    request fails.

  • Treasury page (src/app/app/treasury/page.tsx):

    • Fetches GET /treasury/proposals on mount (and after a new proposal is
      created via the modal).
    • Opens a Socket.IO connection and listens for treasury_proposal_updated
      events, patching status, approvalsCount, and rejectionsCount in local
      state without a full re-fetch.
    • Renders a responsive 1–3 column ProposalCard grid with skeleton loading
      and an empty state.
    • "Pending Transactions" summary card now reflects the live count of active
      proposals.

Test plan

  • POST /treasury/propose with a valid body → 201, proposal appears in
    GET /treasury/proposals
  • GET /treasury/proposals returns hasVoted: false / myVote: null
    before voting
  • Click Approve on a card → Freighter prompt appears → on confirm,
    button shows "Approved ✓", both buttons disable
  • Click Reject → same flow with "Rejected ✗"
  • Voting a second time → toast shows "Already voted on this proposal"
  • Approve/Reject on a non-active proposal → 409 with descriptive error
  • Cancel Freighter prompt → toast shows "Freighter signing was cancelled or
    failed", no API call made
  • Backend emits treasury_proposal_updated → treasury page updates counts
    in real time without manual refresh
  • "Pending Transactions" card count matches number of active proposals

…odebestia#132)

Add ProposalCard component, vote-recording API endpoints, per-user vote
tracking table, and real-time Socket.IO updates on the treasury page.
@drips-wave

drips-wave Bot commented Jun 27, 2026

Copy link
Copy Markdown

@Jaydams Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

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.

Build approval / rejection voting UI for multisig proposals

1 participant