21.2. Automatic coin renewal#
Wallet-core implements the September 2026 policy from DD 71: Auto-refresh, with deterministic greedy output selection. Wallet clients receive renewal information with each scoped balance.
21.2.1. Selection and eligibility#
For an input coin, let D be its deposit expiration, W its withdrawal
expiration, R = D - now, and E = min(90 days, (D - W) / 4). Days are fixed
24-hour periods. Invalid or infinite lifetimes are reported; expired coins use
existing expiration and recovery handling.
The wallet considers compatible, verified, currently withdrawable denomination keys, excluding revoked and lost keys. It selects outputs greedily in descending face-value order, breaking ties by lower withdrawal fee, later deposit expiration, and denomination hash. The refresh protocol permits at most 64 outputs. This is deliberately best effort: it does not implement DD71’s globally optimal value/lifetime/coin-count selection. Spending existing coins retains DD91’s modified greedy algorithm and earliest-expiration preference.
The earliest selected output expiration determines the output lifetime. Total cost includes melting fees, withdrawal fees, and unrepresentable remainder. The wallet requires positive recovered value and an extension of validity, then evaluates these strict conditions in order:
Output remaining lifetime exceeds four times the input remaining lifetime.
Input remaining lifetime is below 180 days, output remaining lifetime exceeds 360 days, total cost is zero, and external power is confirmed.
Input remaining lifetime is below
E.
Decision, accounting, and execution use the same selected outputs. Inputs reserved for payments or refreshes are unavailable for another automatic refresh. Before sending a melt, the wallet revalidates eligibility and selected keys. A request that might already have reached the exchange retains its original commitment through retry and recovery.
21.2.2. Scheduling#
A private random deadline per wallet and input denomination spreads renewal
traffic. Before D - E / 10, the delay is at most the minimum of one day,
E / 10, and half the time to that urgent boundary. Urgent inputs are due
immediately. Restarting, updating keys, or reopening the application does not
redraw or postpone a deadline. Temporarily ineligible inputs retain their deadline
while the wallet waits for a valid plan. Retry backoff is randomized and capped
by the time to urgency, or remaining lifetime once urgent.
21.2.3. Background balance reporting#
Renewal information is computed by the refresh-balance maintenance task and
persisted by balance scope. A balance request only reads the saved report and its
input generation; it does not load denominations, scan refresh history, or run
output selection. The report survives closing and reopening the wallet.
Changes to holdings, exchange keys and trust, refresh progress, and relevant retry errors invalidate the report in the same transaction as their inputs. The task reads a consistent snapshot, releases the database transaction, and computes the report while periodically yielding to other wallet work. It publishes only if the input generation is still current, then notifies balance clients. A changed generation causes another calculation instead of publishing stale data.
Known warnings and recovery notices remain visible while a report is being updated. A cost bound is withheld when its generation, balance amount, or time validity no longer matches; clients see a checking indication until the new report is ready. An empty cache also returns a checking indication without blocking the balance request. The task schedules itself for the next relevant validity or key freshness boundary, with a daily upper limit between checks.
21.2.4. Power observations#
hintPowerState accepts { powerSource: "external" | "battery" | "unknown" }
and returns an empty object. Observations are transient and expire after 60
seconds: a host should refresh its current observation at least every 30 seconds.
The browser integration uses supported battery observations and reports unknown
for unsupported or inconclusive readings. Unknown power never enables the free
opportunistic rule; necessary refreshes do not require external power.
21.2.5. Balance warnings and recovery notices#
Each balance may contain refreshInfo with risks, recoveries, and
annualCostBound. Risks identify the exchange, amount and earliest expiration.
They distinguish a pending renewal, a connection failure, an exchange error,
unavailable suitable replacements established from fresh keys, a check in
progress, and invalid validity dates. They do not assert device-wide offline
status. Pending and failing renewals retain expiration indications until success.
A completed group whose coins were close to expiration before melting supplies
one recovery notice, including the new expiration and next relevant date.
dismissWalletWarning accepts { warningId: string } to persist dismissal.
Active expiration risks cannot be dismissed. A renewal notice does not imply the
wallet was previously offline.
21.2.6. Conditional cost bound#
The balance screen’s expandable cost summary covers keeping the current balance for 365 days without payments or additional withdrawals. It is a conditional upper bound, not a predicted debit. It assumes continuously available compatible families with stable values, fees and lifetime bounds, and reveal completing before output withdrawal validity ends. Unpublished future offerings are a projection, not a signed commitment.
Wallet-core checks all reachable compatible denominations, including small change,
and includes actual greedy-selection losses. It establishes conservative bounds
Gmin, Hmax, and loss fraction p, then uses
Delta = Gmin - Hmax / 4, N = 1 + floor(365 days / Delta), and
B * (1 - (1 - p)**N). Group bounds are rounded upward to Taler’s supported
amount precision before summing. Missing or stale information, unrefreshable
change, nonpositive Delta and unsettled holdings make the estimate unavailable.
Changed balances or offerings cause recomputation.
The estimate excludes initial withdrawal fees, payment-related refreshes, and losses from expiration or outages. Keeping a wallet offline beyond its coin validity periods can still lose funds.
21.2.7. Development experiments#
With development mode enabled and an existing balance, use
taler://dev-experiment/dd71-risk, dd71-recovered, or
dd71-cost-unavailable to exercise the balance presentation. These transient
fixtures do not alter coins. dd71-clear removes them. The browser demo also
includes a pending risk, a dismissible recovery notice, and a cost bound.