Skip to content

feat(maturity): allow disbursing to an address book entry - #395

Merged
yhabib merged 6 commits into
mainfrom
feat/disburse-maturity-address-book
Jul 1, 2026
Merged

yhabib merged 6 commits into
mainfrom
feat/disburse-maturity-address-book

Conversation

@yhabib

@yhabib yhabib commented May 28, 2026 •

Copy link
Copy Markdown
Collaborator

Motivation

Disburse maturity only targeted the user's own accounts or subaccounts. The address book is already wired into the Send ICP flow, so reusing it here lets users disburse to any saved destination without retyping addresses.

Changes

  • Widened the useDisburseMaturity hook to accept either an ICP account identifier or an ICRC-1 account (principal + optional subaccount) as the destination.
  • Routed ICP entries through toAccountIdentifier and ICRC-1 entries through the structured toAccount param on the governance canister call.
  • Added an opt-in "Use address book" toggle to the disburse-maturity modal; the account picker stays the default action and the toggle is off on open.
  • Decoded ICRC-1 address-book entries on confirm, guarded so a malformed entry shows a validation error instead of crashing the modal.
  • Showed a read-only main-account destination when subaccounts are disabled, and kept an "open address book" settings link when the address book is empty.
  • Disabled the Disburse button while the address book is still loading.
  • Normalized the ICRC-1 subaccount once so the forwarded destination and the balance-invalidation query key stay in sync.
  • Added noDestination and invalidDestination error strings.

@zeropath-ai

zeropath-ai Bot commented May 28, 2026

Copy link
Copy Markdown

✅ No security or compliance issues detected. Reviewed everything up to 1fb0432.

Security Overview
Detected Code Changes
Change Type Relevant files
Enhancement ► src/governance-app-frontend/src/features/stakes/components/DisburseMaturityModal.tsx
    Add Address Book integration for destination selection.
    Implement switch to toggle between AccountSelect and AddressBookSelect.
    Update mutation logic to handle different destination types.
► src/governance-app-frontend/src/features/stakes/hooks/useDisburseMaturity.ts
    Add type for disburse maturity destination (ICP and ICRC1).
    Update mutation parameters to accept a destination object.
    Implement logic to resolve destination account identifier for both ICP and ICRC1.
    Modify governance canister call to support ICRC1 destination.
► src/governance-app-frontend/src/i18n/en/modals/neuronDetail.json
    Add translation for "noDestination" error message.
Refactor ► src/governance-app-frontend/src/features/stakes/components/DisburseMaturityModal.tsx
    Consolidate destination selection logic.
    Simplify state management for destination selection.

@yhabib yhabib changed the title feat(disburse-maturity): allow disbursing to an address book entry DRAFT: \feat(disburse-maturity): allow disbursing to an address book entry May 28, 2026
@yhabib yhabib changed the title DRAFT: \feat(disburse-maturity): allow disbursing to an address book entry feat(disburse-maturity): allow disbursing to an address book entry Jun 9, 2026
Lets a neuron's available maturity be disbursed to any saved address
in the user's address book, in addition to the existing "my accounts"
flow. ICP entries pass through `toAccountIdentifier`; ICRC-1 entries
are decoded and passed through `toAccount` (principal + subaccount).

UX mirrors the Send ICP toggle: when the address book has entries,
the modal defaults to the address-book picker; users can flip back
to their own subaccounts at any time.
@yhabib
yhabib force-pushed the feat/disburse-maturity-address-book branch from 1fb0432 to fd10a25 Compare June 9, 2026 12:20
@github-actions

github-actions Bot commented Jun 9, 2026 •

Copy link
Copy Markdown

📊 Build Bundle Stats

The latest build generated the following assets:

