Skip to content

fix: phase-one wallet hardening integration - #55

Open
thomas-kroes wants to merge 23 commits into
mainfrom
codex/phase1-fee-sidepanel-integration
Open

fix: phase-one wallet hardening integration#55
thomas-kroes wants to merge 23 commits into
mainfrom
codex/phase1-fee-sidepanel-integration

Conversation

@thomas-kroes

Copy link
Copy Markdown
Contributor

Summary

  • Integrate the reviewed side-panel/default-lock hardening from feat: popup / side panel display mode toggle #51 with the public fee-estimation work from Feat/public fee estimation #52.
  • Default every missing display-mode preference, including upgrades from versions that did not store the key, to the side panel; preserve every explicit stored preference thereafter.
  • Default every missing auto-lock preference to 10 minutes, including upgrades; preserve an explicitly stored 0 as Never.
  • Restore serializable approval state safely across service-worker restarts while excluding raw WASM requests, promoting queued requests, and revalidating origin/account/liveness before approval.
  • Keep dApp-supplied fees exact. Treat wallet-generated fees as advisory, explicitly disclose that they may change, and retry an underfunded advisory build once with the remaining locally available notes.
  • Reconcile note reservations, wallet history, fee, and change to the inputs and fee WASM actually built.
  • Bind raw-transaction approval and post-sign verification to a stable witnessless transaction-intent hash. The raw transaction ID is still checked before signing, but is not incorrectly expected to remain unchanged after witness signatures are attached.

Review scope

This is the phase-one release integration artifact and supersedes merging #51 and #52 independently. It is intentionally a draft: do not merge before the planned human review and cross-repository release ordering are complete.

Validation

  • npm run format:check
  • npm run typecheck
  • npm test — 24 tests, including approval restoration/invalidation and advisory-fee retry/reconciliation coverage
  • npm run build
  • production dependency audit — zero findings

The transaction-intent invariant is also covered in nockbox/iris-rs#29: signing preserves the witnessless spends hash while legitimately changing the raw transaction ID.

Manual acceptance checklist

  • Existing install with no display-mode key upgrades to side panel; switching to popup persists across worker/extension restarts
  • Missing auto-lock preference defaults to 10 minutes; explicitly selecting Never persists
  • Estimated-fee approval clearly states that the final network fee may differ
  • Advisory fee drift can reserve additional local notes and rebuild once; exact-fee requests never retry or change fee
  • Retry failure releases all reservations, and successful retry records only the inputs WASM actually used
  • Raw signing approval succeeds when only witness signatures change and rejects any changed transaction intent
  • Existing vault upgrade, keyfile export/import, seed copy, and HTTP/HTTPS dApp flows remain functional

thomas-kroes and others added 23 commits June 10, 2026 15:03
Let users choose between the toolbar pop-up and Chrome side panel via
Settings > Display mode. Side panel reuses the same React app with fluid
layout; dApp approvals route to the panel with popup-window fallback.

Co-authored-by: Cursor <cursoragent@cursor.com>
When display mode is side panel, always notify the panel and never fall
back to approval popup windows if sidePanel.open() fails.

Co-authored-by: Cursor <cursoragent@cursor.com>
Covers the case where an approval arrived while the panel was hidden or
the runtime message was missed before the panel remounted.

Co-authored-by: Cursor <cursoragent@cursor.com>
Open the side panel on the user-gesture chain before provider requests
that may need approval. Persist connect/sign/tx pending state to
chrome.storage.session so the side panel can restore after SW restarts.
Also restyle the display mode settings icon to match other settings icons.

Co-authored-by: Cursor <cursoragent@cursor.com>
Use the same solid/hollow evenodd split as the theme icon — a window
frame with a cut-out side panel — instead of two thin filled blocks.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep fluid w-full h-full layout on SendReviewScreen from the side panel work.

Co-authored-by: Cursor <cursoragent@cursor.com>
Exposes the wallet's existing internal fee estimation
(wallet:estimateTransactionFee -> vault.estimateTransactionFee, WASM
auto-calc) as a public dApp-callable provider method, so dApps can show
the required fee without duplicating transaction-building logic.

- Register nock_estimateTransactionFee in PROVIDER_METHODS (defined
  locally until @nockbox/iris-sdk >= 0.3.0 is published) and
  isProviderMethod()
- New background handler: gated on approved origin + unlocked vault
  (read-only, no approval popup, same gating as nock_getWalletInfo);
  validates params and returns { fee } in canonical nicks (string)
…mation

Previously, omitting fee in nock_sendTransaction failed with 'Missing
fee', forcing dApps to ask users for a fee or duplicate wallet/WASM
transaction-building logic.

Now, when a dApp omits fee:
- The background estimates it via vault.estimateTransactionFee before
  showing the approval popup (estimation failure rejects the request
  up front with -32603, no dangling pending request)
- The approval popup labels the fee as '(estimated)'
- On approval, undefined is passed to vault.sendTransactionV2 so WASM
  auto-calculates the exact fee at build time, eliminating the
  'Insufficient fee' late-failure for this path
- The dApp response reports the actual fee used (walletTx.fee)

Explicitly-provided fees keep the existing behavior verbatim: parsed
with allowZero, respected as-is, and echoed back in the response.
For omitted-fee nock_sendTransaction, approval now passes the wallet's
fresh estimate as the fee (matching the popup send flow) instead of
undefined. The undefined branch in sendTransactionV2 reserves a
2-NOCK placeholder for note selection, so an account that could afford
amount + estimate but not amount + 2 NOCK failed at approval with
'Insufficient available funds'. Passing the concrete estimate sizes
note selection to the fee actually shown and charged.

