taler-docs

Documentation for GNU Taler components, APIs and protocols
Log | Files | Refs | README | LICENSE

037-wallet-transactions-lifecycle.rst (44693B)


      1 DD 37: Wallet Transaction Lifecycle
      2 ###################################
      3 
      4 :Design status: Accepted
      5 :Implementation status: Implemented
      6 :DD shepherd: TBD
      7 :Historical contributors: Sebastian, Özgür Kesim, Christian Grothoff, Florian Dold
      8 :First published: 2023-02-13
      9 :Last substantive change: 2026-09-07
     10 :Normative references: :doc:`../wallet/wallet-core`
     11 
     12 .. contents:: Table of Contents
     13    :depth: 2
     14 
     15 Summary
     16 =======
     17 
     18 This document describes the transaction lifecycle exposed by wallet-core:
     19 what a transaction is doing, what lets it progress, and which actions a
     20 frontend can request. It defines the common state model and the meaning of
     21 each transaction's stages without prescribing screen layouts or translated
     22 strings.
     23 
     24 Transactions in the same state can have different available actions,
     25 depending on their type and circumstances. Frontends must use the returned
     26 ``txActions`` rather than reconstruct permissions from the state name.
     27 
     28 State notation and public data
     29 ==============================
     30 
     31 States are written as ``major[:minor][/working]``. For example, ``dialog:proposed``,
     32 ``pending:withdraw/working``, ``pending:kyc``, and ``done``.
     33 Diagram labels may wrap after a colon or before ``/working``; the line break
     34 is not part of the state string. The colon and minor component are omitted
     35 when there is no minor state; ``/working`` is appended only when
     36 ``txState.working`` is true.
     37 
     38 ``/working`` signals that the transaction is in an active processing phase.
     39 UIs typically show a loading indicator during this phase and keep it until
     40 the flag clears. Processing includes time spent awaiting HTTP responses or
     41 retry delays; the flag does not measure instantaneous CPU or network activity.
     42 When it clears, the UI renders the resulting state: often a pending wait for
     43 an external event, a dialog requiring a user decision, or a finalizing or
     44 terminal outcome. Clearing ``/working`` does not imply successful completion.
     45 
     46 A pending transaction without ``/working`` generally waits for a condition
     47 to change. Wallet-core may still poll, send requests, and resume processing
     48 automatically once that condition changes. Finalizing work can likewise
     49 continue without an active loading indicator. The flag describes one
     50 transaction's processing phase for presentation, not overall wallet activity.
     51 
     52 For example:
     53 
     54 * ``pending:withdraw/working``: active withdrawal processing, typically shown
     55   with a loading indicator.
     56 * ``pending:exchange-wait-reserve``: waiting for funding while polling the
     57   exchange.
     58 * ``dialog:proposed``: waiting for a user decision.
     59 * ``finalizing:track``: background tracking of bank delivery.
     60 * ``done``: completion.
     61 
     62 In a state expression, ``/idle`` matches ``working`` being false
     63 or absent. It can therefore match dialog and terminal states as well as
     64 pending waits; it is not a separate lifecycle stage. Omitting the qualifier
     65 from a state expression accepts either value of ``working``. A displayed
     66 state simply omits the suffix when the flag is false or absent; it
     67 does not append ``/idle``.
     68 
     69 State expressions select states; they are distinct from the concrete state
     70 labels in the tables and diagrams. An expression with an omitted minor
     71 component matches any minor: ``pending`` is equivalent to ``pending:*``.
     72 Use ``pending:-`` to match only a pending state with no minor component.
     73 Thus ``pending/idle`` selects pending states whose ``working`` flag is false
     74 or absent, regardless of their minor. ``pending:kyc/idle`` selects only the
     75 operation-KYC wait. ``*`` matches any major or minor component, and
     76 comma-separated expressions select any of their alternatives.
     77 
     78 The ``working`` flag is primarily transitional. A future lifecycle model may
     79 express the distinction between active processing and waiting through
     80 separate major states instead of this flag and its ``/working`` and ``/idle``
     81 qualifiers. This document describes the current representation; the future
     82 major-state names and migration are not specified here.
     83 
     84 Use the major state to identify suspension and ``txActions`` to determine
     85 available actions. A suspended major state takes precedence over the
     86 processing hint: render the transaction as paused even if ``working`` is
     87 still true. The processing hint does not grant action permissions.
     88 
     89 The tables below group states with shared behavior and list each family's
     90 members in the left column. The same public state can appear in different
     91 contexts with different actions. Diagrams show selected paths; their
     92 conceptual groups are explicitly labeled. They omit repeated retry and
     93 suspension edges, and do not imply that every transaction visits every node.
     94 
     95 Using lifecycle data in a UI
     96 ============================
     97 
     98 Read ``type``, ``txState``, ``txActions``, and the transaction details together.
     99 The type and minor state explain the operation, the major state determines
    100 its lifecycle stage, and ``working`` guides the loading indicator. Translate
    101 these into user-facing descriptions rather than displaying state expressions
    102 as the ordinary status text. For an unfamiliar minor state, retain the
    103 major-state presentation and use the returned actions and details.
    104 
    105 .. list-table::
    106    :header-rows: 1
    107    :widths: 25 75
    108 
    109    * - Field
    110      - Meaning
    111    * - ``txState.major`` / ``minor``
    112      - Lifecycle stage and optional operation-specific detail. Minor states also
    113        occur in dialog, finalizing, suspended, and terminal stages.
    114    * - ``txState.working``
    115      - An active-processing hint used for loading indicators, as described
    116        above. It does not measure progress or determine action permissions.
    117    * - ``txActions``
    118      - Currently advertised generic actions: ``retry``, ``suspend``, ``resume``,
    119        ``abort``, ``fail``, and ``delete``. The API checks availability again
    120        when an action is requested.
    121    * - ``error``
    122      - Details of an attempt that encountered an error. A recoverable network
    123        error does not itself make the transaction ``failed``.
    124    * - ``abortReason`` / ``failReason``
    125      - Reasons for abandoning the original operation or for failure, where
    126        supplied. Consult these and the transaction-specific details to
    127        distinguish recovery outcomes.
    128    * - ``amountRaw``
    129      - Transaction amount before fees or extra costs.
    130    * - ``amountEffective``
    131      - Amount shown at confirmation, including estimated fees. It is preserved
    132        if the operation fails, expires, or is aborted.
    133    * - ``amountEffectiveFinal``
    134      - Settled wallet balance effect when known, including fees and recovery.
    135        It is nonnegative; the transaction type determines debit or credit.
    136        Absence means that the amount is not yet settled or cannot be established,
    137        not that its value is zero.
    138 
    139 Use the settled amount to describe the actual wallet balance effect when it
    140 is available, and distinguish it from the original confirmation amount.
    141 State alone does not establish how much value was delivered, recovered, or
    142 lost. A wallet balance effect also does not establish receipt of a bank
    143 transfer by the counterparty. Ordinary merchant refunds remain separate
    144 credit records.
    145 
    146 After a ``transaction-state-transition`` notification, refresh the affected
    147 transaction's details and actions. The notification is a reason to refresh,
    148 not a replacement for the full transaction. A ``deleted`` transition removes
    149 the entry from the UI; a lookup may also find that it has already disappeared.
    150 Fetch current data when reopening a screen or reconnecting to wallet-core,
    151 since the UI may not have observed every transition. After requesting an
    152 action, display the resulting state rather than assuming the action completed
    153 the transaction.
    154 
    155 Accepting a proposed transaction uses its transaction-specific confirmation
    156 action. These confirmations, following a bank confirmation URL, visiting a
    157 KYC URL, and making a bank transfer are separate from the generic transaction
    158 actions.
    159 
    160 Common States
    161 =============
    162 
    163 .. list-table::
    164    :header-rows: 1
    165    :widths: 31 69
    166 
    167    * - Major state
    168      - Meaning
    169    * - ``dialog``
    170      - A proposal or choice is waiting for the user, or an order is waiting for
    171        another wallet. It is not a terminal state.
    172    * - ``pending``
    173      - The requested operation has more work to do. It may be actively processing
    174        or waiting for the bank, exchange, another wallet, or KYC.
    175    * - ``finalizing``
    176      - Post-processing or recovery remains. Payment auto-refund monitoring and
    177        deposit tracking use this stage, but so does hard-limit recovery of an
    178        unsuccessful operation. It does not universally mean success.
    179    * - ``aborting``
    180      - The wallet is reconciling or recovering an operation that was aborted or
    181        expired. Cancellation can race with successful completion.
    182    * - ``suspended``
    183      - The pending operation is paused and may be resumed. This is not an aborted
    184        or failed outcome.
    185    * - ``suspended-aborting`` / ``suspended-finalizing``
    186      - Paused abort processing or finalizing work.
    187    * - ``done``
    188      - Successful completion of this transaction record. Subsequent explicit
    189        operations, such as requesting a refund or restoring a payment session,
    190        can make a payment active again.
    191    * - ``aborted``
    192      - The original operation was abandoned. Recovery and partial effects must be
    193        read from the transaction details.
    194    * - ``failed``
    195      - Processing ended unsuccessfully. This alone does not imply that all funds
    196        were lost.
    197    * - ``expired``
    198      - The operation ended because its validity period elapsed, after any
    199        required cleanup.
    200    * - ``none`` / ``deleted``
    201      - Notification-only endpoints: creation has no preceding state, and deletion
    202        has no remaining transaction history entry.
    203 
    204 The final states are ``done``, ``aborted``, ``failed``, ``expired``, and
    205 ``deleted``. Here, final means that ordinary processing of the transaction
    206 has ended; an explicit later operation may reactivate it. Suspended states,
    207 ``dialog``, and ``finalizing`` are not final.
    208 
    209 .. graphviz::
    210    :caption: Common lifecycle: selected paths, with operation details omitted.
    211    :alt: A proposal starts processing. Processing can finish, finalize, or enter abort recovery. Pausing is described separately.
    212    :align: center
    213 
    214    digraph lifecycle {
    215      graph [rankdir=TB, newrank=true, bgcolor="transparent", pad=0.15, nodesep=0.35, ranksep=0.42];
    216      node [shape=box, style="rounded,filled", fillcolor="#f3f6fa", color="#526478", fontname="monospace", fontsize=11, margin="0.14,0.10"];
    217      edge [color="#526478", fontname="sans-serif", fontsize=10, arrowsize=0.7];
    218      dialog [label="dialog\n(stage)"];
    219      pending [label="pending\n(stage)"];
    220      finalizing [label="finalizing\n(stage)"];
    221      aborting [label="aborting\n(stage)"];
    222      done [label="done", fillcolor="#e5f2e9"];
    223      outcome [label="Settled outcome\n(done, aborted,\nfailed, or expired)", fontname="sans-serif", fillcolor="#fff1db"];
    224      dialog -> pending [label="accept / confirm"];
    225      pending -> done [label="complete"];
    226      pending -> finalizing [label="follow-up work"];
    227      pending -> aborting [label="abort / expire"];
    228      finalizing -> outcome [label="follow-up / recovery\nsettled"];
    229      aborting -> outcome [label="reconcile / recover"];
    230    }
    231 
    232 Common Transitions
    233 ==================
    234 
    235 .. list-table::
    236    :header-rows: 1
    237    :widths: 20 80
    238 
    239    * - Action
    240      - Effect when advertised
    241    * - ``retry``
    242      - Reset the associated task so another attempt can run without waiting for
    243        its existing retry delay. It does not approve a proposal, bypass KYC, or
    244        guarantee progress.
    245    * - ``suspend``
    246      - Pause processing while retaining the ability to resume. The usual
    247        major-state pairs are pending/suspended, aborting/suspended-aborting, and
    248        finalizing/suspended-finalizing.
    249    * - ``resume``
    250      - Restore the corresponding active operation. The minor state normally
    251        identifies the work to resume.
    252    * - ``abort``
    253      - Abandon the requested operation, possibly after reconciliation, purse
    254        deletion, refunds, or refreshes. It can finish successfully if the
    255        counterparty already completed the operation.
    256    * - ``fail``
    257      - Stop the operation in failure without completing further recovery. It is
    258        different from abort and can leave funds unrecovered.
    259    * - ``delete``
    260      - Remove the history record according to its transaction-specific cleanup
    261        rules. It does not reverse payments, erase already withdrawn coins, or
    262        substitute for refund or abort.
    263 
    264 Actions are not universal even within one major state. For example, deposit
    265 KYC before submission does not advertise ``retry``, while aggregate KYC does;
    266 refund records advertise only ``delete``, even while pending. Some finalizing
    267 records allow deletion, but hard-limit recovery normally allows only retry.
    268 The operation tables below specify these differences. A state can change
    269 between reading it and requesting an action; refresh the transaction when
    270 wallet-core rejects a now-unavailable action.
    271 
    272 .. _dd37-kyc:
    273 
    274 KYC and balance limits
    275 ======================
    276 
    277 The exchange's KYC/AML design is described in :doc:`023-taler-kyc`; endpoint
    278 contracts are in :doc:`../core/api-exchange`.
    279 
    280 .. list-table::
    281    :header-rows: 1
    282    :widths: 38 62
    283 
    284    * - Public state
    285      - Meaning and continuation
    286    * - ``pending:kyc-init/working``
    287      - Wallet-core is obtaining KYC details or initializing wallet balance
    288        authorization. This is used by withdrawals, deposits, and P2P credits.
    289        There is not yet a usable KYC continuation just because a transaction has
    290        entered this state.
    291    * - ``pending:kyc``
    292      - Operation-specific KYC has an access token. Wallet-core supplies a KYC
    293        URL and polls the exchange. Used for withdrawal, deposit/aggregation, and
    294        P2P merge requirements.
    295    * - ``pending:balance-kyc``
    296      - A withdrawal or P2P credit would exceed the authorized wallet balance at
    297        the exchange. Wait for authorization or for a balance change that makes
    298        the incoming amount permissible.
    299    * - ``pending:kyc-auth``
    300      - A direct deposit requires proof of control of its target bank account.
    301        Follow ``kycAuthTransferInfo`` to make a transfer from that account to the
    302        exchange. Token access can then become available for ordinary KYC.
    303    * - ``finalizing:kyc-hard-limit/working``
    304      - An operation exceeded a hard limit. Wallet-core performs
    305        operation-specific cleanup; passing ordinary KYC cannot raise that hard
    306        limit.
    307    * - ``failed:kyc-hard-limit``
    308      - The original operation failed after hard-limit handling. Inspect
    309        ``failReason`` and recovery details; this state does not by itself
    310        establish successful return of funds.
    311 
    312 Ordinary KYC waiting has suspended counterparts with the same minor component.
    313 Paused deposit recovery can expose ``suspended-finalizing:kyc-hard-limit``.
    314 There is no public ``merge-kyc``, ``withdraw-kyc``, or ``aml`` minor state.
    315 Merge KYC is exposed as ``kyc-init`` or ``kyc``. Exchange ``aml_review``
    316 influences polling; wallet-core does not expose a separate
    317 transaction state distinguishing staff review from a user-interactive check.
    318 Consequently, ``pending:kyc`` does not prove that further user input is needed.
    319 
    320 .. graphviz::
    321    :caption: Shared KYC flow: selected waiting paths; return to the interrupted operation.
    322    :alt: KYC initialization leads to operation KYC or balance KYC. Bank account authentication can provide access to deposit KYC. Authorization returns to processing.
    323    :align: center
    324 
    325    digraph kyc {
    326      graph [rankdir=TB, newrank=true, bgcolor="transparent", pad=0.15, nodesep=0.35, ranksep=0.42];
    327      node [shape=box, style="rounded,filled", fillcolor="#f3f6fa", color="#526478", fontname="monospace", fontsize=11, margin="0.14,0.10"];
    328      edge [color="#526478", fontname="sans-serif", fontsize=10, arrowsize=0.7];
    329      init [label="pending:kyc-init\n/working"];
    330      auth [label="pending:kyc-auth\n(deposits only)"];
    331      kyc [label="pending:kyc"];
    332      balance [label="pending:balance-kyc"];
    333      proceed [label="Continue the\ninterrupted operation", fontname="sans-serif", fillcolor="#e5f2e9"];
    334      init -> kyc [label="operation KYC\ndetails available"];
    335      init -> balance [label="balance KYC\ndetails available"];
    336      auth -> kyc [label="account authenticated\n+ token available"];
    337      kyc -> proceed [label="operation allowed"];
    338      balance -> proceed [label="limit raised or\nbalance reduced"];
    339    }
    340 
    341 The KYC diagram shows common paths, not a compulsory sequence. An operation
    342 can start with known authorization, retry directly, or move back through
    343 initialization. A bank-account authentication request can also arise after
    344 ordinary deposit KYC has already started.
    345 
    346 KYC data and polling
    347 --------------------
    348 
    349 ``kycUrl`` identifies the exchange's KYC web interface. Treat it as a
    350 continuation for a transaction whose KYC details are available, not as proof
    351 that KYC succeeded.
    352 Offer the supplied URL when the transaction is waiting in ``kyc`` or
    353 ``balance-kyc`` and the URL is available. During ``kyc-init``, show that KYC
    354 details are being obtained; the presence of a URL alone does not establish
    355 that initialization is complete. Do not construct a continuation URL from
    356 state names. The KYC access token grants access to the account's KYC process
    357 and is not a user-facing identifier.
    358 
    359 ``kycAuthTransferInfo.debitPaytoUri`` specifies the account that must send the
    360 authentication transfer; a transfer from another account will not authenticate
    361 it. ``accountPub`` identifies the account key. Prefer ``transferOptionsExt``:
    362 it groups transfer instructions, amounts, and expiry by exchange credit
    363 account. Use the supplied account-specific instructions and amounts for the
    364 authentication transfer.
    365 
    366 Wallet-core monitors the exchange's authorization status and rechecks whether
    367 the operation can proceed as authorization, limits, or the balance change.
    368 The UI does not need to poll the exchange itself. When the user returns from
    369 the KYC page, refresh the transaction and show its current state. Merely
    370 closing that page does not complete a transaction, and continued KYC waiting
    371 does not necessarily mean that the user must submit information again.
    372 
    373 An account's KYC status can include limits that still restrict the particular
    374 operation. Wallet-core evaluates the operation, projected balance, and
    375 relevant transaction volume against these limits. A hard limit may also
    376 reject an operation during preparation, before a transaction is created.
    377 
    378 Balance authorization is shared by transactions at the same exchange. It
    379 covers the projected wallet balance after the incoming operation, including
    380 value awaiting refresh. Fees do not increase that coin balance. Use the
    381 balance and limit information supplied by wallet-core for explanations;
    382 reconstructing it from the visible transaction list can miss relevant value
    383 or account-specific limits.
    384 
    385 Hard-limit recovery
    386 -------------------
    387 
    388 When an in-progress operation encounters a hard limit, it reports
    389 ``WALLET_KYC_LIMIT_EXCEEDED`` and starts recovery rather than remaining
    390 indefinitely in ordinary operation-KYC waiting:
    391 
    392 * Withdrawals request reserve closure back to the originating account. A
    393   successful close and a permanently failed close both end in
    394   ``failed:kyc-hard-limit``; the failure reason distinguishes them. Temporary
    395   failures keep recovery active. Acceptance of reserve closure is not proof
    396   that the bank has already credited the return transfer.
    397 * Deposits use refund and refresh recovery. Fully recovered hard-limit
    398   deposits end in ``failed:kyc-hard-limit``; partial recovery, refund failure,
    399   or an already completed wire transfer use the deposit outcomes below.
    400 * P2P push credits reconcile whether a merge committed. P2P pull credits
    401   delete/reconcile the purse. If funds were already merged, recovery can
    402   continue through withdrawal instead of immediately ending in failure.
    403 
    404 Balance authorization has its own exchange-level lifecycle. A balance-KYC
    405 wait does not necessarily enter the transaction hard-limit recovery path
    406 described here.
    407 
    408 Transaction Type: Withdrawal
    409 ============================
    410 
    411 Manual and bank-integrated withdrawals eventually wait for reserve funding
    412 and withdraw coins. Bank-integrated withdrawals additionally register the
    413 reserve and wait for confirmation at the bank. Depending on how the
    414 operation was prepared, approval in the wallet can precede transaction
    415 creation or appear as ``dialog:proposed``. This wallet approval is separate
    416 from confirmation of the transfer at the bank.
    417 
    418 .. graphviz::
    419    :caption: Withdrawal progress, with bank-only steps on the right.
    420    :alt: Manual withdrawals wait for reserve funding. Bank withdrawals register the reserve and await confirmation first. Both withdraw coins and complete.
    421    :align: center
    422 
    423    digraph withdrawal {
    424      graph [rankdir=TB, newrank=true, bgcolor="transparent", pad=0.15, nodesep=0.35, ranksep=0.42];
    425      node [shape=box, style="rounded,filled", fillcolor="#f3f6fa", color="#526478", fontname="monospace", fontsize=11, margin="0.14,0.10"];
    426      edge [color="#526478", fontname="sans-serif", fontsize=10, arrowsize=0.7];
    427      manual [label="Manual withdrawal\n(entry)", fontname="sans-serif"];
    428      bank [label="Bank-integrated\nentry after wallet approval", fontname="sans-serif"];
    429      register [label="pending:bank-register-reserve\n/working"];
    430      confirm [label="pending:bank-confirm-transfer"];
    431      reserve [label="pending:exchange-wait-reserve"];
    432      withdraw [label="pending:withdraw/working"];
    433      done [label="done", fillcolor="#e5f2e9"];
    434      { rank=same; manual; bank; }
    435      manual -> reserve [label="transfer instructions"];
    436      bank -> register [label="start"];
    437      register -> confirm [label="registered"];
    438      confirm -> reserve [label="bank confirms"];
    439      reserve -> withdraw [label="funding observed"];
    440      withdraw -> done [label="coins obtained"];
    441    }
    442 
    443 .. list-table::
    444    :header-rows: 1
    445    :widths: 40 60
    446 
    447    * - State or family
    448      - Progress and available actions
    449    * - ``dialog:proposed``
    450      - Confirm the withdrawal through its dedicated API, or ``abort`` to refuse
    451        it.
    452    * - ``pending:bank-register-reserve/working``;
    453        ``pending:bank-confirm-transfer``
    454      - Register the reserve, then wait for bank confirmation. Actions: ``retry``,
    455        ``suspend``, ``abort``. Suspended counterparts: ``resume``, ``abort``.
    456    * - ``pending:exchange-wait-reserve``
    457      - Wait for reserve funding, then withdraw. Actions: ``retry``, ``suspend``;
    458        also ``abort`` until funding has been observed. Suspended counterpart:
    459        ``resume`` and the same conditional ``abort``.
    460    * - ``pending:withdraw/working``
    461      - Withdraw selected coins; reselect denominations when necessary, with no
    462        additional public state for that step. Actions: ``retry``, ``suspend``.
    463        ``suspended:withdraw``: ``resume``.
    464    * - KYC initialization and waiting
    465 
    466        | ``pending:kyc-init/working``
    467        | ``pending:kyc``
    468        | ``pending:balance-kyc``
    469      - Actions: ``retry``, ``suspend``; also ``abort`` until funding has been
    470        observed. Suspended counterparts: ``resume`` and the same conditional
    471        ``abort``.
    472    * - ``aborting:bank/working``
    473      - Ask the bank to abort. Actions: ``retry``, ``suspend``, ``fail``.
    474        ``suspended-aborting:bank``: ``resume``, ``fail``.
    475    * - ``finalizing:kyc-hard-limit/working``
    476      - Return-to-origin recovery. Only ``retry`` is advertised.
    477    * - Terminal outcomes
    478 
    479        | ``done``
    480        | ``failed``
    481        | ``failed:aborting-bank``
    482        | ``failed:kyc-hard-limit``
    483        | ``aborted:bank``
    484        | ``aborted:exchange``
    485        | ``aborted:refused``
    486        | ``aborted:completed-by-other-wallet``
    487      - Only ``delete``.
    488 
    489 When the bank rejects an abort because it already confirmed the transfer
    490 (HTTP 409), wallet-core retains ``suspended:exchange-wait-reserve`` so the
    491 withdrawal can be resumed. A successful bank abort becomes ``aborted:bank``;
    492 an unknown bank operation becomes ``failed``. Aborting a manual withdrawal
    493 before observed funding produces ``aborted:exchange``; it does not undo a
    494 bank transfer. Do not promise a returned amount or arrival time from that
    495 state alone.
    496 
    497 Withdrawals performed as part of P2P receipts or other operations are tracked
    498 through the containing transaction. A P2P credit can remain
    499 ``pending:withdraw/working`` while its underlying withdrawal is in KYC or
    500 recovery; the containing transaction need not expose every sub-step.
    501 
    502 Transaction Type: Payment
    503 =========================
    504 
    505 A merchant payment claims an order, obtains user approval, and submits the
    506 payment. A shared/unclaimed order may instead wait for another wallet.
    507 After payment, monitoring auto-refunds is finalizing work. Explicit refund
    508 checks and session restoration can reactivate a completed payment.
    509 
    510 ``rebind-session`` restores access to an already paid order in another
    511 merchant session; it does not request another purchase. ``auto-refund``
    512 checks for merchant-offered refunds, ``check-refund`` performs an explicit
    513 refund check, and ``accept-refund`` processes the offered refund. These
    514 stages can therefore occur after the original payment succeeded.
    515 
    516 .. graphviz::
    517    :caption: Main payment path and automatic refund monitoring.
    518    :alt: Claim a proposal, obtain approval, and submit payment. After payment succeeds, complete immediately or monitor auto-refunds and accept a refund if one appears.
    519    :align: center
    520 
    521    digraph payment {
    522      graph [rankdir=TB, newrank=true, bgcolor="transparent", pad=0.15, nodesep=0.35, ranksep=0.42];
    523      node [shape=box, style="rounded,filled", fillcolor="#f3f6fa", color="#526478", fontname="monospace", fontsize=11, margin="0.14,0.10"];
    524      edge [color="#526478", fontname="sans-serif", fontsize=10, arrowsize=0.7];
    525      claim [label="pending:claim-proposal\n/working"];
    526      dialog [label="dialog:proposed"];
    527      pay [label="pending:submit-payment\n/working"];
    528      monitor [label="finalizing:auto-refund"];
    529      accept [label="pending:accept-refund\n/working"];
    530      done [label="done", fillcolor="#e5f2e9"];
    531      claim -> dialog [label="proposal available"];
    532      dialog -> pay [label="confirm payment"];
    533      pay -> monitor [label="paid; monitor refunds"];
    534      direct [label="done", fillcolor="#e5f2e9"];
    535      pay -> direct [label="paid; no monitoring"];
    536      monitor -> accept [label="refund offered"];
    537      monitor -> done [label="monitoring ends"];
    538      accept -> done [label="refund processed;\nmonitoring ended"];
    539    }
    540 
    541 After processing a refund, wallet-core returns to ``finalizing:auto-refund``
    542 if the auto-refund deadline is still in the future. That repeated monitoring
    543 path is omitted from the diagram; its final ``done`` node applies when no
    544 more monitoring remains. ``done`` appears at both exits to keep the flow
    545 readable.
    546 
    547 .. list-table::
    548    :header-rows: 1
    549    :widths: 36 64
    550 
    551    * - State or family
    552      - Progress and available actions
    553    * - ``dialog:proposed``
    554      - An ordinary or shared proposal. Confirm through the payment API; generic
    555        actions are ``retry``, ``delete``. Refusal uses the proposal API and can
    556        produce ``aborted:refused``.
    557    * - ``dialog:waiting-for-other-wallet``
    558      - An unclaimed/shared order is waiting on another wallet. Generic action:
    559        ``delete``.
    560    * - Pending processing
    561 
    562        | ``pending:claim-proposal/working``
    563        | ``pending:submit-payment/working``
    564        | ``pending:rebind-session/working``
    565        | ``pending:auto-refund/working``
    566        | ``pending:check-refund/working``
    567        | ``pending:accept-refund/working``
    568      - Each advertises ``retry``, ``suspend``, ``abort``. Suspended
    569        counterparts advertise ``resume``, ``abort``.
    570    * - ``finalizing:auto-refund``
    571      - Wait for automatic refunds after successful payment. A refund moves to
    572        ``pending:accept-refund/working``; monitoring completion returns to
    573        ``done``. Actions: ``retry``, ``suspend``, ``delete``.
    574    * - ``suspended-finalizing:auto-refund``
    575      - Paused automatic refund monitoring. Actions: ``resume``, ``delete``.
    576    * - ``aborting/working``
    577      - Abort payment using refund/recovery processing. Actions: ``retry``,
    578        ``suspend``, ``fail``. ``suspended-aborting``: ``resume``, ``fail``.
    579    * - Terminal outcomes
    580 
    581        | ``done``
    582        | ``aborted``
    583        | ``aborted:refused``
    584        | ``aborted:continued-with-other-wallet``
    585        | ``expired``
    586        | ``failed``
    587        | ``failed:claim-proposal``
    588        | ``failed:abort``
    589        | ``failed:paid-by-other``
    590        | ``failed:repurchase``
    591      - Each advertises ``delete``.
    592 
    593 Aborting a session replay or an explicit refund check returns the payment to
    594 ``done``; it does not undo the original payment. Payment abort can also race
    595 with payment completion. Repurchase detection creates a
    596 ``failed:repurchase`` record, normally filtered from history, while restoring
    597 access through the original payment. Refund credits are separate records;
    598 a payment returning to ``done`` after accepting a refund does not mean that
    599 no refund occurred.
    600 
    601 Transaction Type: Deposit
    602 =========================
    603 
    604 A direct deposit sends coins to an exchange for delivery to a bank account.
    605 After submission, ``finalizing:track`` waits for the exchange's wire-transfer
    606 status, taking the wire deadline into account. Tracking can discover a new
    607 KYC requirement and make the transaction pending again.
    608 
    609 .. graphviz::
    610    :caption: Deposit submission, delivery tracking, and abort recovery.
    611    :alt: Submitted deposits enter tracking and complete after wire confirmation. An abort reconciles refunds and refreshes; an already completed transfer ends as done with the abort-too-late detail.
    612    :align: center
    613 
    614    digraph deposit {
    615      graph [rankdir=TB, newrank=true, bgcolor="transparent", pad=0.15, nodesep=0.35, ranksep=0.42];
    616      node [shape=box, style="rounded,filled", fillcolor="#f3f6fa", color="#526478", fontname="monospace", fontsize=11, margin="0.14,0.10"];
    617      edge [color="#526478", fontname="sans-serif", fontsize=10, arrowsize=0.7];
    618      deposit [label="pending:deposit/working"];
    619      track [label="finalizing:track"];
    620      done [label="done", fillcolor="#e5f2e9"];
    621      abort [label="aborting"];
    622      recovered [label="aborted:\ndeposit-abort-recovered", fillcolor="#e5f2e9"];
    623      late [label="done:\ndeposit-abort-too-late", fillcolor="#fff1db"];
    624      deposit -> track [label="coins deposited"];
    625      track -> done [label="wire confirmed"];
    626      deposit -> abort [label="abort"];
    627      abort -> recovered [label="refund + refresh complete"];
    628      abort -> late [label="already wired"];
    629      recovered -> late [style=invis];
    630    }
    631 
    632 .. list-table::
    633    :header-rows: 1
    634    :widths: 36 64
    635 
    636    * - State or family
    637      - Progress and available actions
    638    * - ``pending:deposit/working``
    639      - Submit deposits. Actions: ``retry``, ``suspend``, ``abort``. ``suspended``
    640        (without a minor): only ``resume``.
    641    * - Submission KYC
    642 
    643        | ``pending:kyc-init/working``
    644        | ``pending:kyc``
    645        | ``pending:kyc-auth``
    646      - Actions: ``suspend``, ``abort``. Suspended counterparts: ``resume``,
    647        ``abort``.
    648    * - Aggregation KYC
    649 
    650        | ``pending:kyc-init/working``
    651        | ``pending:kyc``
    652      - KYC after deposits were submitted. Actions: ``retry``, ``suspend``,
    653        ``fail``. Suspended counterparts: ``resume``, ``fail``.
    654    * - ``finalizing:track``
    655      - Track delivery. Actions: ``suspend``, ``delete``.
    656        ``suspended-finalizing:track``: ``resume``, ``delete``. KYC can interrupt
    657        tracking.
    658    * - ``pending:track`` / ``suspended:track``
    659      - Delivery tracking on older transactions. Active actions: ``retry``,
    660        ``suspend``, ``fail``; suspended actions: ``resume``, ``fail``.
    661    * - ``aborting``
    662      - Refund deposited contributions and refresh recoverable coins. Actions:
    663        ``retry``, ``suspend``, ``fail``. ``suspended-aborting``: ``resume``,
    664        ``fail``.
    665    * - ``finalizing:kyc-hard-limit/working``
    666      - Recovery after a hard-limit rejection. Only ``retry``.
    667    * - ``suspended-finalizing:kyc-hard-limit``
    668      - Paused hard-limit recovery. Actions: ``resume``, ``fail``.
    669 
    670 All terminal outcomes below advertise ``delete``. Their states distinguish
    671 delivery, recovered value, and unsuccessful recovery.
    672 
    673 .. list-table::
    674    :header-rows: 1
    675    :widths: 46 54
    676 
    677    * - Outcome
    678      - Interpretation
    679    * - ``done``
    680      - Ordinary deposit completed.
    681    * - ``done:deposit-abort-too-late``
    682      - The exchange already wired the deposit; abort could not recover it.
    683    * - ``aborted:deposit-abort-recovered``
    684      - Abort recovery completed, including required refreshes.
    685    * - ``failed:deposit-abort-partial``
    686      - The abort had a mixed or partial outcome across contributions.
    687    * - ``failed:deposit-abort-refund-failed``
    688      - A permanent refund failure prevented establishing complete recovery.
    689    * - ``failed:deposit-abort-recovery-failed``
    690      - Refresh recovery failed after refund/reconciliation.
    691    * - ``failed:kyc-hard-limit``
    692      - Hard-limit rejection with completed recovery.
    693    * - ``failed:deposit`` / ``failed:track``
    694      - Deposit or tracking processing failed.
    695 
    696 An exchange refund acknowledgment is not yet recovered spendable value:
    697 wallet-core waits for the associated refresh. A refund lookup returning 404
    698 also requires reconciliation and refresh; it does not prove successful bank
    699 delivery. The deposit's amounts and recovery details distinguish the settled
    700 financial effect.
    701 
    702 P2P transactions
    703 ================
    704 
    705 Push and pull each have a debit (payer) and a credit (receiver) record. Their
    706 public states describe each wallet's local progress, not one shared state
    707 machine. Preparing or downloading a proposal can precede creation of the
    708 transaction and are not separate transaction states.
    709 
    710 A purse holds funds at the exchange for a P2P payment. Merging it assigns
    711 the funds to the receiver's reserve, from which the receiver withdraws coins.
    712 The sender's payment can therefore be complete before the receiver has
    713 obtained spendable coins.
    714 
    715 Credit-side KYC is shared with the section above. Public ``kyc`` covers
    716 merge authorization; ``balance-kyc`` gates the wallet's resulting balance.
    717 An already committed merge must be reconciled even if the user has aborted.
    718 
    719 Transaction Type: Peer Push Debit
    720 ---------------------------------
    721 
    722 The sender creates and funds a purse, then shares its payment URI while
    723 waiting for the receiver to merge it. Abort or expiry deletes the purse and
    724 recovers value before reaching the appropriate terminal state.
    725 
    726 .. graphviz::
    727    :caption: P2P push: selected sender and receiver paths.
    728    :alt: The sender creates a purse and waits. The receiver accepts and merges it, then withdraws the funds. The sender completes when the merge is observed.
    729    :align: center
    730 
    731    digraph push {
    732      graph [rankdir=TB, newrank=true, bgcolor="transparent", pad=0.15, nodesep=0.35, ranksep=0.42];
    733      node [shape=box, style="rounded,filled", fillcolor="#f3f6fa", color="#526478", fontname="monospace", fontsize=11, margin="0.14,0.10"];
    734      edge [color="#526478", fontname="sans-serif", fontsize=10, arrowsize=0.7];
    735      subgraph cluster_sender {
    736        label="Sender: peer-push-debit"; fontname="sans-serif"; fontsize=12; color="#a8b7c7";
    737        create [label="pending:create-purse\n/working"];
    738        ready [label="pending:ready"];
    739        sent [label="done", fillcolor="#e5f2e9"];
    740        create -> ready [label="purse funded"];
    741        ready -> sent [label="merge observed"];
    742      }
    743      subgraph cluster_receiver {
    744        label="Receiver: peer-push-credit"; fontname="sans-serif"; fontsize=12; color="#a8b7c7";
    745        proposal [label="dialog:proposed"];
    746        merge [label="pending:merge/working"];
    747        withdraw [label="pending:withdraw\n/working"];
    748        received [label="done", fillcolor="#e5f2e9"];
    749        proposal -> merge [label="accept"];
    750        merge -> withdraw [label="merge committed"];
    751        withdraw -> received [label="coins obtained"];
    752      }
    753      { rank=same; create; proposal; }
    754    }
    755 
    756 .. list-table::
    757    :header-rows: 1
    758    :widths: 42 58
    759 
    760    * - State or family
    761      - Progress and available actions
    762    * - ``pending:create-purse/working``; ``pending:ready``
    763      - Create/fund the purse, then wait for its merge. Actions: ``retry``,
    764        ``suspend``, ``abort``. Suspended counterparts: ``resume``, ``abort``.
    765    * - ``aborting:delete-purse/working``
    766      - Deletion/recovery after abort or expiry. Actions: ``retry``, ``suspend``,
    767        ``fail``. ``suspended-aborting:delete-purse``: ``resume``, ``fail``.
    768    * - ``done``, ``aborted``, ``expired``, ``failed``
    769      - Final outcomes. Each advertises ``delete``. Reconciliation can discover
    770        successful delivery despite an abort request.
    771 
    772 Transaction Type: Peer Push Credit
    773 ----------------------------------
    774 
    775 .. list-table::
    776    :header-rows: 1
    777    :widths: 42 58
    778 
    779    * - State or family
    780      - Progress and available actions
    781    * - ``dialog:proposed``
    782      - An incoming offer can be accepted through the P2P API. Generic actions:
    783        ``retry``, ``delete``.
    784    * - Merge and merge KYC
    785 
    786        | ``pending:merge/working``
    787        | ``pending:kyc-init/working``
    788        | ``pending:kyc``
    789      - Merge into the bound reserve, satisfying KYC when needed.
    790        Actions: ``retry``, ``suspend``, ``abort``.
    791        Suspended counterparts: ``resume``, ``abort``.
    792    * - Balance KYC
    793 
    794        | ``pending:kyc-init/working``
    795        | ``pending:balance-kyc``
    796      - Actions: ``suspend``, ``abort``. Suspended counterparts: ``resume``,
    797        ``abort``.
    798    * - ``pending:withdraw/working``
    799      - Obtain the received coins via the child withdrawal. Actions: ``retry``,
    800        ``suspend``, ``fail``. ``suspended:withdraw``: ``resume``, ``fail``.
    801    * - ``finalizing:merge/working``
    802      - An abort is reconciling whether the merge committed. Only ``retry``. If it
    803        committed, continue withdrawing; otherwise the receiver can finish
    804        aborted.
    805    * - ``finalizing:kyc-hard-limit/working``
    806      - Reconcile a hard-limit failure. Only ``retry``; a committed merge can
    807        still require withdrawal.
    808    * - ``done``, ``aborted``, ``expired``, ``failed``, ``failed:kyc-hard-limit``
    809      - Final outcomes. Each advertises ``delete``.
    810 
    811 Transaction Type: Peer Pull Credit
    812 ----------------------------------
    813 
    814 The receiver creates an invoice purse and shares its URI. The payer deposits
    815 into that purse; once it is merged, the receiver withdraws the resulting
    816 funds. Creating the invoice can itself require merge or balance KYC.
    817 
    818 .. graphviz::
    819    :caption: P2P pull: selected invoice creator and payer paths.
    820    :alt: The receiver creates an invoice and waits for payment, then withdraws. The payer confirms the proposal, deposits into the purse, and completes.
    821    :align: center
    822 
    823    digraph pull {
    824      graph [rankdir=TB, newrank=true, bgcolor="transparent", pad=0.15, nodesep=0.35, ranksep=0.42];
    825      node [shape=box, style="rounded,filled", fillcolor="#f3f6fa", color="#526478", fontname="monospace", fontsize=11, margin="0.14,0.10"];
    826      edge [color="#526478", fontname="sans-serif", fontsize=10, arrowsize=0.7];
    827      subgraph cluster_receiver {
    828        label="Receiver: peer-pull-credit"; fontname="sans-serif"; fontsize=12; color="#a8b7c7";
    829        create [label="pending:create-purse\n/working"];
    830        ready [label="pending:ready"];
    831        withdraw [label="pending:withdraw\n/working"];
    832        received [label="done", fillcolor="#e5f2e9"];
    833        create -> ready [label="invoice ready"];
    834        ready -> withdraw [label="payment + merge\nobserved"];
    835        withdraw -> received [label="coins obtained"];
    836      }
    837      subgraph cluster_payer {
    838        label="Payer: peer-pull-debit"; fontname="sans-serif"; fontsize=12; color="#a8b7c7";
    839        proposal [label="dialog:proposed"];
    840        deposit [label="pending:deposit\n/working"];
    841        paid [label="done", fillcolor="#e5f2e9"];
    842        proposal -> deposit [label="accept"];
    843        deposit -> paid [label="deposit accepted"];
    844      }
    845      { rank=same; create; proposal; }
    846    }
    847 
    848 .. list-table::
    849    :header-rows: 1
    850    :widths: 42 58
    851 
    852    * - State or family
    853      - Progress and available actions
    854    * - Invoice creation, payment waiting, and merge KYC
    855 
    856        | ``pending:create-purse/working``
    857        | ``pending:ready``
    858        | ``pending:kyc-init/working``
    859        | ``pending:kyc``
    860      - Create the invoice, wait for payment, or satisfy merge KYC.
    861        Actions: ``retry``, ``suspend``, ``abort``. Suspended counterparts:
    862        ``resume``, ``abort``.
    863    * - Balance KYC
    864 
    865        | ``pending:kyc-init/working``
    866        | ``pending:balance-kyc``
    867      - Actions: ``suspend``, ``abort``. Suspended counterparts: ``resume``,
    868        ``abort``.
    869    * - ``pending:withdraw/working``
    870      - Withdraw the credit. Actions: ``retry``, ``suspend``.
    871        ``suspended:withdraw``: only ``resume``.
    872    * - ``aborting:delete-purse``
    873      - Delete/reconcile after user abort. Actions: ``retry``, ``suspend``,
    874        ``fail``. ``suspended-aborting:delete-purse``: ``resume``, ``fail``.
    875    * - ``finalizing:delete-purse/working``
    876      - Delete/reconcile after expiration. Actions: ``retry``, ``suspend``. The
    877        paused state is ``suspended:delete-purse``, with only ``resume``.
    878    * - ``finalizing:kyc-hard-limit/working``
    879      - Hard-limit cleanup. Only ``retry``. If a payment already merged the purse,
    880        reconcile and withdraw rather than discarding the credit.
    881    * - ``done``, ``aborted``, ``expired``, ``failed``, ``failed:kyc-hard-limit``
    882      - Final outcomes. Each advertises ``delete``.
    883 
    884 Transaction Type: Peer Pull Debit
    885 ---------------------------------
    886 
    887 .. list-table::
    888    :header-rows: 1
    889    :widths: 42 58
    890 
    891    * - State or family
    892      - Progress and available actions
    893    * - ``dialog:proposed``
    894      - Accept the invoice through the P2P API. Generic actions: ``retry``,
    895        ``delete``.
    896    * - ``pending:deposit/working``
    897      - Deposit the payment into the invoice purse. Actions: ``suspend``,
    898        ``abort``. ``suspended:deposit``: ``resume``, ``abort``.
    899    * - ``aborting:deposit/working``
    900      - Reconcile a possibly accepted deposit before deciding what can be
    901        recovered. Only ``suspend``. ``suspended-aborting:deposit``: only
    902        ``resume``.
    903    * - ``aborting:refresh/working``
    904      - Refresh coins that can be recovered. Actions: ``suspend``, ``fail``.
    905        ``suspended-aborting:refresh``: ``resume``, ``fail``.
    906    * - ``done``, ``aborted``, ``expired``, ``failed``
    907      - Final outcomes. Each advertises ``delete``. Reconciliation can discover
    908        that the payment succeeded rather than recovering the coins.
    909 
    910 Other transaction families
    911 ==========================
    912 
    913 Transaction Type: Refund
    914 ------------------------
    915 
    916 Refund records represent credits associated with a merchant payment, separate
    917 from that payment's refund-processing states. The refund states are
    918 ``pending``, ``done``, ``aborted``, ``failed``, or ``expired``, with no minor
    919 component or ``/working`` suffix. Every refund record advertises only
    920 ``delete``. A failed refund group can still contain successful refund items;
    921 inspect its amounts rather than treating failure as a zero credit.
    922 
    923 If ``isAbortRecovery`` is true, the recovered value is already included in
    924 the unsuccessful payment's settled cost. Do not count that refund again
    925 when presenting the net balance effect of the payment and its refunds.
    926 
    927 Transaction Type: Refresh
    928 -------------------------
    929 
    930 Refresh obtains fresh coins from existing value. Denomination reselection
    931 is part of the same processing phase. Refreshes are
    932 normally excluded from the transaction list unless ``includeRefreshes`` or
    933 ``includeAll`` is requested.
    934 
    935 .. list-table::
    936    :header-rows: 1
    937    :widths: 30 70
    938 
    939    * - State
    940      - Progress and available actions
    941    * - ``pending/working``
    942      - Perform refresh or denomination reselection. Actions: ``retry``,
    943        ``suspend``.
    944    * - ``suspended``
    945      - Paused refresh. Only ``resume``.
    946    * - ``done`` / ``failed``
    947      - Processing finished. Only ``delete``.
    948 
    949 Transaction Type: Recoup
    950 ------------------------
    951 
    952 Recoup recovers value affected by denomination revocation. Its public state
    953 and action table is the same as refresh: ``pending/working`` offers
    954 ``retry`` and ``suspend``; ``suspended`` offers ``resume``; ``done`` and
    955 ``failed`` offer ``delete``. It is not modeled as user-abortable work.
    956 
    957 Transaction Type: Denomination Loss
    958 -----------------------------------
    959 
    960 A ``denom-loss`` record accounts for value lost through denomination events.
    961 Its states are ``done`` and ``aborted``, both with only ``delete``. Here
    962 ``done`` means that recording the loss is complete, not that money was
    963 received or recovered.