dist/index.html                                           2.08 kB │ gzip:   0.72 kB
dist/assets/index-BxgF3HlS.css                          133.97 kB │ gzip:  21.03 kB
dist/assets/externalServices-CK4eoRia.js                  0.19 kB │ gzip:   0.16 kB
dist/assets/address-C-4H442a.js                           0.20 kB │ gzip:   0.15 kB
dist/assets/Skeleton-WHeowStZ.js                          0.43 kB │ gzip:   0.32 kB
dist/assets/useTvlValue-CaiaZRMj.js                       0.57 kB │ gzip:   0.39 kB
dist/assets/numbers-CQnY2h6o.js                           0.58 kB │ gzip:   0.36 kB
dist/assets/service-BbxpOLFn.js                           0.59 kB │ gzip:   0.37 kB
dist/assets/Spinner-L1I9w2yZ.js                           0.59 kB │ gzip:   0.41 kB
dist/assets/PageHeader-X0rvreRR.js                        0.77 kB │ gzip:   0.45 kB
dist/assets/CertifiedBadge-BR8eME7Q.js                    0.81 kB │ gzip:   0.48 kB
dist/assets/Separator-Cbsboy1g.js                         0.83 kB │ gzip:   0.50 kB
dist/assets/events-BGJ2aHTc.js                            0.91 kB │ gzip:   0.33 kB
dist/assets/useIcpIndex-BPYuk8V5.js                       1.07 kB │ gzip:   0.63 kB
dist/assets/rolldown-runtime-CMxvf4Kt.js                  1.21 kB │ gzip:   0.67 kB
dist/assets/addressBook-D-FHCqdB.js                       1.66 kB │ gzip:   0.99 kB
dist/assets/useCommandPaletteSettings-D4dkTH7L.js         1.73 kB │ gzip:   0.86 kB
dist/assets/useGovernanceAppCanister-DbpNkQEk.js          1.91 kB │ gzip:   0.96 kB
dist/assets/AnimatedNumber-BUW9aN7Y.js                    1.96 kB │ gzip:   1.12 kB
dist/assets/useIcpIndexTransactionsPolling-Di0XkOYB.js    2.03 kB │ gzip:   1.09 kB
dist/assets/tickers-CEov172o.js                           3.10 kB │ gzip:   1.48 kB
dist/assets/ToggleGroup-BB6latDC.js                       3.16 kB │ gzip:   1.41 kB
dist/assets/Switch-rvrAg9H_.js                            3.23 kB │ gzip:   1.45 kB
dist/assets/SensitiveValue-BQhvywNG.js                    7.34 kB │ gzip:   3.29 kB
dist/assets/badge-BCWkEndq.js                             8.07 kB │ gzip:   2.34 kB
dist/assets/spamFilter-D0dZ_bjZ.js                        8.54 kB │ gzip:   3.80 kB
dist/assets/routes-CuIWrKld.js                            8.92 kB │ gzip:   3.38 kB
dist/assets/TopicFollowingAccordion-DgYgQ_Je.js           9.34 kB │ gzip:   3.81 kB
dist/assets/MutationDialog-CSWY8lLj.js                    9.55 kB │ gzip:   3.44 kB
dist/assets/_id-MrGhvGfk.js                              14.33 kB │ gzip:   4.30 kB
dist/assets/_auth-CU0vFTX_.js                            15.57 kB │ gzip:   5.73 kB
dist/assets/accounts-DcikMfvA.js                         23.71 kB │ gzip:   8.18 kB
dist/assets/GetTokens-6ch_6lzJ.js                        39.20 kB │ gzip:  13.99 kB
dist/assets/settings-BiiExlbv.js                         42.54 kB │ gzip:  12.22 kB
dist/assets/dashboard-DiRDsyPI.js                        50.62 kB │ gzip:  15.04 kB
dist/assets/button-v0HtDCA3.js                           53.50 kB │ gzip:  18.67 kB
dist/assets/neurons-qf7HeVDV.js                          67.06 kB │ gzip:  20.09 kB
dist/assets/neuronDetail-CHXmNlPj.js                     70.37 kB │ gzip:  21.05 kB
dist/assets/voting-Bzl9wNrW.js                           70.80 kB │ gzip:  21.40 kB
dist/assets/vendor-md-DL0JfF_R.js                        73.29 kB │ gzip:  19.98 kB
dist/assets/index-BDJrNTXS.js                            73.56 kB │ gzip:  22.87 kB
dist/assets/vendor-tanstack-BZKtD_S5.js                 161.15 kB │ gzip:  49.35 kB
dist/assets/vendor-core-react-qLCIanUQ.js               189.81 kB │ gzip:  59.76 kB
dist/assets/vendor-recharts-Ck18_gYq.js                 223.45 kB │ gzip:  64.01 kB
dist/assets/vendor-icp-DP4ARddz.js                      411.37 kB │ gzip: 104.08 kB
dist/assets/vendor-libs-B2aYRUFu.js                     553.60 kB │ gzip: 180.31 kB

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 extends the neuron “Disburse maturity” flow to support selecting a destination from the user’s address book, enabling disbursement to either an ICP account identifier or an ICRC-1 account (principal + optional subaccount).