Also drops the '~' prefix on the popup fee since the displayed value is
now applied verbatim rather than approximated.

Addresses review feedback (P2) on PR #52.
Fixes the failing typecheck-and-format CI check.

Co-authored-by: Cursor <cursoragent@cursor.com>
chrome.sidePanel and chrome.tabs are unavailable in content scripts, so
the previous content-script open call never ran. Open the panel
synchronously in the onMessage listener instead, where Chrome preserves
the dApp click gesture (any await consumes it), using an in-memory
display mode cache.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Replace the 15 numbered wallet icons with a new 29-icon pack: 5 kept
  classics (styles 1, 2, 3, 8, 14 - default unchanged) plus 24 new
  iris-themed icons, normalised to the shared tintable-SVG convention
  (var(--fill-0) placeholder, container-sized root).
- Add shared/walletStyles.ts as the single source of truth: icon
  registry with visual families (picker groups similar icons together),
  a 17-colour palette (7 existing + 10 new in the same poppy scheme),
  and a deterministic assignment sequence that round-robins across
  icon families and strides the colour rainbow so consecutive wallets
  always look distinct; combinations only repeat after all 493 are used.
- Switch persisted iconStyleId to stable string ids with transparent
  migration of legacy numeric ids (retired styles fall back to default).
- Drive AccountIcon and WalletStylingScreen from the shared registry.

https://claude.ai/code/session_01EPxCTHkLN8QM5iuNR5qqrn
feat: replace wallet icon pack and rework style assignment logic
@thomas-kroes
thomas-kroes marked this pull request as ready for review July 31, 2026 12:00
@thomas-kroes

Copy link
Copy Markdown
Contributor Author

@greptile-apps

@greptile-apps

greptile-apps Bot commented Jul 31, 2026

Copy link
Copy Markdown

Greptile Summary

This PR integrates wallet hardening and fee-estimation behavior across the extension.

  • Defaults missing display-mode preferences to the side panel and missing auto-lock preferences to ten minutes while preserving explicit settings.
  • Adds restart-safe approval snapshots, requester/account validation, and side-panel approval routing.
  • Adds advisory fee estimation, one-time underfunded-build retry, and reconciliation against the transaction actually built.
  • Verifies raw-transaction approvals with stable witnessless transaction-intent hashes.
  • Expands CI and automated coverage for approval restoration, side-panel behavior, RPC methods, and fee reconciliation.

Confidence Score: 5/5

The PR appears safe to merge from the reviewed code, with no concrete blocking or independently actionable non-blocking defect identified.

The changed approval, transaction-building, reservation-cleanup, origin-validation, and settings-migration paths retain their required guards and reconcile persisted state with the transaction actually built.

Important Files Changed

Filename Overview
extension/background/index.ts Integrates display-mode routing, approval persistence and validation, advisory-fee handling, and hardened raw-transaction approval.
extension/shared/vault.ts Adds transaction-intent verification and reconciles reservations, fees, inputs, change, and history with the transaction produced by WASM.
extension/shared/transaction-fee.ts Introduces bounded advisory-fee retry and strict reconciliation helpers for built transaction inputs and amounts.
extension/shared/pending-approval-state.ts Adds serializable pending-approval snapshots with filtering, expiration handling, and queue promotion.
extension/content/index.ts Hardens the page-to-extension message envelope and supplies authoritative extension-side display context.
extension/popup/hooks/useApprovalDetection.ts Updates approval discovery and routing to support both popup and side-panel surfaces.
extension/shared/constants.ts Defines display-mode, auto-lock, runtime-message, and approval-related constants used by the integrated hardening flow.
package.json Adds the Vitest-based test command and development dependency.
.github/workflows/ci.yml Runs the test suite as part of the required CI workflow.

Sequence Diagram

sequenceDiagram
    participant D as dApp
    participant B as Background worker
    participant U as Approval UI
    participant V as Vault/WASM
    participant N as Network
    D->>B: Provider transaction request
    B->>V: Estimate advisory fee when omitted
    B->>U: Display approval request
    U->>B: Approve
    B->>B: Revalidate origin, account, and requester
    B->>V: Reserve notes and build transaction
    alt Advisory fee is underfunded
        B->>V: Reserve remaining available notes
        B->>V: Retry build once
    end
    V-->>B: Actual inputs, fee, and change
    B->>N: Broadcast built transaction
    B->>V: Reconcile reservations and history
    B-->>D: Transaction result
Loading

Reviews (1): Last reviewed commit: "fix: harden advisory fees and raw signin..." | Re-trigger Greptile

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f9a62b42ec

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

method === PROVIDER_METHODS.SEND_TRANSACTION ||
method === PROVIDER_METHODS.GET_WALLET_INFO ||
method === PROVIDER_METHODS.SIGN_TX ||
method === PROVIDER_METHODS.ESTIMATE_TRANSACTION_FEE ||

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Bypass SDK mapping for the locally added fee method

When a dApp calls nock_estimateTransactionFee without an api field—the supported default-provider request shape—resolveSourceApiVersion treats it as API 0 and this classification sends it through mapRpcRequest from @nockbox/iris-sdk 0.2.0. That SDK predates this locally added method, so the request is rejected before reaching the new switch handler; the outgoing bridge repeats the same unsupported mapping. Special-case this method as a pass-through, or provide explicit request/response mappings until the SDK is upgraded.

Useful? React with 👍 / 👎.

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.

2 participants