taler-docs

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

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


      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-02-17
     10 :Implementation evidence: taler-typescript-core (2023-04-22), taler-android (2023-05-15)
     11 :Normative references: ``wallet/wallet-core.md``
     12 
     13 .. contents:: Table of Contents
     14    :depth: 2
     15 
     16 Summary
     17 =======
     18 
     19 This design doc discusses the lifecycle of transactions in wallet-core.
     20 
     21 Motivation
     22 ==========
     23 
     24 The transactions in wallet-core all should have an associated state machine.  All transactions
     25 should have some common actions that work uniformly across all transactions.
     26 
     27 Requirements
     28 ============
     29 
     30 The underlying state machine should make it obvious what interactions
     31 are possible for the user.  The number of possible user interactions
     32 in any state should be small.
     33 
     34 Proposed Solution
     35 =================
     36 
     37 
     38 Common States
     39 -------------
     40 
     41 The following states apply to multiple different transactions.  Only pending
     42 and aborting have transaction-specific sub-states, denoted by ``state(substate)``.
     43 
     44 ``pending``: A pending transaction waits for some external event/service.
     45 The transaction stays pending until its change on the wallet's material balance
     46 is finished. Any pending state can be suspended and resumed.
     47 
     48 There are some other distinctions for pending transactions:
     49 
     50 * long-polling vs. exponential backoff: A pending transaction is either waiting
     51   on an external service by making a long-polling request or by repeating requests
     52   with exponential back-off.
     53 * ``lastError``: A pending transaction is either clean (i.e. the network interaction
     54   is literally active in transmission or the external service successfully
     55   communicated that it is not ready yet and this is perfectly normal)
     56   or has a ``lastError``, which is a ``TalerErrorDetails``
     57   object with details about what happened during the last attempt to proceed
     58   with the transaction.
     59 
     60 ``finalizing``: A finalizing transaction is functionally similar to a ``pending`` transaction,
     61 but is not shown to the user as a pending transaction. It is effectively finished from a user's
     62 perspective, but some processing can happen on the transaction that might lead to some
     63 other state than ``done``.
     64 
     65 ``done``: A transaction that is done does not require any more processing.  It also
     66 never has a ``lastError`` but is considered successful.
     67 
     68 ``dialog``: A transaction requires input from the user.
     69 
     70 ``aborting``: Similar to a pending transaction, but instead of taking active steps to
     71 complete the transaction, the wallet is taking active steps to abort it. The ``lastError``
     72 indicates errors the wallet experienced while taking active steps to abort the transaction.
     73 
     74 ``aborted``: Similar to ``done``, but the transaction was successfully aborted
     75 instead of successfully finished. It will have the information of when (timestamp) it was
     76 aborted and in which pending sub-state the abort action was initiated. Also, we can
     77 include more information information relevant to the transaction in ``abortReason``
     78 
     79 ``suspended``: Similar to a ``aborted`` transaction, but the transaction was could be
     80 resumed and may then still succeed.
     81 
     82 ``suspended-aborting``:  Network requests or other expensive work
     83 to abort a transaction is paused.
     84 
     85 ``failed``: Similar to ``done``, but the transaction could not be completed or
     86 possibly not even be aborted properly.  The user may have lost money.  In some
     87 cases, a report to the auditor would make sense in this state.
     88 
     89 ``expired``: Similar to ``failed``, but the failure was caused by a timeout.
     90 
     91 ``deleted``: A ``deleted`` state is always a final state.  We only use this
     92 state for illustrative purposes. In the implementation, the data associated
     93 with the transaction would be literally deleted.
     94 
     95 
     96 Common Transitions
     97 ------------------
     98 
     99 Transitions are actions or other events.
    100 
    101 ``[action:retry]``: Retrying a transaction *(1.)* stops ongoing long-polling
    102 requests for the transaction *(2.)* resets the retry timeout *(3.)* re-runs the
    103 handler to process the transaction. Retries are always possible the following
    104 states: ``pending(*)`` and ``aborting(*)``.
    105 
    106 .. attention::
    107 
    108    Should we show the retry timeout in the UI somewhere?  Should we show it in dev mode?
    109 
    110    SEBASJM: Since the wallet will retry anyway, maybe is better if we replace the "retry"
    111    button with a "try now" button and a side text "retrying in xxx seconds".
    112 
    113    CG: Instead of a side text, this *might* make a good mouse-over hint for
    114    a "retry" (or "try now") button. I would not make this overly visible with
    115    side-text as the information is not that important. The text should also be
    116    "retrying next at XXX" using an absolute time XXX --- otherwise the UI would
    117    be way too busy recomputing/updating all of these strings: Using an absolute time,
    118    we only have to redraw anything once a retry actually happened. Given that
    119    retries should basically never be > 24h (we can impose a hard cap), the absolute
    120    time can just be in the format HH:MM:SS (without day).
    121 
    122 ``[action:suspend]``: Suspends a pending transaction, stopping any associated
    123 network activities, but with a chance of trying again at a later time. This
    124 could be useful if a user needs to save battery power or bandwidth and an
    125 operation is expected to take longer (such as a backup, recovery or very large
    126 withdrawal operation).
    127 
    128 ``[action:resume]``: Suspended transactions may be resumed, placing them back
    129 into a pending state.
    130 
    131 ``[action:abort]``: Aborting a transaction either directly stops processing for the
    132 transaction and puts it in an ``aborted`` state, or starts the necessary steps to
    133 actively abort the transaction (e.g. to avoid losing money) and puts it in an
    134 ``aborting`` state.
    135 
    136 ``[action:fail]``: Directly puts an ``aborting`` or ``pending`` transaction into a
    137 ``failed`` state. May result in an ultimate loss of funds (beyond fees) to the
    138 user and thus requires additional consent.
    139 
    140 ``[action:delete]``: Deleting a transaction completely deletes the transaction
    141 from the database.  Depending on the type of transaction, some of the other
    142 data *resulting* from the transaction might still survive deletion. For
    143 example, deleting a withdrawal transaction does not delete already
    144 successfully withdrawn coins. Deleting is only safe (no money lost) on initial
    145 and final states (failed, aborted, done).
    146 
    147 Whether aborting, deleting or suspending are possible depends on
    148 the transaction type, and usually only one of the four choices should be
    149 offered.
    150 
    151 
    152 .. image:: ../images/transaction-common-states.png
    153 
    154 
    155 Boxed labels indicate an end state in which there is no network activity and
    156 hence no need to give the user a way to abort or suspend the activity.  The
    157 circle indicates the initial state.  Ovals are states with network activity.
    158 
    159 Blue arrows are used for user-triggered actions (via UI buttons).  Purple
    160 arrows are used to indicate externally triggered actions.  Black arrows
    161 without labels are used for the normal successful path.  Red arrows indicate
    162 failure paths.
    163 
    164 
    165 Common pending sub-states
    166 -------------------------
    167 
    168 During the pending state the transaction can go through several sub-states before
    169 reaching a final state. Some of this sub-states are shared between different
    170 transaction types:
    171 
    172 ``kyc``: The transaction cannot proceed because the user needs to actively
    173 finish a KYC process.  The wallet should show the user a hint on how to
    174 start the KYC process.
    175 
    176 ``kyc-init``: The transaction cannot proceed, as the user needs to actively
    177 finish a KYC process. The information for the KYC process is still loading.
    178 
    179 
    180 Transaction Type: Withdrawal
    181 ----------------------------
    182 
    183 * ``dialog(proposed)``
    184 
    185   Initial dialog state for bank-integrated withdrawals.  In this state, the user must confirm
    186   the withdrawal to proceed, and possibly provide further information (such as the amount).
    187 
    188   Depending on how a bank-integrated withdrawal transaction is created,
    189   it starts either in this state or in ``pending(bank-register-reserve)``.
    190 
    191 
    192 * ``pending(bank-register-reserve)``
    193 
    194   Initial active state for bank-integrated withdrawals.  The wallet submits the reserve public key
    195   and selected exchange to the bank (via the bank integration API).  Note that if the
    196   user aborts at this stage, we do not know if the bank is in the confirmation stage,
    197   so we must still *try* to abort the transaction at the bank.
    198 
    199   * ``[processed-success] => pending(bank-confirm-transfer)``
    200   * ``[processed-error] => failed``: On permanent errors (like 404 for the withdrawal operation),
    201     the wallet gives up.
    202   * ``[action:abort] => aborting(bank)``
    203 
    204 * ``pending(bank-confirm-transfer)``
    205 
    206   The wallet waits until the bank has confirmed the withdrawal operation;
    207   usually the user has to complete a 2FA step to *approve* that the money is
    208   wired to the chosen exchange.  Note that the user's *approve* action is done
    209   in the bank's user interface and not the wallet's user interface. The wallet
    210   internally merely *polls* for the success or failure of the approve action.
    211   The wallet **may** occasionally (after some initial delay, especially on
    212   failures from the bank-poll to return any result) long-poll for the reserve
    213   status and, if successful, may then directly jump to
    214   ``pending(withdraw-coins)`` if the reserve is filled even if the poll at
    215   the bank did not return success or failure.
    216 
    217   * ``[bank-poll-success] => pending(exchange-wait-reserve)``
    218   * ``[bank-aborted] => aborted``: Bank denied the operation.
    219   * ``[exchange-poll-success] => pending(withdraw-coins)``:  Optional
    220     short-cut transition. Exchange was faster than the bank.
    221   * ``[action:abort] => aborting(bank)``
    222 
    223 * ``aborting(bank)``
    224 
    225   The user aborted the withdraw operation in the wallet.  The wallet must now
    226   try to signal the bank that the wire transfer should no longer be performed.
    227   Note that it is possible that the bank registration never succeeded (if the
    228   user aborted us during ``pending(bank-register-reserve)``) and in this case
    229   we get an ``unknown transaction`` failure here.  It is also theoretically
    230   possible that the user approved the transaction in the bank while
    231   simultaneously aborting in the wallet. In this case, we transition to
    232   ``suspended(exchange-wait-reserve)`` (treating the ``abort`` action as a ``suspend``
    233   action).
    234 
    235   * ``[processed-success] => aborted``
    236   * ``[processed-error(already-confirmed)] => suspended(exchange-wait-reserve)``: We
    237     keep a transaction history entry reminding the user about when the already
    238     wired funds will be returned.
    239   * ``[processed-error(unknown-transaction)] => failed``
    240 
    241 * ``suspended(exchange-wait-reserve)``
    242 
    243   State where funds were (presumably) wired to the exchange but the wallet
    244   was asked to not proceed with the withdraw, but we still resume.
    245 
    246   In this state, the wallet should show to the user that the money from the
    247   withdrawal reserve will be sent back to the originating bank account after
    248   ``$closing_delay``.  Note that the ``resume`` action should be disabled
    249   after ``$closing_delay``.
    250 
    251   * ``[action:delete] => deleted``
    252   * ``[action:resume] => pending(exchange-wait-reserve)``
    253 
    254 * ``pending(exchange-wait-reserve)``
    255 
    256   Initial state for manual withdrawals.  Here, the wallet long-polls the
    257   exchange for the reserve status, waiting for the wire transfer to arrive
    258   at the exchange.
    259 
    260   * ``[exchange-poll-success] => pending(withdraw-coins)``
    261   * ``[action:suspend] => suspended(exchange-wait-reserve)``
    262 
    263 * ``pending(withdraw-coins)``
    264 
    265   State where we are finally withdrawing the actual coins. Depending on
    266   the AML and KYC thresholds, we may at any time transition into a
    267   holding pattern on the AML or KYC checks of the exchange.
    268 
    269   It is possible that the selected denominations expired.
    270   In that case, the wallet will re-select denominations.
    271 
    272   * ``[processed-success] => done``
    273   * ``[processed-kyc-required] => pending(kyc)``
    274   * ``[processed-aml-required] => pending(aml)``
    275   * ``[reserve-expired] => expired(reserve)``
    276   * ``[action:suspend] => suspended(withdraw-coins)``
    277 
    278 * ``pending(kyc)``
    279 
    280   State where the user needs to provide some identity data to pass a KYC
    281   check.  The wallet only shows the user the link for starting the KYC
    282   process and long-polls the exchange in anticipation of the user
    283   completing the KYC requirement.
    284 
    285   * ``[poll-success] => pending(withdraw-coins)``
    286   * ``[action:suspend] => suspended(kyc)``
    287 
    288 * ``suspended(kyc)``
    289 
    290   State where the user needs to provide some identity data to pass a KYC
    291   check, but the long-polling was explicitly stopped. The user can
    292   choose to resume or delete.
    293 
    294   * ``[action:delete] => deleted``
    295   * ``[action:resume] => pending(kyc)``
    296 
    297 * ``pending(aml)``
    298 
    299   State where the wallet needs to wait for completion of an AML process by an
    300   AML officer of the exchange. The wallet shows that the AML process is
    301   blocking progress. The message shown should distinguish between a mere
    302   pending AML process and an AML freezing decision in terms of the message
    303   shown to the user. If the AML decision is pending at the exchange, he user
    304   should be urged to simply wait.  If the funds were frozen, the wallet
    305   informs the user that their funds were frozen due to an AML decision.  The
    306   user is urged to contact the exchange operator's AML department out-of-band.
    307   In any case, the wallet long-polls for the AML decision to be made or change
    308   (possibly at a lower frequeny in case of a freeze).
    309 
    310   * ``[poll-success] => pending(withdraw-coins)``
    311   * ``[action:suspend] => suspended(aml)``
    312 
    313 * ``suspended(aml)``
    314 
    315   State where the user needs to await some AML decision by the exchange.
    316   The long-polling was explicitly stopped. The user can choose to resume or delete.
    317 
    318   * ``[action:delete] => deleted``
    319   * ``[action:resume] => pending(aml)``
    320 
    321 * ``suspended(withdraw-coins)``
    322 
    323   In this state, the wallet should show how much money arrived into the wallet
    324   and the rest of the money will be sent back to the originating bank account
    325   after ``$closing_delay``.  Note that the ``resume`` action should be
    326   disabled after ``$closing_delay``.
    327 
    328   * ``[action:delete] => deleted``
    329   * ``[action:resume] => pending(exchange-wait-reserve)``
    330 
    331 * ``done``
    332 
    333   The withdrawal operation is complete.
    334 
    335   * ``[action:delete] => deleted``
    336 
    337 * ``deleted``
    338 
    339   Withdrawn coins are preserved, as is reserve information for recoup.
    340   So this mostly removes the entry from the visible transaction history.
    341   Only once all coins were spent, the withdraw is fully removed.
    342 
    343 
    344 .. image:: ../images/transaction-withdrawal-states.png
    345 
    346 
    347 Transaction Type: Payment to Merchant
    348 -------------------------------------
    349 
    350 * ``pending(claim-proposal)``
    351 
    352   We received a ``pay`` URI. Download (claim) the proposal from the merchant.  Can fail if
    353   the proposal was already claimed by someone else.  If repurchase detection
    354   tells us that we already paid for this product, we go immediately to
    355   ``failed(repurchase)`` state for this transaction, but with a side-effect of
    356   transitioning the UI into a ``pending(repurchase-session-reset)`` on a
    357   *different* transaction (which before was in ``done``).
    358 
    359   A ``failed(repurchase)`` transaction will eventually be GCed (=deleted)
    360   automatically.
    361 
    362   * ``[error:already-claimed] => failed(already-claimed)`` -- the proposal was
    363     already claimed by someone else.
    364   * ``[error:invalid-proposal] => failed(invalid-proposal)`` -- the merchant provided a
    365     proposal that is invalid (e.g. malformed contract
    366     terms or bad signature).
    367 
    368 * ``dialog(merchant-order-proposed)``
    369 
    370   Let the user accept (or refuse) the payment.
    371 
    372   * ``[action:pay-accept] => pending(submit-payment)``
    373   * ``[action:pay-refuse] => aborted(refused)`` -- The user explicitly
    374     decided not to proceed (at least not with this wallet).
    375   * ``[expired] => failed(expired)`` -- The offer has expired before the user made any
    376     decision. Note that we should use this transition at
    377     least a few seconds before the offer *actually* expires to avoid
    378     encountering an expiration during ``pending(submit-payment)`` in most
    379     real-world scenarios. Basically, we should prevent last-second payments to
    380     be event attempted client-side.
    381 
    382     The ``failed(expired)`` might be automatically deleted upon GC.
    383 
    384 * ``pending(submit-payment)``
    385 
    386   Submit coin-by-coin (or in bulk groups) until payment is complete.
    387 
    388   * ``[action:abort] => aborting(pay-incomplete)`` -- The user explicitly decided to
    389     abort the process while the payment was happening.  Note that if the
    390     payment was already completed (and hence the merchant refuses any
    391     refunds), it is theoretically possible that pressing the abort button will
    392     nevertheless end up in a ``finalizing(auto-refund)`` state (and subsequently
    393     a ``done`` state) instead!
    394   * ``[success] => finalizing(auto-refund)`` -- Upon receiving confirmation from
    395     the merchant that the purchase was completed.
    396   * ``[error(insufficient balance)] => aborting(pay-incomplete)`` This transition
    397     happens if we detect double-spending and our balance is not sufficient
    398     after the double-spending. It is also conceivable (but should be rare)
    399     that this transition happens because the offer expired.
    400 
    401 * ``finalizing(auto-refund)``
    402 
    403   The payment succeed. We remain in this state as long as an auto-refund-check
    404   is active.  If auto refunds are not enabled, we immediately continue to
    405   ``done``.
    406 
    407   * ``[no-auto-refund] => done``
    408   * ``[timeout] => done`` -- This happens when the auto refund set by the
    409     contract expired.
    410   * ``[long-poll:refund] => aborting(pay-incomplete)`` -- An auto-refund was detected.
    411   * ``[action:abort] => done`` -- The user may explicitly request to abort the
    412     auto-refund processing (for example to enable subsequent deletion before
    413     the auto-refund delay expires).
    414 
    415 * ``aborting(pay-incomplete)``
    416 
    417   The wallet should interact with the merchant to request
    418   a refund on the incomplete payment.
    419 
    420   * ``[success] => aborted(pay-incomplete)``
    421   * ``[already-paid] => done``
    422 
    423 * ``aborted(refunded)``
    424 
    425   The purchase ended with a (partial) refund. The state (and UI) should show
    426   the specific provenance of the state, which may include an insufficient
    427   balance (due to double-spending being detected during payment), and one or
    428   more partial or full refunds.
    429 
    430   * ``[action:delete] => deleted``
    431 
    432 * ``done``
    433 
    434   The purchase is completed.
    435 
    436   * ``[action:delete] => deleted``
    437   * ``[repurchase] => pending(rebind-session)``: Another offer
    438     became pending for this product and we need to update the session so
    439     that the user does not have to buy it again.
    440   * ``[check-refunds]` => pending(check-refunds)``: New refunds
    441     might be available for this purchase.
    442 
    443 * ``pending(check-refund)``
    444 
    445   New refunds might be available for this purchase.
    446   This state must only be entered *after* the payment has successfully
    447   completed.  It is not relevant for auto-refunds or refunds for incomplete
    448   payments.
    449 
    450   * ``[refunds-checked] => pending(user-new-refund)`` --- New
    451     refund(s) are available, user needs to confirm.
    452   * ``[refunds-checked] => done`` --- Refunds were checked, but no
    453     new refunds are available.
    454   * ``[action:stop-refund-query] => done`` ---
    455     This action would usually only be offered when the state is pending
    456     with errors. It stops the refund query, but the payment of course
    457     is left intact.
    458 
    459 * ``pending(rebind-session)``
    460 
    461   The wallet should reset the associated session for the already purchased
    462   (digital) item.
    463 
    464   * ``[success] => done``
    465   * ``[action:abort] => done`` -- User aborted the session reset.
    466 
    467 * ``deleted``
    468 
    469   When a payment is deleted, associated refund transactions are always deleted
    470   with it.
    471 
    472 .. image:: ../images/transaction-payment-states.png
    473 
    474 
    475 Transaction Type: Refund
    476 ------------------------
    477 
    478 A refund is a pseudo-transaction that is always associated with a merchant
    479 payment transaction.
    480 
    481 * ``pending(accept)``
    482 
    483   Initial state for a refund.
    484 
    485   * ``[processed-error] => failed``: we received a permanent failure (such as money already wired to the merchant)
    486 
    487 * ``failed``
    488 
    489   The refund failed permanently.
    490 
    491 .. image:: ../images/transaction-refund-states.png
    492 
    493 
    494 Transaction Type: Refresh
    495 -------------------------
    496 
    497 This is about refreshes that are triggered via coin expiration or as part of
    498 getting change after making a payment.  In the first case, the refresh
    499 transaction is forever shown as a separate transaction in the history unless
    500 it did not affect the wallet balance (in which case we hide it). In the second
    501 case, the refresh transaction is folded into the payment transaction upon
    502 completion, so that the balance changes are included in the fees of the
    503 transaction that caused us to obtain change.
    504 
    505 If we have to adjust the refund amount (because a coin has fewer funds on it
    506 than we expect) the transaction only shows the changes due to the refresh, and
    507 we merely adjust the current balance of the wallet but without giving any
    508 justification (as we cannot give details we do not have). So this will look
    509 the same as if the double-spending transaction had been deleted by the user.
    510 
    511 * ``pending``
    512 
    513   A refresh operation is pending.
    514 
    515   * ``[processed-success] => done``
    516   * ``[action:suspend] => suspended``
    517   * ``[failed] => failed``
    518 
    519 * ``suspended``
    520 
    521   A refresh operation was suspended by the user.
    522 
    523   * ``[action:resume] => pending``
    524 
    525 * ``done``
    526 
    527   The refresh operation completed.
    528 
    529   * ``[action:delete] => deleted``
    530 
    531 * ``failed``
    532 
    533   The refresh operation failed. The user lost funds.
    534 
    535   * ``[action:delete] => deleted``
    536 
    537 * ``deleted``
    538 
    539   All memory of the refresh operation is lost, but of course the resulting
    540   fresh coins are preserved.
    541 
    542 .. image:: ../images/transaction-refresh-states.png
    543 
    544 
    545 Transaction Type: Deposit
    546 -------------------------
    547 
    548 * ``pending(deposit)``
    549 
    550   Initial state for deposit transactions.
    551   We deposit the amount coin-by-coin (or in bulk groups) until deposit is completed.
    552 
    553   * ``[action:suspend] => suspended(submit-deposit)``
    554   * ``[processed-success] => pending(track)``
    555   * ``[processed-failure] => aborting(refund)``
    556 
    557 * ``suspended(deposit)``
    558 
    559   The user suspended our ongoing deposit operation.
    560 
    561   * ``[action:resume] => pending(deposit)``
    562   * ``[action:abort] => aborting(refund)``
    563 
    564 * ``pending(track)``
    565 
    566   All the coins were submitted, waiting to be wired.
    567 
    568   * ``[poll-success] => done``
    569   * ``[poll-accepted-kyc] => pending(kyc)``
    570   * ``[poll-accepted-aml] => pending(aml)``
    571   * ``[action:abort] => aborting(refund)``
    572 
    573 * ``pending(kyc)``
    574 
    575   Exchange requires KYC before making the wire transfer.
    576 
    577   * ``[long-poll:kyc] => done``
    578   * ``[action:suspend] => suspended(kyc)``
    579 
    580 * ``suspended(kyc)``
    581 
    582   The user suspended us while we were waiting for KYC to be finished.
    583 
    584   * ``[action:resume] => pending(kyc)``
    585 
    586 * ``pending(aml)``
    587 
    588   Exchange requires AML before making the wire transfer.
    589 
    590   * ``[long-poll:aml] => done``
    591   * ``[action:suspend] => suspended(aml)``
    592 
    593 * ``suspended(aml)``
    594 
    595   The user suspended us while we were waiting for AML to be finished.
    596 
    597   * ``[action:resume] => pending(aml)``
    598 
    599 * ``aborting(refund)``
    600 
    601   Wallet should try to get the deposited amount back from the exchange (by submitting a refund).
    602 
    603   * ``[action:suspend] => suspended(refund)``
    604   * ``[processed-success] => aborting(refresh)``
    605   * ``[processed-error] => aborting(refresh)``: Even if the refund attempt failed, maybe the deposit failed as well and we can still succeed with a refresh.
    606 
    607 * ``suspended(refund)``
    608 
    609   The user suspended us while we were trying to get a refund.
    610 
    611   * ``[action:resume] => aborting(refund)``
    612 
    613 * ``aborting(refresh)``
    614 
    615   * ``[action:suspend] => suspended(refresh)``
    616   * ``[processed-success] => aborted``
    617   * ``[processed-error] => failed``
    618 
    619 * ``suspended(refresh)``
    620 
    621   The user suspended us while we were trying to do the refresh.
    622 
    623   * ``[action:resume] => aborting(refresh)``
    624 
    625 * ``aborted``
    626 
    627   The operation was aborted, some funds may have been lost (to fees or deposited anyway).
    628 
    629   * ``[action:delete] => deleted``
    630 
    631 * ``done``
    632 
    633   The deposit operation completed.
    634 
    635   * ``[action:delete] => deleted``
    636 
    637 * ``deleted``
    638 
    639   All memory of the deposit operation is lost.
    640 
    641 .. image:: ../images/transaction-deposit-states.png
    642 
    643 
    644 Transaction Type: Peer Push Debit
    645 ---------------------------------
    646 
    647 Peer Push Debit transactions are created when the user wants to transfer money
    648 to another wallet.
    649 
    650 States and transitions:
    651 
    652 * ``pending(purse-create)``
    653 
    654   The wallet is creating a purse. Initial state.
    655 
    656   * ``[process-success] => pending(ready)``: The wallet has created the purse.
    657   * ``[process-failure] => aborting(refund)``: The purse creation failed.
    658   * ``[action:suspend] => suspended(purse-create)``: The user suspended the operation.
    659 
    660 * ``suspended(purse-create)``
    661 
    662   * ``[action:resume] => pending(purse-create)``: The user resumed the operation.
    663   * ``[action:abort] => aborting(refund)``: The user aborted the operation.
    664 
    665 * ``pending(ready)``
    666 
    667   In this state, the user can send / show the ``taler://`` URI or QR code to somebody else.
    668 
    669   * ``[action:abort] => aborting(delete-purse)``: The user aborts the P2P payment. The wallet tries to reclaim money in the purse.
    670   * ``[purse-timeout] => aborting(refresh)``: The other party was too slow and the purse has now expired.
    671   * ``[poll-success] => done``: The other party has accepted the payment.
    672   * ``[poll-error] => aborting(refresh)``: The exchange claims that there is a permanent error regarding the purse.  (FIXME(CG): not clear that this is the best transition! Could also go to ``aborting(refund)`` or ``aborting(delete-purse)``; best choice may depend on the specific error returned.)
    673 
    674 * ``aborting(delete-purse)``
    675 
    676   The wallet is deleting the purse to prevent the receiver from merging it and to reclaim the funds in it.
    677 
    678   * ``[processed-success] => aborting(refresh)``: The purse was deleted successfully, and refunded coins must be refreshed.
    679   * ``[processed-failed(already-merged)] => done``: The other party claimed the funds faster that we were able to abort.
    680   * ``[processed-failed(other)] => aborting(refresh)``:  The exchange reports a permanent error.  We still try to refresh.
    681   * ``[action:fail] => failed``: The user explicitly asked us to give up and accepted the possible loss of funds.
    682 
    683 * ``aborting(refund)``
    684 
    685   We abandon the purse that was never fully funded and ask for the deposited coins to be refunded.
    686 
    687   * ``[processed-success] => aborting(refresh)``: After the refund, we still need to refresh the coins.
    688   * ``[processed-failure] => aborting(refresh)``: The refund failed, we still try to refresh the coins.
    689   * ``[action:fail] => failed``: The user explicitly asked us to give up and accepted the possible loss of funds.
    690 
    691 * ``aborting(refresh)``
    692 
    693   * ``[processed-success] => aborted``: Refresh group finished. Aborting was successful, money was reclaimed.
    694   * ``[processed-failed] => failed``: Refresh group failed to complete with a permanent error.
    695   * ``[action:fail] => failed``: The user explicitly asked us to give up and accepted the possible loss of funds.
    696 
    697 * ``done``
    698 
    699   The transfer was successful.
    700 
    701   * ``[action:delete] => deleted``
    702 
    703 * ``aborted``
    704 
    705   The transfer was aborted. Except for fees, the money was recovered.
    706 
    707   * ``[action:delete] => deleted``
    708 
    709 * ``failed``
    710 
    711   The transfer failed. Money was lost. Unless on a forced abort, we should probably complain to the auditor.
    712 
    713   * ``[action:delete] => deleted``
    714 
    715 * ``deleted``
    716 
    717   All memory of the push debit operation is lost.
    718 
    719 .. image:: ../images/transaction-push-debit-states.png
    720 
    721 
    722 Transaction Type: Peer Push Credit
    723 ----------------------------------
    724 
    725 Peer Push Credit transactions are created when the user accepts to be paid via
    726 a ``taler://pay-push`` URI.
    727 
    728 States and transitions:
    729 
    730 * ``pending(download)``
    731 
    732   Wallet read the taler:// URI and is downloading the contract details for the user.
    733 
    734   * ``[processed-success] => pending(user)``: Contract can be shown to the user.
    735   * ``[action:suspend] => suspended(download)``: User suspended the operation.
    736 
    737 * ``suspended(download)``
    738 
    739   The download of the purse meta data was suspended by the user.
    740 
    741   * ``[action:resume] => pending(download)``
    742 
    743 * ``pending(user)``
    744 
    745   User needs to decide about accepting the money.
    746 
    747   * ``[action:accept] => pending(merge)``
    748   * ``[timeout] => failed``: User took too long to decide.
    749 
    750 * ``pending(merge)``
    751 
    752   * ``[processed-success] => pending(withdraw)``: Merging the reserve was successful.
    753   * ``[kyc-required] => pending(merge-kyc)``: User must pass KYC checks before the purse can be merged.
    754   * ``[timeout] => failed``: The purse expired before we could complete the merge.
    755   * ``[failure] => failed``: The merge failed permanently.
    756   * FIXME(CG): do we want to allow suspending here?
    757 
    758 * ``pending(merge-kyc)``
    759 
    760   We cannot merge the purse until passing a KYC check.
    761   The user is shown a hint where to begin the KYC
    762   process and the wallet long-polls on the KYC status.
    763 
    764   * ``[poll-success] => pending(withdraw)``
    765   * ``[action:suspend] => suspended(kyc)``
    766   * ``[timeout] => failed``: The purse expired before we could complete the merge.
    767 
    768 * ``suspended(merge-kyc)``
    769 
    770   We cannot merge the purse until passing a KYC check,
    771   and that check was suspended by the user.
    772 
    773   * ``[action:resume] => pending(kyc)``
    774   * ``[timeout] => failed``: The purse expired before we could complete the merge.
    775 
    776 * ``pending(withdraw)``
    777 
    778   The wallet is withdrawing coins from the reserve that was filled by merging
    779   the purse.
    780 
    781   * ``[kyc-required] => pending(withdraw-kyc)``
    782   * ``[aml-required] => pending(withdraw-aml)``
    783   * ``[withdraw-failure] => failed``
    784   * ``[withdraw-success] => done``
    785   * ``[action:suspend] => suspended(withdraw)``
    786 
    787 * ``suspended(withdraw)``
    788 
    789   The user requested the withdraw operation to be suspended.
    790 
    791   * ``[action:resume] => pending(withdraw)``
    792 
    793 * ``pending(withdraw-kyc)``
    794 
    795   We cannot withdraw more coins until passing a KYC check.
    796   The user is shown a hint where to begin the KYC
    797   process and the wallet long-polls on the KYC status.
    798 
    799   * ``[poll-success] => pending(withdraw-coins)``
    800   * ``[action:suspend] => suspended(withdraw-kyc)``
    801 
    802 * ``suspended(withdraw-kyc)``
    803 
    804   We cannot withdraw from the reserve until passing a KYC check,
    805   and that check was suspended by the user.
    806 
    807   * ``[action:resume] => pending(withdraw-kyc)``
    808 
    809 * ``pending(withdraw-aml)``
    810 
    811   We cannot withdraw more coins until AML rules are satisfied.
    812   The user is shown a hint as to the AML status (pending or frozen).
    813 
    814   * ``[poll-success] => pending(withdraw-coins)``
    815   * ``[action:suspend] => suspended(withdraw-aml)``
    816 
    817 * ``suspended(withdraw-aml)``
    818 
    819   We cannot withdraw from the reserve until AML rules are satisfied,
    820   and the status check was suspended by the user.
    821 
    822   * ``[action:resume] => pending(withdraw-aml)``
    823   * ``[action:delete] => deleted``
    824 
    825 * ``failed``
    826 
    827   The operation failed. Details are shown to the user. The money from the purse eventually goes to the sender (or some other wallet that merged it).
    828 
    829   * ``[action:delete] => deleted``
    830 
    831 * ``done``
    832 
    833   The operation succeeded.
    834 
    835   * ``[action:delete] => deleted``: No money will be lost, the withdrawn coins will be kept
    836 
    837 * ``deleted``
    838 
    839   All memory of the push credit operation is lost.
    840 
    841 .. image:: ../images/transaction-push-credit-states.png
    842 
    843 
    844 Transaction Type: Peer Pull Credit
    845 ----------------------------------
    846 
    847 TODO: Also specify variant where account reserve needs to be created / funded first (Note: post 1.0-feature).
    848 
    849 * ``pending(purse-create)``
    850 
    851   The wallet is creating a purse. Initial state.
    852 
    853   * ``[process-success] => pending(ready)``: The wallet has created the purse.
    854   * ``[process-failure] => deleted``: The purse creation failed. We only show a transient error.
    855   * ``[action:abort] => deleted``: The user aborted the operation.
    856 
    857 * ``pending(ready)``
    858 
    859   In this state, the user can send / show the ``taler://`` URI or QR code to
    860   somebody else.
    861 
    862   * ``[action:abort] => aborting(delete-purse)``: The user aborts the P2P payment.
    863   * ``[purse-timeout] => aborted``: The other party was too slow and the purse
    864     has now expired.
    865   * ``[poll-success] => pending(withdraw)``: The other party has made the payment.
    866   * ``[poll-error] => aborting(delete-purse)``: The exchange claims that there
    867     is a permanent error regarding the purse.  We should try to delete it.
    868 
    869 * ``aborting(delete-purse)``
    870 
    871   We are cleaning up the purse after the operation failed or was aborted by
    872   the user.
    873 
    874   * ``[failure:already-merged] => pending(withdraw)``: Too late to abort, the
    875     other side already paid the invoice.
    876   * ``[process-success] => aborted``: The wallet has deleted the purse.
    877   * ``[failure:other] => failed``: The purse deletion failed; we are
    878     nevertheless done.
    879   * ``[action:fail] => failed``: Money may be lost if it was deposited
    880     into the purse in the meantime.
    881 
    882 * ``aborted``
    883 
    884   The invoicing process ended without success.
    885 
    886   * ``[action:delete] => deleted``
    887 
    888 * ``pending(withdraw)``
    889 
    890   The wallet is withdrawing the money paid for the invoice.
    891 
    892   * ``[processed-success] => done``
    893   * ``[failure] => failed``
    894   * ``[processed-kyc] => pending(kyc)``
    895   * ``[processed-aml] => pending(aml)``
    896   * ``[action:suspend] => suspended(withdraw)``
    897 
    898 * ``suspended(withdraw)``
    899 
    900   The user suspended a withdraw operation.
    901 
    902   * ``[action:resume] => pending(withdraw)``
    903 
    904 * ``pending(kyc)``
    905 
    906   The user must supply KYC information before withdrawing can continue.
    907 
    908   * ``[poll-success] => pending(withdraw)``
    909   * ``[action:suspend] => suspended(kyc)``
    910 
    911 * ``suspended(kyc)``
    912 
    913   The user suspended waiting for the KYC operation to complete.
    914 
    915   * ``[action:resume] => pending(kyc)``
    916 
    917 * ``pending(aml)``
    918 
    919   The user must await a positive exchange AML decision.
    920 
    921   * ``[poll-success] => pending(withdraw)``
    922   * ``[action:suspend] => suspended(aml)``
    923 
    924 * ``suspended(aml)``
    925 
    926   The user suspended waiting for the AML decision to be successful.
    927 
    928   * ``[action:resume] => pending(aml)``
    929 
    930 * ``failed``
    931 
    932   Obtaining the money for the invoce failed. This is likely a case for the
    933   auditor.
    934 
    935   * ``[action:delete] => deleted``
    936 
    937 * ``done``
    938 
    939   The payment for the invoice was successfully received.
    940 
    941   * ``[action:delete] => deleted``
    942 
    943 * ``deleted``
    944 
    945 .. image:: ../images/transaction-pull-credit-states.png
    946 
    947 
    948 Transaction Type: Peer Pull Debit
    949 ---------------------------------
    950 
    951 * ``pending(download)``
    952 
    953   We are downloading the information about the invoice.  Initial state.
    954 
    955   * ``[action:suspend] => suspended(download)``
    956   * ``[success] => pending(user)``
    957 
    958 * ``suspended(download)``
    959 
    960   User suspended downloading the information about the invoice.
    961 
    962   * ``[action:resume] => pending(download)``
    963   * ``[action:delete] => deleted``
    964 
    965 * ``pending(user)``
    966 
    967   We have downloaded information about the pull payment and are waiting for
    968   the user to confirm.
    969 
    970   * ``[action:confirm-pay] => pending(deposit)``
    971   * ``[action:delete] => deleted``
    972   * ``[timeout] => aborted``
    973 
    974 * ``pending(deposit)``
    975 
    976   The user has confirmed the payment and the wallet tries to deposit
    977   into the provided purse.
    978 
    979   * ``[action:suspend] => suspended(deposit)``
    980   * ``[processed-success] => done``
    981   * ``[failure:timeout] => aborting(refresh)``
    982   * ``[failure:other] => aborting(refund)``
    983 
    984 * ``suspended(deposit)``
    985 
    986   User suspended depositing into the purse.
    987 
    988   * ``[action:resume] => pending(deposit)``
    989   * ``[action:abort] => aborting(refund)``
    990 
    991 * ``aborting(refund)``
    992 
    993   Aborts the payment, asking for the already deposited coins to be refunded.
    994 
    995   * ``[processed-success] => aborted(refunded)``
    996   * ``[processed-failure] => aborting(refresh)``
    997   * ``[action:fail] => failed``
    998 
    999 * ``aborting(refresh)``
   1000 
   1001   Refreshes the coins that were previously deposited into the purse to recover their value.
   1002 
   1003   * ``[processed-success] => aborted``
   1004   * ``[processed-failed] => failed``
   1005 
   1006 * ``done``
   1007 
   1008   The invoice was successfully paid.
   1009 
   1010   * ``[action:delete] => deleted``
   1011 
   1012 * ``deleted``
   1013 
   1014   All information about the invoice has been deleted.
   1015 
   1016 .. image:: ../images/transaction-pull-debit-states.png
   1017 
   1018 
   1019 UI Strings for Transaction States
   1020 =================================
   1021 
   1022 * ``pending(kyc-init)``
   1023 
   1024   * Transactions: withdrawal, deposit, peer-push-credit, peer-pull-credit
   1025   * Title: "Preparing legitimization"
   1026 
   1027 * ``pending(kyc)``:
   1028 
   1029   * Transactions: withdrawal, deposit, peer-push-credit, peer-pull-credit
   1030   * Title: "Legitimization required"
   1031 
   1032 * ``pending(balance-kyc)``:
   1033 
   1034   * Transactions: withdrawal, deposit, peer-push-credit, peer-pull-credit, refund (?)
   1035   * Title: "Exceeds balance limit"
   1036 
   1037 * ``pending(kyc-auth)``:
   1038 
   1039   * Title: "Legitimization required"
   1040   * Alt Title: "Bank account verification required"
   1041   * Alt Title: "Verify bank account"
   1042 
   1043 * ``pending(accept-refund)``
   1044 
   1045   * Title: "Checking for refund"
   1046   * Alt title: "Processing refund"
   1047 
   1048     * User doesn't care about this info
   1049 
   1050 * ``finalizing(auto-refund)``
   1051 
   1052   * Title: TBD
   1053 
   1054 * ``pending(check-refund)``
   1055 
   1056   * Title: "Checking for refund"
   1057 
   1058 * ``aborted(completed-by-other-wallet)``
   1059 
   1060   * Title: "Completed by other wallet"
   1061 
   1062 * ``pending(bank-confirm-transfer)``
   1063 
   1064   * Title: "Waiting for bank transfer"
   1065 
   1066 * ``withdrawal:aborted(exchange)``
   1067 
   1068   * Title: "Aborted"
   1069   * Description: Mention that money will come back via bank account transfer.
   1070 
   1071 * ``pay:dialog(proposed)``
   1072 
   1073   * TBD (=> Vlada?)
   1074 
   1075 * ``pay:failed(paid-by-other)``
   1076 
   1077   * Title: "Paid with other wallet"
   1078 
   1079 * ``pending(ready)``
   1080 
   1081   * Title: "Ready"
   1082 
   1083 * ``pending(rebind-session)``
   1084 
   1085   * Title: "Restoring access"
   1086 
   1087 * ``finalizing(track)``
   1088 
   1089   * Title: TBD
   1090 
   1091 
   1092 Minor states just shown as ``pending/aborting/...`` (i.e. no more
   1093 details shown to the user):
   1094 
   1095 * ``failed(aborting-bank)``
   1096 * ``aborting(bank)``
   1097 * ``pending(bank-register-reserve)``
   1098 * ``pending(claim-proposal)``
   1099 * ``pending(create-purse)``
   1100 * ``aborting(delete-purse)``
   1101 * ``pending(deposit)``
   1102 * ``withdrawal:pending(exchange-wait-reserve)``
   1103 * ``peer-push-credit:pending(merge)``
   1104 * ``aborting(refresh)``
   1105 * ``aborted(refused)``
   1106 * ``pending(submit-payment)``
   1107 * ``pending(withdraw)``
   1108 * ``pending(withdraw-coins)``
   1109 * ``failed(repurchase)`` (anyway only shows in dev mode)
   1110 
   1111 
   1112 Alternatives
   1113 ============
   1114 
   1115 * Each transaction could be treated completely separately; however, uniform
   1116   terminology for actions (and thus button labels) is likely more helpful for
   1117   the user experience.
   1118 
   1119 * We could require user re-approval if fees changed when the available
   1120   denominations change during a *withdraw*.  This would require a different
   1121   state machine on withdraw. We believe the answer can be "no", for two
   1122   reasons: the wallet MUST pick denominations to withdraw with the "most
   1123   long-term" withdraw window (i.e. active denominations that have the longest
   1124   available withdraw durations). So in virtually all normal cases, this will
   1125   just succeed as a sane exchange will have a reasonable duration overlap, and
   1126   in the very few cases it's really the user's fault for going offline in the
   1127   middle of the operation. Plus, even in those few cases, it is highly
   1128   unlikely that the fee would actually change: again most key rotations can be
   1129   expected to be there to rotate the key, and not to adjust the withdraw fee.
   1130   And in the extremely rare case that the user went offline and in the
   1131   meantime the fees did *increase*, it's again unlikely to matter much to the
   1132   user. So special-casing this and testing this is probably not worth it.
   1133 
   1134 * We could require user re-approval if due to expired/invalid coins the coin
   1135   selection (and thus fees) changes during a *deposit*.  Again, expired coins
   1136   should virtually never happen unless a user goes offline for a long time in
   1137   the middle of a purchase (which would be very strange). If deposit fees
   1138   *increase* due to a double-spend detection during payment, we might want to
   1139   have an *optional* dialog ("Balance reduced by X as wallet state was not
   1140   up-to-date (did you restore from backup?).  Consequently, the fees for this
   1141   transactions increased from Y to Z.  [Abort] [Continue] + checkbox: [X] Do
   1142   not ask again."). Probably at best a post-1.0 feature.
   1143 
   1144 
   1145 Discussion / Q&A
   1146 ================
   1147 
   1148 * The diagrams only show what is happening **after** the wallet
   1149   has created the transaction.  It is possible that network requests
   1150   are happening before that, but they are not considered to be part
   1151   of the transaction.
   1152 * We have decided against a ``cancel`` state, because it resulted
   1153   in too much complexity.  Instead of doing a direct ``cancel``,
   1154   the user has to go to the transaction and abort and/or delete
   1155   it.
   1156 * We might add a ``revive`` action in the future that allows
   1157   to go from ``aborting`` back to ``pending`` for transactions
   1158   where this makes sense.  We're not doing it right now
   1159   to simplify things.