Changes:

  • Expanded useDisburseMaturity to accept a typed destination (icp vs icrc1) and route the governance call accordingly.
  • Added an address-book toggle + selector to DisburseMaturityModal, including auto-toggle behavior and an empty-state link to settings.
  • Introduced a new validation error string for the “toggle on but no destination selected” case.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
src/governance-app-frontend/src/i18n/en/modals/neuronDetail.json Adds a new validation error string for missing destination selection.
src/governance-app-frontend/src/features/stakes/hooks/useDisburseMaturity.ts Adds destination typing, routes governance call based on destination kind, and invalidates balance cache for resolved destination.
src/governance-app-frontend/src/features/stakes/components/DisburseMaturityModal.tsx Adds address-book-based destination selection UI and confirm-time decoding for ICRC-1 entries.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@yhabib yhabib changed the title feat(disburse-maturity): allow disbursing to an address book entry feat(maturity): allow disbursing to an address book entry Jul 1, 2026
yhabib added 4 commits July 1, 2026 11:07
When the subaccounts advanced feature is disabled, turning the address
book toggle off left the destination section blank and silently
disbursed to the main account. Render a read-only main-account field in
that case so the destination is always visible.
Prevent confirming before the address book finishes loading and the
auto-toggle engages, which would otherwise disburse to the main account
instead of the intended saved destination.
…book opt-in

Drop the auto-on toggle so the account/main-account picker stays the
primary action; the address book is now opt-in via the toggle. Disburse
is still blocked until the address book finishes loading.
Wrap decodeIcrcAccount in the confirm handler so a malformed address book
entry surfaces a validation error instead of crashing the modal. Normalize
the ICRC subaccount once (32-byte guard) so the forwarded destination and
the balance-invalidation key stay consistent.

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

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

@yhabib
yhabib marked this pull request as ready for review July 1, 2026 10:00
@yhabib
yhabib requested a review from a team as a code owner July 1, 2026 10:00
@zeropath-ai

zeropath-ai Bot commented Jul 1, 2026 •

Copy link
Copy Markdown

✅ No security or compliance issues detected. Reviewed everything up to dcb8e0c.

Security Overview
Detected Code Changes
Change Type Relevant files
Enhancement ► src/governance-app-frontend/src/features/stakes/components/DisburseMaturityModal.tsx
      Implement address book destination option with toggle and main account fallback
► src/governance-app-frontend/src/features/stakes/hooks/useDisburseMaturity.ts
      Add DisburseMaturityDestination type and destination resolution logic
Enhancement ► src/governance-app-frontend/src/i18n/en/modals/neuronDetail.json
      Add error messages for no destination and invalid destination

Drop the showDestinationSection gate so the destination is always shown:
the main-account read-only field and the empty-address-book settings link
now appear even when subaccounts are disabled and the address book is empty.
@yhabib
yhabib added this pull request to the merge queue Jul 1, 2026
Merged via the queue into main with commit d4a9091 Jul 1, 2026
12 checks passed
@yhabib
yhabib deleted the feat/disburse-maturity-address-book branch July 1, 2026 12:00
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.

3 participants