23.38. DD 37: Wallet Transaction Lifecycle#
- Design status:
Accepted
- Implementation status:
Implemented
- DD shepherd:
TBD
- Historical contributors:
Sebastian, Özgür Kesim, Christian Grothoff, Florian Dold
- First published:
2023-02-13
- Last substantive change:
2026-09-07
- Normative references:
23.38.1. Summary#
This document describes the transaction lifecycle exposed by wallet-core: what a transaction is doing, what lets it progress, and which actions a frontend can request. It defines the common state model and the meaning of each transaction’s stages without prescribing screen layouts or translated strings.
Transactions in the same state can have different available actions,
depending on their type and circumstances. Frontends must use the returned
txActions rather than reconstruct permissions from the state name.
23.38.2. State notation and public data#
States are written as major[:minor][/working]. For example, dialog:proposed,
pending:withdraw/working, pending:kyc, and done.
Diagram labels may wrap after a colon or before /working; the line break
is not part of the state string. The colon and minor component are omitted
when there is no minor state; /working is appended only when
txState.working is true.
/working signals that the transaction is in an active processing phase.
UIs typically show a loading indicator during this phase and keep it until
the flag clears. Processing includes time spent awaiting HTTP responses or
retry delays; the flag does not measure instantaneous CPU or network activity.
When it clears, the UI renders the resulting state: often a pending wait for
an external event, a dialog requiring a user decision, or a finalizing or
terminal outcome. Clearing /working does not imply successful completion.
A pending transaction without /working generally waits for a condition
to change. Wallet-core may still poll, send requests, and resume processing
automatically once that condition changes. Finalizing work can likewise
continue without an active loading indicator. The flag describes one
transaction’s processing phase for presentation, not overall wallet activity.
For example:
pending:withdraw/working: active withdrawal processing, typically shown with a loading indicator.pending:exchange-wait-reserve: waiting for funding while polling the exchange.dialog:proposed: waiting for a user decision.finalizing:track: background tracking of bank delivery.done: completion.
In a state expression, /idle matches working being false
or absent. It can therefore match dialog and terminal states as well as
pending waits; it is not a separate lifecycle stage. Omitting the qualifier
from a state expression accepts either value of working. A displayed
state simply omits the suffix when the flag is false or absent; it
does not append /idle.
State expressions select states; they are distinct from the concrete state
labels in the tables and diagrams. An expression with an omitted minor
component matches any minor: pending is equivalent to pending:*.
Use pending:- to match only a pending state with no minor component.
Thus pending/idle selects pending states whose working flag is false
or absent, regardless of their minor. pending:kyc/idle selects only the
operation-KYC wait. * matches any major or minor component, and
comma-separated expressions select any of their alternatives.
The working flag is primarily transitional. A future lifecycle model may
express the distinction between active processing and waiting through
separate major states instead of this flag and its /working and /idle
qualifiers. This document describes the current representation; the future
major-state names and migration are not specified here.
Use the major state to identify suspension and txActions to determine
available actions. A suspended major state takes precedence over the
processing hint: render the transaction as paused even if working is
still true. The processing hint does not grant action permissions.
The tables below group states with shared behavior and list each family’s members in the left column. The same public state can appear in different contexts with different actions. Diagrams show selected paths; their conceptual groups are explicitly labeled. They omit repeated retry and suspension edges, and do not imply that every transaction visits every node.
23.38.3. Using lifecycle data in a UI#
Read type, txState, txActions, and the transaction details together.
The type and minor state explain the operation, the major state determines
its lifecycle stage, and working guides the loading indicator. Translate
these into user-facing descriptions rather than displaying state expressions
as the ordinary status text. For an unfamiliar minor state, retain the
major-state presentation and use the returned actions and details.
Field |
Meaning |
|---|---|
|
Lifecycle stage and optional operation-specific detail. Minor states also occur in dialog, finalizing, suspended, and terminal stages. |
|
An active-processing hint used for loading indicators, as described above. It does not measure progress or determine action permissions. |
|
Currently advertised generic actions: |
|
Details of an attempt that encountered an error. A recoverable network
error does not itself make the transaction |
|
Reasons for abandoning the original operation or for failure, where supplied. Consult these and the transaction-specific details to distinguish recovery outcomes. |
|
Transaction amount before fees or extra costs. |
|
Amount shown at confirmation, including estimated fees. It is preserved if the operation fails, expires, or is aborted. |
|
Settled wallet balance effect when known, including fees and recovery. It is nonnegative; the transaction type determines debit or credit. Absence means that the amount is not yet settled or cannot be established, not that its value is zero. |
Use the settled amount to describe the actual wallet balance effect when it is available, and distinguish it from the original confirmation amount. State alone does not establish how much value was delivered, recovered, or lost. A wallet balance effect also does not establish receipt of a bank transfer by the counterparty. Ordinary merchant refunds remain separate credit records.
After a transaction-state-transition notification, refresh the affected
transaction’s details and actions. The notification is a reason to refresh,
not a replacement for the full transaction. A deleted transition removes
the entry from the UI; a lookup may also find that it has already disappeared.
Fetch current data when reopening a screen or reconnecting to wallet-core,
since the UI may not have observed every transition. After requesting an
action, display the resulting state rather than assuming the action completed
the transaction.
Accepting a proposed transaction uses its transaction-specific confirmation action. These confirmations, following a bank confirmation URL, visiting a KYC URL, and making a bank transfer are separate from the generic transaction actions.
23.38.4. Common States#
Major state |
Meaning |
|---|---|
|
A proposal or choice is waiting for the user, or an order is waiting for another wallet. It is not a terminal state. |
|
The requested operation has more work to do. It may be actively processing or waiting for the bank, exchange, another wallet, or KYC. |
|
Post-processing or recovery remains. Payment auto-refund monitoring and deposit tracking use this stage, but so does hard-limit recovery of an unsuccessful operation. It does not universally mean success. |
|
The wallet is reconciling or recovering an operation that was aborted or expired. Cancellation can race with successful completion. |
|
The pending operation is paused and may be resumed. This is not an aborted or failed outcome. |
|
Paused abort processing or finalizing work. |
|
Successful completion of this transaction record. Subsequent explicit operations, such as requesting a refund or restoring a payment session, can make a payment active again. |
|
The original operation was abandoned. Recovery and partial effects must be read from the transaction details. |
|
Processing ended unsuccessfully. This alone does not imply that all funds were lost. |
|
The operation ended because its validity period elapsed, after any required cleanup. |
|
Notification-only endpoints: creation has no preceding state, and deletion has no remaining transaction history entry. |
The final states are done, aborted, failed, expired, and
deleted. Here, final means that ordinary processing of the transaction
has ended; an explicit later operation may reactivate it. Suspended states,
dialog, and finalizing are not final.
Common lifecycle: selected paths, with operation details omitted.#
23.38.5. Common Transitions#
Action |
Effect when advertised |
|---|---|
|
Reset the associated task so another attempt can run without waiting for its existing retry delay. It does not approve a proposal, bypass KYC, or guarantee progress. |
|
Pause processing while retaining the ability to resume. The usual major-state pairs are pending/suspended, aborting/suspended-aborting, and finalizing/suspended-finalizing. |
|
Restore the corresponding active operation. The minor state normally identifies the work to resume. |
|
Abandon the requested operation, possibly after reconciliation, purse deletion, refunds, or refreshes. It can finish successfully if the counterparty already completed the operation. |
|
Stop the operation in failure without completing further recovery. It is different from abort and can leave funds unrecovered. |
|
Remove the history record according to its transaction-specific cleanup rules. It does not reverse payments, erase already withdrawn coins, or substitute for refund or abort. |
Actions are not universal even within one major state. For example, deposit
KYC before submission does not advertise retry, while aggregate KYC does;
refund records advertise only delete, even while pending. Some finalizing
records allow deletion, but hard-limit recovery normally allows only retry.
The operation tables below specify these differences. A state can change
between reading it and requesting an action; refresh the transaction when
wallet-core rejects a now-unavailable action.
23.38.6. KYC and balance limits#
The exchange’s KYC/AML design is described in DD 23: Taler KYC; endpoint contracts are in Exchange RESTful API.
Public state |
Meaning and continuation |
|---|---|
|
Wallet-core is obtaining KYC details or initializing wallet balance authorization. This is used by withdrawals, deposits, and P2P credits. There is not yet a usable KYC continuation just because a transaction has entered this state. |
|
Operation-specific KYC has an access token. Wallet-core supplies a KYC URL and polls the exchange. Used for withdrawal, deposit/aggregation, and P2P merge requirements. |
|
A withdrawal or P2P credit would exceed the authorized wallet balance at the exchange. Wait for authorization or for a balance change that makes the incoming amount permissible. |
|
A direct deposit requires proof of control of its target bank account.
Follow |
|
An operation exceeded a hard limit. Wallet-core performs operation-specific cleanup; passing ordinary KYC cannot raise that hard limit. |
|
The original operation failed after hard-limit handling. Inspect
|
Ordinary KYC waiting has suspended counterparts with the same minor component.
Paused deposit recovery can expose suspended-finalizing:kyc-hard-limit.
There is no public merge-kyc, withdraw-kyc, or aml minor state.
Merge KYC is exposed as kyc-init or kyc. Exchange aml_review
influences polling; wallet-core does not expose a separate
transaction state distinguishing staff review from a user-interactive check.
Consequently, pending:kyc does not prove that further user input is needed.
Shared KYC flow: selected waiting paths; return to the interrupted operation.#
The KYC diagram shows common paths, not a compulsory sequence. An operation can start with known authorization, retry directly, or move back through initialization. A bank-account authentication request can also arise after ordinary deposit KYC has already started.
23.38.6.1. KYC data and polling#
kycUrl identifies the exchange’s KYC web interface. Treat it as a
continuation for a transaction whose KYC details are available, not as proof
that KYC succeeded.
Offer the supplied URL when the transaction is waiting in kyc or
balance-kyc and the URL is available. During kyc-init, show that KYC
details are being obtained; the presence of a URL alone does not establish
that initialization is complete. Do not construct a continuation URL from
state names. The KYC access token grants access to the account’s KYC process
and is not a user-facing identifier.
kycAuthTransferInfo.debitPaytoUri specifies the account that must send the
authentication transfer; a transfer from another account will not authenticate
it. accountPub identifies the account key. Prefer transferOptionsExt:
it groups transfer instructions, amounts, and expiry by exchange credit
account. Use the supplied account-specific instructions and amounts for the
authentication transfer.
Wallet-core monitors the exchange’s authorization status and rechecks whether the operation can proceed as authorization, limits, or the balance change. The UI does not need to poll the exchange itself. When the user returns from the KYC page, refresh the transaction and show its current state. Merely closing that page does not complete a transaction, and continued KYC waiting does not necessarily mean that the user must submit information again.
An account’s KYC status can include limits that still restrict the particular operation. Wallet-core evaluates the operation, projected balance, and relevant transaction volume against these limits. A hard limit may also reject an operation during preparation, before a transaction is created.
Balance authorization is shared by transactions at the same exchange. It covers the projected wallet balance after the incoming operation, including value awaiting refresh. Fees do not increase that coin balance. Use the balance and limit information supplied by wallet-core for explanations; reconstructing it from the visible transaction list can miss relevant value or account-specific limits.
23.38.6.2. Hard-limit recovery#
When an in-progress operation encounters a hard limit, it reports
WALLET_KYC_LIMIT_EXCEEDED and starts recovery rather than remaining
indefinitely in ordinary operation-KYC waiting:
Withdrawals request reserve closure back to the originating account. A successful close and a permanently failed close both end in
failed:kyc-hard-limit; the failure reason distinguishes them. Temporary failures keep recovery active. Acceptance of reserve closure is not proof that the bank has already credited the return transfer.Deposits use refund and refresh recovery. Fully recovered hard-limit deposits end in
failed:kyc-hard-limit; partial recovery, refund failure, or an already completed wire transfer use the deposit outcomes below.P2P push credits reconcile whether a merge committed. P2P pull credits delete/reconcile the purse. If funds were already merged, recovery can continue through withdrawal instead of immediately ending in failure.
Balance authorization has its own exchange-level lifecycle. A balance-KYC wait does not necessarily enter the transaction hard-limit recovery path described here.
23.38.7. Transaction Type: Withdrawal#
Manual and bank-integrated withdrawals eventually wait for reserve funding
and withdraw coins. Bank-integrated withdrawals additionally register the
reserve and wait for confirmation at the bank. Depending on how the
operation was prepared, approval in the wallet can precede transaction
creation or appear as dialog:proposed. This wallet approval is separate
from confirmation of the transfer at the bank.
Withdrawal progress, with bank-only steps on the right.#
State or family |
Progress and available actions |
|---|---|
|
Confirm the withdrawal through its dedicated API, or |
|
Register the reserve, then wait for bank confirmation. Actions: |
|
Wait for reserve funding, then withdraw. Actions: |
|
Withdraw selected coins; reselect denominations when necessary, with no
additional public state for that step. Actions: |
KYC initialization and waiting pending:kyc-init/workingpending:kycpending:balance-kyc |
Actions: |
|
Ask the bank to abort. Actions: |
|
Return-to-origin recovery. Only |
Terminal outcomes donefailedfailed:aborting-bankfailed:kyc-hard-limitaborted:bankaborted:exchangeaborted:refusedaborted:completed-by-other-wallet |
Only |
When the bank rejects an abort because it already confirmed the transfer
(HTTP 409), wallet-core retains suspended:exchange-wait-reserve so the
withdrawal can be resumed. A successful bank abort becomes aborted:bank;
an unknown bank operation becomes failed. Aborting a manual withdrawal
before observed funding produces aborted:exchange; it does not undo a
bank transfer. Do not promise a returned amount or arrival time from that
state alone.
Withdrawals performed as part of P2P receipts or other operations are tracked
through the containing transaction. A P2P credit can remain
pending:withdraw/working while its underlying withdrawal is in KYC or
recovery; the containing transaction need not expose every sub-step.
23.38.8. Transaction Type: Payment#
A merchant payment claims an order, obtains user approval, and submits the payment. A shared/unclaimed order may instead wait for another wallet. After payment, monitoring auto-refunds is finalizing work. Explicit refund checks and session restoration can reactivate a completed payment.
rebind-session restores access to an already paid order in another
merchant session; it does not request another purchase. auto-refund
checks for merchant-offered refunds, check-refund performs an explicit
refund check, and accept-refund processes the offered refund. These
stages can therefore occur after the original payment succeeded.
Main payment path and automatic refund monitoring.#
After processing a refund, wallet-core returns to finalizing:auto-refund
if the auto-refund deadline is still in the future. That repeated monitoring
path is omitted from the diagram; its final done node applies when no
more monitoring remains. done appears at both exits to keep the flow
readable.
State or family |
Progress and available actions |
|---|---|
|
An ordinary or shared proposal. Confirm through the payment API; generic
actions are |
|
An unclaimed/shared order is waiting on another wallet. Generic action:
|
Pending processing pending:claim-proposal/workingpending:submit-payment/workingpending:rebind-session/workingpending:auto-refund/workingpending:check-refund/workingpending:accept-refund/working |
Each advertises |
|
Wait for automatic refunds after successful payment. A refund moves to
|
|
Paused automatic refund monitoring. Actions: |
|
Abort payment using refund/recovery processing. Actions: |
Terminal outcomes doneabortedaborted:refusedaborted:continued-with-other-walletexpiredfailedfailed:claim-proposalfailed:abortfailed:paid-by-otherfailed:repurchase |
Each advertises |
Aborting a session replay or an explicit refund check returns the payment to
done; it does not undo the original payment. Payment abort can also race
with payment completion. Repurchase detection creates a
failed:repurchase record, normally filtered from history, while restoring
access through the original payment. Refund credits are separate records;
a payment returning to done after accepting a refund does not mean that
no refund occurred.
23.38.9. Transaction Type: Deposit#
A direct deposit sends coins to an exchange for delivery to a bank account.
After submission, finalizing:track waits for the exchange’s wire-transfer
status, taking the wire deadline into account. Tracking can discover a new
KYC requirement and make the transaction pending again.
Deposit submission, delivery tracking, and abort recovery.#
State or family |
Progress and available actions |
|---|---|
|
Submit deposits. Actions: |
Submission KYC pending:kyc-init/workingpending:kycpending:kyc-auth |
Actions: |
Aggregation KYC pending:kyc-init/workingpending:kyc |
KYC after deposits were submitted. Actions: |
|
Track delivery. Actions: |
|
Delivery tracking on older transactions. Active actions: |
|
Refund deposited contributions and refresh recoverable coins. Actions:
|
|
Recovery after a hard-limit rejection. Only |
|
Paused hard-limit recovery. Actions: |
All terminal outcomes below advertise delete. Their states distinguish
delivery, recovered value, and unsuccessful recovery.
Outcome |
Interpretation |
|---|---|
|
Ordinary deposit completed. |
|
The exchange already wired the deposit; abort could not recover it. |
|
Abort recovery completed, including required refreshes. |
|
The abort had a mixed or partial outcome across contributions. |
|
A permanent refund failure prevented establishing complete recovery. |
|
Refresh recovery failed after refund/reconciliation. |
|
Hard-limit rejection with completed recovery. |
|
Deposit or tracking processing failed. |
An exchange refund acknowledgment is not yet recovered spendable value: wallet-core waits for the associated refresh. A refund lookup returning 404 also requires reconciliation and refresh; it does not prove successful bank delivery. The deposit’s amounts and recovery details distinguish the settled financial effect.
23.38.10. P2P transactions#
Push and pull each have a debit (payer) and a credit (receiver) record. Their public states describe each wallet’s local progress, not one shared state machine. Preparing or downloading a proposal can precede creation of the transaction and are not separate transaction states.
A purse holds funds at the exchange for a P2P payment. Merging it assigns the funds to the receiver’s reserve, from which the receiver withdraws coins. The sender’s payment can therefore be complete before the receiver has obtained spendable coins.
Credit-side KYC is shared with the section above. Public kyc covers
merge authorization; balance-kyc gates the wallet’s resulting balance.
An already committed merge must be reconciled even if the user has aborted.
23.38.10.1. Transaction Type: Peer Push Debit#
The sender creates and funds a purse, then shares its payment URI while waiting for the receiver to merge it. Abort or expiry deletes the purse and recovers value before reaching the appropriate terminal state.
P2P push: selected sender and receiver paths.#
State or family |
Progress and available actions |
|---|---|
|
Create/fund the purse, then wait for its merge. Actions: |
|
Deletion/recovery after abort or expiry. Actions: |
|
Final outcomes. Each advertises |
23.38.10.2. Transaction Type: Peer Push Credit#
State or family |
Progress and available actions |
|---|---|
|
An incoming offer can be accepted through the P2P API. Generic actions:
|
Merge and merge KYC pending:merge/workingpending:kyc-init/workingpending:kyc |
Merge into the bound reserve, satisfying KYC when needed.
Actions: |
Balance KYC pending:kyc-init/workingpending:balance-kyc |
Actions: |
|
Obtain the received coins via the child withdrawal. Actions: |
|
An abort is reconciling whether the merge committed. Only |
|
Reconcile a hard-limit failure. Only |
|
Final outcomes. Each advertises |
23.38.10.3. Transaction Type: Peer Pull Credit#
The receiver creates an invoice purse and shares its URI. The payer deposits into that purse; once it is merged, the receiver withdraws the resulting funds. Creating the invoice can itself require merge or balance KYC.
P2P pull: selected invoice creator and payer paths.#
State or family |
Progress and available actions |
|---|---|
Invoice creation, payment waiting, and merge KYC pending:create-purse/workingpending:readypending:kyc-init/workingpending:kyc |
Create the invoice, wait for payment, or satisfy merge KYC.
Actions: |
Balance KYC pending:kyc-init/workingpending:balance-kyc |
Actions: |
|
Withdraw the credit. Actions: |
|
Delete/reconcile after user abort. Actions: |
|
Delete/reconcile after expiration. Actions: |
|
Hard-limit cleanup. Only |
|
Final outcomes. Each advertises |
23.38.10.4. Transaction Type: Peer Pull Debit#
State or family |
Progress and available actions |
|---|---|
|
Accept the invoice through the P2P API. Generic actions: |
|
Deposit the payment into the invoice purse. Actions: |
|
Reconcile a possibly accepted deposit before deciding what can be
recovered. Only |
|
Refresh coins that can be recovered. Actions: |
|
Final outcomes. Each advertises |
23.38.11. Other transaction families#
23.38.11.1. Transaction Type: Refund#
Refund records represent credits associated with a merchant payment, separate
from that payment’s refund-processing states. The refund states are
pending, done, aborted, failed, or expired, with no minor
component or /working suffix. Every refund record advertises only
delete. A failed refund group can still contain successful refund items;
inspect its amounts rather than treating failure as a zero credit.
If isAbortRecovery is true, the recovered value is already included in
the unsuccessful payment’s settled cost. Do not count that refund again
when presenting the net balance effect of the payment and its refunds.
23.38.11.2. Transaction Type: Refresh#
Refresh obtains fresh coins from existing value. Denomination reselection
is part of the same processing phase. Refreshes are
normally excluded from the transaction list unless includeRefreshes or
includeAll is requested.
State |
Progress and available actions |
|---|---|
|
Perform refresh or denomination reselection. Actions: |
|
Paused refresh. Only |
|
Processing finished. Only |
23.38.11.3. Transaction Type: Recoup#
Recoup recovers value affected by denomination revocation. Its public state
and action table is the same as refresh: pending/working offers
retry and suspend; suspended offers resume; done and
failed offer delete. It is not modeled as user-abortable work.
23.38.11.4. Transaction Type: Denomination Loss#
A denom-loss record accounts for value lost through denomination events.
Its states are done and aborted, both with only delete. Here
done means that recording the loss is complete, not that money was
received or recovered.