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.