0xMiden / 0xMiden/wallet

Feature: user-configurable spending limits (daily/weekly) with biometric/password confirmation

未关闭
#646 0 条评论 0 个 reaction 已指派 1 人 已被 @WiktorStarczewski 认领 在 GitHub 查看
enhancement
主要语言
TypeScript
星标
5
派生
28
平均合并
9 小时 50 分钟
30 天内合并 PR
123

描述

## Summary

Let users set **spending limits** — a daily and/or weekly cap on outgoing value — directly in the wallet, as a self-custody guardrail. When a transaction would push cumulative spend over the configured limit within the window, require an extra **biometric / password confirmation** to proceed (or block until the window resets). Changing or disabling a limit requires the same confirmation, so a briefly-unlocked session can't simply raise it.

## Motivation

- Guards against the two most common ways self-custody users lose funds: fat-finger mistakes, and a casual attacker who gets a briefly-unlocked session.
- Feature-parity expectation — most consumer wallets offer per-period limits.
- Complements the Guardian co-signer: a lightweight, always-on guardrail the user controls themselves, no second party required.

## Proposed behaviour

**Configuration** — a new **Settings → "Spending limits"** sub-screen:
- Enable/disable, and set a **daily** and/or **weekly** cap.
- Denomination: **per-asset native amount** as the robust default (see Open questions re: fiat).
- Enabling, raising, or disabling a limit requires a **step-up confirmation** (biometric on mobile, password on extension/desktop). Lowering a limit can be allowed without step-up (strictly safer) — TBD.

**Enforcement** — at send/swap/bridge/earn-deposit time:
- Before submitting an outgoing transaction, compute cumulative spend in the window; if this tx would exceed the limit, require the step-up confirmation to proceed. If the user can't/won't confirm, block with a clear message ("Daily limit reached — resets in Xh, or raise it in Settings").

## Security — please read

**This is a client-side UX guardrail, not a cryptographic limit.** The account's OpenZeppelin multisig / Guardian enforces **signature-count** thresholds per procedure (`openzeppelin::multisig::procedure_thresholds`) and has **no notion of transferred value** — there is no on-chain amount/limit policy today (`src/lib/miden/guardian/account.ts`, enforced during proof per `src/lib/miden/transaction/index.ts:1127`). Consequences that shape the design:

- The limit protects against mistakes and a casual attacker with a briefly-unlocked session. It does **not** stop a determined attacker who has the unlocked wallet + on-device keys (they can bypass the UI and drive the SDK directly).
- The check must therefore live at the **transaction-initiation chokepoint**, not just in the UI, and the step-up must gate **both** exceeding the limit **and** changing/disabling it — otherwise it's trivially bypassed.
- A **true, enforced** limit would need new account-component logic (a value-aware procedure/guardian policy) that doesn't exist in the current integration — see Out of scope.

## Suggested implementation (integration points)

- **Step-up confirmation:** reuse `confirmSensitiveAction(reason)` — `src/lib/biometric/index.ts:183`. It already gates send (`src/screens/send-flow/ReviewTransaction.tsx:209`) and swap (`src/screens/swap-flow/SwapManager.tsx:207`), and its own doc invites callers to "layer their own policy on top." Password-reconfirm pattern for the extension/desktop fallback: `src/app/templates/RevealSecret.tsx`.
- **Chokepoint (covers ALL spend flows):** add the limit check in the `initiate*Transaction` layer — `initiateSendTransaction` / `initiateSwapTransaction` / `initiateBridgedSendTransaction` / `initiateEarnDepositTransaction` in `src/lib/miden/transaction/initiate.ts` (each has a clean `amount: bigint` + `faucetId`). A **UI-only** step-up would miss dApp programmatic send (`src/lib/miden/back/dapp.ts:1260,1301`), earn (`src/lib/epoch/earn-note.ts`), and bridge (`src/lib/epoch/miden-note.ts`, `src/lib/agglayer/b2agg/index.ts`), none of which call `confirmSensitiveAction` today — centralizing at `initiate*` covers them (and correctly excludes incoming/auto-consume).
- **Spend aggregation:** sum `amount` over the `transactions` Dexie table where `type ∈ {send, swap, bridged-send, earn-deposit}` and `completedAt`/`initiatedAt` is within the window, grouped by `faucetId` (`src/lib/miden/repo.ts`; `ITransaction` in `src/lib/miden/db/types.ts`). Amounts are per-faucet native base units.
- **Fiat option:** a Binance price feed exists (`src/lib/prices/binance.ts`, surfaced as `token.fiatPrice`) for mapped tokens (MIDEN etc.), but unmapped/DEX tokens default to `$1` — a USD limit is only reliable for mapped tokens, so per-asset native limits are the safer primary design.
- **Settings storage:** `setSetting/getSetting` + `mirrorSetting` (so the extension service worker can read it) in `src/lib/settings/helpers.ts`; keys/defaults in `src/lib/settings/constants.ts`. `SettingToggle` is boolean-only, so this wants a small new sub-screen with numeric inputs rather than a toggle row.

## Open questions (need a decision)

1. **Denomination:** per-asset native amount (robust, all tokens) vs USD-equivalent (intuitive, only reliable for price-mapped tokens). Recommend native first; USD later.
2. **Window:** rolling 24h/7d vs calendar day/week (rolling is simpler and harder to game).
3. **On limit reached:** hard block until reset vs allow with mandatory step-up — i.e. speed-bump or wall? (The ask implies step-up-to-exceed.)
4. **Which flows count:** send, swap, bridged-send, earn-deposit — include earn-deposit (moving funds into a vault)? include dApp programmatic sends (recommend yes)?
5. **Cross-device / reinstall:** spend history + limit config are local; after a reinstall the running total resets. Acceptable, or reconstruct from on-chain history?
6. **Biometrics unavailable/disabled:** `confirmSensitiveAction` short-circuits to `true` when biometrics are off — for a spend limit we probably want to fall back to **password** rather than silently allow. Confirm.

## Acceptance criteria

- [ ] Settings surface to enable and set daily and/or weekly limits (per-asset native amount).
- [ ] Enabling/raising/disabling a limit requires biometric or password confirmation.
- [ ] Outgoing transactions exceeding the active limit require a step-up confirmation (or are blocked), enforced at the `initiate*` chokepoint so dApp/earn/bridge are covered.
- [ ] Clear messaging when a limit is hit (amount over, time to reset, how to raise).
- [ ] Cumulative spend computed correctly over the window per asset; incoming/consume excluded.
- [ ] Documented explicitly that this is a client-side guardrail, not a cryptographic limit.
- [ ] Tests: limit math (window boundaries, per-asset), step-up-required paths, settings persistence.

## Out of scope / follow-ups

- True on-chain enforcement via a value-aware account/Guardian policy (much larger; needs account-component work).
- USD-denominated limits across all tokens (needs broader price coverage).
- Per-recipient allowlists.

贡献指南

打开贡献指南

评估

这个 Issue 还没有评估数据。

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。