diff options
author | Christian Grothoff <christian@grothoff.org> | 2023-04-09 17:22:43 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2023-04-09 17:22:43 +0200 |
commit | 9e148c42d940ddcfafe1394f0461d40bceabb008 (patch) | |
tree | ee4db2e4836e8194364488a2f152b98dac0b9a41 /design-documents | |
parent | 836ec500bdbdb91a07110b1455f0f6cf2d26fa7c (diff) | |
download | docs-9e148c42d940ddcfafe1394f0461d40bceabb008.tar.gz docs-9e148c42d940ddcfafe1394f0461d40bceabb008.tar.bz2 docs-9e148c42d940ddcfafe1394f0461d40bceabb008.zip |
more work on DD37 review
Diffstat (limited to 'design-documents')
-rw-r--r-- | design-documents/037-wallet-transactions-lifecycle.rst | 284 |
1 files changed, 210 insertions, 74 deletions
diff --git a/design-documents/037-wallet-transactions-lifecycle.rst b/design-documents/037-wallet-transactions-lifecycle.rst index a08fe07f..3242e695 100644 --- a/design-documents/037-wallet-transactions-lifecycle.rst +++ b/design-documents/037-wallet-transactions-lifecycle.rst @@ -56,7 +56,9 @@ include more information information relevant to the transaction in `abortReason ``suspended``: Similar to a ``aborted`` transaction, but the transaction was could be resumed and may then still succeed. -``failed``: Similar to ``done``, but the transaction could not even be aborted properly. +``failed``: Similar to ``done``, but the transaction could not even be aborted +properly. The user may have lost money. This is likely a case for a report to +the auditor. ``deleted``: A ``deleted`` state is always a final state. We only use this state for illustrative purposes. In the implementation, the data associated @@ -68,13 +70,6 @@ Common Transitions Transitions are actions or other events. -``[action:delete]``: Deleting a transaction -completely deletes the transaction from the database. Depending on the type of -transaction, some of the other data *resulting* from the transaction might -still survive deletion. For example, deleting a withdrawal transaction does not -delete already successfully withdrawn coins. Deleting is only safe (no money lost) -on initial and final states (failed, aborted, done). - ``[action:retry]``: Retrying a transaction *(1.)* stops ongoing long-polling requests for the transaction *(2.)* resets the retry timeout *(3.)* re-runs the handler to process the transaction. Retries are always possible the following @@ -96,11 +91,6 @@ states: ``pending(*)`` and ``aborting(*)``. retries should basically never be > 24h (we can impose a hard cap), the absolute time can just be in the format HH:MM:SS (without day). -``[action:abort]``: Aborting a transaction either directly stops processing for the -transaction and puts it in an ``aborted`` state, or starts the necessary steps to -actively abort the transaction (e.g. to avoid losing money) and puts it in an -``aborting`` state. - ``[action:suspend]``: Suspends a pending transaction, stopping any associated network activities, but with a chance of trying again at a later time. This could be useful if a user needs to save battery power or bandwidth and an @@ -110,22 +100,43 @@ withdrawal operation). ``[action:resume]``: Suspended transactions may be resumed, placing them back into a pending state. -``[action:abort-force]``: Directly puts an ``aborting`` transaction into the -``failed`` state. +``[action:abort]``: Aborting a transaction either directly stops processing for the +transaction and puts it in an ``aborted`` state, or starts the necessary steps to +actively abort the transaction (e.g. to avoid losing money) and puts it in an +``aborting`` state. + +``[action:force-abort]``: Directly puts an ``aborting`` transaction into a +``failed`` state. May result in an ultimate loss of funds (beyond fees) to the +user and thus requires additional consent. +``[action:delete]``: Deleting a transaction completely deletes the transaction +from the database. Depending on the type of transaction, some of the other +data *resulting* from the transaction might still survive deletion. For +example, deleting a withdrawal transaction does not delete already +successfully withdrawn coins. Deleting is only safe (no money lost) on initial +and final states (failed, aborted, done). -Whether aborting or resuming are possible depends on the transaction type, and -usually only one of the two choices should be offered. +``[action:force-delete]``: Directly puts a transaction into a ``deleted`` +state. May result in an ultimate loss of funds (beyond fees) to the user and +thus requires additional consent. + + +Whether aborting, deleting or suspending are possible depends on the +transaction type, and usually only one of the three choices should be offered. .. image:: ../transaction-common-states.png :width: 400 -Boxed labels indicate an end state in which it is safe to delete the -transaction record since no work is due. +Boxed labels indicate an end state in which there is no network activity and +hence no need to give the user a way to abort or suspend the activity. The +circle indicates the initial state. Ovals are states with network activity. -Blue arrows are used for user-triggered actions (via UI buttons). +Blue arrows are used for user-triggered actions (via UI buttons). Purple +arrows are used to indicate externally triggered actions. Black arrows +without labels are used for the normal successful path. Red arrows indicate +failure paths. Common pending sub-states @@ -135,18 +146,18 @@ During the pending state the transaction can go through several sub-states befor reaching a final state. Some of this sub-states are shared between different transaction types: -``kyc-required``: The transaction can't proceed because the user needs to actively -finish a KYC process. Part of a withdrawal process or peer-to-peer push credit. - -``aml-required``: The transaction can't proceed because the user needs to wait for -the exchange operator to conclude an AML investigation by the staff at the exchange. -The user is not expected to take any action and should just wait for the investigation -to conclude. Part of a withdrawal process or peer-to-peer push credit. +``kyc``: The transaction cannot proceed because the user needs to actively +finish a KYC process. The wallet should show the user a hint on how to +start the KYC process. -``aml-frozen``: The staff at the exchange decided that the account needed to be frozen. -The user should contact the exchange provider's customer service department and -seek resolution (possibly through the courts) to avoid loosing the funds for good. -Part of a withdrawal process or peer-to-peer push credit. +``aml``: The transaction can't proceed because the user needs to wait for the +exchange operator to conclude an AML investigation by the staff at the +exchange. There are two AML substates. In the substate ``pending`` the user +is not expected to take any action and should just wait for the investigation +to conclude. In the substate ``frozen`` the staff at the exchange decided that +the account needed to be frozen. The user should contact the exchange +provider's customer service department and seek resolution (possibly through +the courts) to avoid loosing the funds for good. Transaction Type: Withdrawal @@ -193,15 +204,19 @@ Transaction Type: Withdrawal ``suspended(after-wired)`` (treating the ``abort`` action as a ``suspend`` action). - * ``[processed-success] => deleted``: We show a transient message that the operation was aborted. - * ``[processed-error(already-confirmed)] => suspended(after-wired)``: We keep a transaction history entry reminding the user about when the already wired funds will be returned. + * ``[processed-success] => deleted``: We show a transient message that the + operation was aborted. + * ``[processed-error(already-confirmed)] => suspended(after-wired)``: We + keep a transaction history entry reminding the user about when the already + wired funds will be returned. * ``[processed-error(unknown-transaction)] => deleted`` * ``suspended(after-wired)`` - In this state, the wallet should show to the user that the money from the withdrawal - reserve will be sent back to the originating bank account after ``$closing_delay``. - Note that the ``resume`` action should be disabled after ``$closing_delay``. + In this state, the wallet should show to the user that the money from the + withdrawal reserve will be sent back to the originating bank account after + ``$closing_delay``. Note that the ``resume`` action should be disabled + after ``$closing_delay``. * ``[action:delete] => deleted`` * ``[action:resume] => pending(exchange-wait-reserve)`` @@ -369,22 +384,31 @@ Transaction Type: Payment to Merchant is active. If auto refunds are not enabled, we immediately continue to ``done``. - * ``[timeout] => done`` -- This happens when the auto refund set by the contract expired. - * ``[action:abort] => done`` -- The user may explicitly request to abort the auto-refund processing (for example to enable subsequent deletion before the auto-refund delay expires). + * ``[timeout] => done`` -- This happens when the auto refund set by the + contract expired. + * ``[long-poll:refund] => aborting(refund)`` -- An auto-refund was detected. + * ``[action:abort] => done`` -- The user may explicitly request to abort the + auto-refund processing (for example to enable subsequent deletion before + the auto-refund delay expires). * ``aborting(refund)`` The wallet should interact with the merchant to confirm that a refund was approved. - * ``[success] => aborted(refunded)`` - * ``[failure] => aborting(refresh)`` + * ``[success] => aborting(refresh)`` + * ``[failure] => aborting(refresh)``: Try refresh anyway. + * ``[action:force-delete] => deleted``: User may loose money. * ``aborting(refresh)`` The wallet should interact with the exchange to obtain fresh coins for the refunded balance. + * ``[success] => aborted(refunded)`` + * ``[failure] => failed`` + * ``[action:force-delete] => deleted``: User may loose money. + * ``aborted(refunded)`` The purchase ended with a (partial) refund. The state (and UI) should show @@ -392,8 +416,6 @@ Transaction Type: Payment to Merchant balance (due to double-spending being detected during payment), and one or more partial or full refunds. - * ``[URI:refund] => aborting(refund)`` -- The previous refund was partial, - and we have received an additional refund for this transaction. * ``[action:delete] => deleted`` * ``done`` @@ -401,46 +423,49 @@ Transaction Type: Payment to Merchant The purchase is completed. * ``[action:delete] => deleted`` - * ``[repurchase] => pending(repurchase-session-reset)`` -- Another offer became pending for this product. + * ``[repurchase] => pending(repurchase-session-reset)``: Another offer + became pending for this product and we need to update the session so + that the user does not have to buy it again. * ``pending(repurchase-session-reset)`` - The wallet should reset the associated session for the already purchased item. + The wallet should reset the associated session for the already purchased + (digital) item. * ``[success] => done`` * ``[action:abort] => done`` -- User aborted the session reset. * ``deleted`` - When a payment is deleted, associated refunds are always deleted with it. + When a payment is deleted, associated refund transactions are always deleted + with it. .. image:: ../transaction-payment-states.png :width: 800 -Purple arrows are used to indicate transitions triggered in special ways outside -of the user interface for this transaction, such as side-effects of repurchase -detection for another purchase or opening of a refund URI. - Transaction Type: Refund ------------------------ -A refund is a pseudo-transaction that is always associated with a merchant payment transaction. +A refund is a pseudo-transaction that is always associated with a merchant +payment transaction. * ``pending(lookup-refund)`` - We received a ``refund`` URI. Download refund details (like the amount) from the merchant. If the merchant responds with a permanent failure, we only show a transient warning and delete the transaction. + We received a ``refund`` URI. Download refund details (like the amount) from + the merchant. If the merchant responds with a permanent failure, we only + show a transient warning and delete the transaction. * ``[success] => pending(user-accept)`` * ``[action:suspend] => suspended(lookup-refund)`` - * ``[failure] => deleted`` + * ``[failure] => deleted``: A transient warning is shown to the user about the failure. * ``suspended(lookup-refund)`` The user suspended while we were looking up the refund details. Allow resuming or permanent deletion. * ``[action:resume] => pending(lookup-refund)`` - * ``[action:delete] => deleted`` + * ``[action:force-delete] => deleted``: Refund funds will be lost to the user. * ``pending(user-accept)`` @@ -457,6 +482,13 @@ A refund is a pseudo-transaction that is always associated with a merchant payme * ``[processed-success] => pending(refresh)`` * ``[processed-error] => failed``: we received a permanent failure (such as money already wired to the merchant) +* ``suspended(merchant)`` + + Refund processing was suspended while waiting for the merchant. + + * ``[action:resume] => pending(merchant)`` + * ``[action:force-delete] => deleted`` + * ``pending(refresh)`` The wallet is now refreshing the coins. @@ -465,6 +497,12 @@ A refund is a pseudo-transaction that is always associated with a merchant payme * ``[action:suspend] => suspended(refresh)`` * ``[processed-error] => failed``: we received a permanent failure. +* ``suspended(refresh)`` + + Refund processing was suspended while waiting for the refresh to complete. + + * ``[action:resume] => pending(refresh)`` + * ``[action:force-delete] => deleted`` * ``failed`` @@ -497,13 +535,14 @@ the same as if the double-spending transaction had been deleted by the user. * ``[processed-success] => done`` * ``[action:suspend] => suspended`` + * ``[failed] => failed`` * ``suspended`` A refresh operation was suspended by the user. * ``[action:resume] => pending`` - * ``[action:delete] => deleted`` + * ``[action:force-delete] => deleted`` * ``done`` @@ -511,6 +550,12 @@ the same as if the double-spending transaction had been deleted by the user. * ``[action:delete] => deleted`` +* ``failed`` + + The refresh operation failed. The user lost funds. + + * ``[action:delete] => deleted`` + * ``deleted`` All memory of the refresh operation is lost, but of course the resulting @@ -536,7 +581,7 @@ Transaction Type: Tip The user suspended the operation to download the tip data. - * ``[action:delete] => deleted`` + * ``[action:force-delete] => deleted`` * ``[action:resume] => pending(query)`` * ``pending(user)`` @@ -546,7 +591,7 @@ Transaction Type: Tip * ``[tip-expired] => failed`` * ``[action:accept] => pending(pickup)`` - * ``[action:abort] => deleted`` + * ``[action:force-delete] => deleted`` * ``pending(pickup)`` @@ -561,7 +606,7 @@ Transaction Type: Tip The user suspended the operation while the tip was being picked up. - * ``[action:delete] => deleted`` + * ``[action:force-delete] => deleted`` * ``[tip-expired] => failed`` * ``[action:resume] => pending(pickup)`` @@ -579,7 +624,7 @@ Transaction Type: Tip the tip expires, as the wallet balance threshold KYC likely applies even without the tip. - * ``[action:delete] => deleted`` + * ``[action:force-delete] => deleted`` * ``[action:resume] => pending(kyc)`` * ``done`` @@ -641,7 +686,7 @@ Transaction Type: Deposit The user suspended us while we were trying to get a refund. * ``[action:resume] => aborting(refund)`` - * ``[action:delete] => deleted`` + * ``[action:force-delete] => deleted`` * ``aborting(refresh)`` @@ -654,7 +699,7 @@ Transaction Type: Deposit The user suspended us while we were trying to do the refresh. * ``[action:resume] => aborting(refresh)`` - * ``[action:delete] => deleted`` + * ``[action:force-delete] => deleted`` * ``aborted`` @@ -725,6 +770,7 @@ States and transitions: * ``[processed-success] => aborting(refresh)``: After the refund, we still need to refresh the coins. * ``[processed-failure] => aborting(refresh)``: The refund failed, we still try to refresh the coins. + * ``[action:abort-force] => failed``: The user explicitly asked us to give up and accepted the possible loss of funds. * ``aborting(refresh)`` @@ -761,7 +807,7 @@ States and transitions: All memory of the push debit operation is lost. .. image:: ../transaction-push-debit-states.png - :width: 400 + :width: 600 Transaction Type: Peer Push Credit @@ -772,34 +818,124 @@ a ``taler://pay-push`` URI. States and transitions: -* ``initial`` +* ``pending(download)`` - Wallet read the taler:// URI and the transaction was initialized + Wallet read the taler:// URI and is downloading the contract details for the user. - * ``[processed-success] => pending(withdrawing)``: Merging the reserve was successful + * ``[processed-success] => pending(user)``: Contract can be shown to the user. + * ``[action:suspend] => suspended(download)``: User suspended the operation. -* ``pending(withdrawing-coins)`` +* ``suspended(download)`` - * ``[processed-kyc-required] => pending(kyc-required)`` + The download of the purse meta data was suspended by the user. -* ``pending(kyc-required)`` + * ``[action:resume] => pending(download)`` + * ``[action:force-delete] => deleted`` + +* ``pending(user)`` + + User needs to decide about accepting the money. + + * ``[action:accept] => pending(merge)`` + * ``[action:force-delete] => deleted`` + * ``[timeout] => failed``: User took too long to decide. + +* ``pending(merge)`` + + * ``[processed-success] => pending(withdraw)``: Merging the reserve was successful. + * ``[kyc-required] => pending(merge-kyc)``: User must pass KYC checks before the purse can be merged. + * ``[timeout] => failed``: The purse expired before we could complete the merge. + * ``[failure] => failed``: The merge failed permanently. + * FIXME(CG): do we want to allow suspending here? + +* ``pending(merge-kyc)`` + + We cannot merge the purse until passing a KYC check. + The user is shown a hint where to begin the KYC + process and the wallet long-polls on the KYC status. + + * ``[poll-success] => pending(withdraw)`` + * ``[action:suspend] => suspended(kyc)`` + * ``[timeout] => failed``: The purse expired before we could complete the merge. + +* ``suspended(merge-kyc)`` + + We cannot merge the purse until passing a KYC check, + and that check was suspended by the user. + + * ``[action:resume] => pending(kyc)`` + * ``[action:force-delete] => deleted`` + * ``[timeout] => failed``: The purse expired before we could complete the merge. + +* ``pending(withdraw)`` + + The wallet is withdrawing coins from the reserve that was filled by merging + the purse. + + * ``[kyc-required] => pending(withdraw-kyc)`` + * ``[aml-required] => pending(withdraw-aml)`` + * ``[withdraw-failure] => failed`` + * ``[withdraw-success] => done`` + * ``[action:suspend] => suspended(withdraw)`` + +* ``suspended(withdraw)`` + + The user requested the withdraw operation to be suspended. + + * ``[action:resume] => pending(withdraw)`` + * ``[action:force-delete] => deleted``: Money is lost. + +* ``pending(withdraw-kyc)`` + + We cannot withdraw more coins until passing a KYC check. + The user is shown a hint where to begin the KYC + process and the wallet long-polls on the KYC status. * ``[poll-success] => pending(withdrawing-coins)`` - * ``[action:abort] => aborted``: The user will lose the coins they were not able to withdraw yet, unless they - resume the transaction again. Exchange should return non-withdrawn coins discounting closing fee. + * ``[action:suspend] => suspended(withdraw-kyc)`` -* ``aborted`` +* ``suspended(withdraw-kyc)`` + + We cannot withdraw from the reserve until passing a KYC check, + and that check was suspended by the user. + + * ``[action:resume] => pending(withdraw-kyc)`` + * ``[action:force-delete] => deleted``: Money is lost. + +* ``pending(withdraw-aml)`` - * ``[action:resume] => pending(withdrawing-coins)`` -(??) this is not possible since aborted is final + We cannot withdraw more coins until AML rules are satisfied. + The user is shown a hint as to the AML status (pending or frozen). - * ``[action:delete] => deleted``: The user will irrevocable lose coins that were not withdrawn from the reserve yet. -(??) no, i think aborting a push-credit should return to the sender, like a refund + * ``[poll-success] => pending(withdrawing-coins)`` + * ``[action:suspend] => suspended(withdraw-aml)`` + +* ``suspended(withdraw-aml)`` + + We cannot withdraw from the reserve until AML rules are satisfied, + and the status check was suspended by the user. + + * ``[action:resume] => pending(withdraw-aml)`` + * ``[action:delete] => deleted`` + +* ``failed`` + + 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). + + * ``[action:delete] => deleted`` * ``done`` + The operation succeeded. + * ``[action:delete] => deleted``: No money will be lost, the withdrawn coins will be kept +* ``deleted`` + + All memory of the push credit operation is lost. + +.. image:: ../transaction-push-credit-states.png + :width: 600 Transaction Type: Peer Pull Credit |