DD 41: Wallet Balance and Amount Definitions
############################################
Summary
=======
This design document discusses terminology and concepts used in the wallet
for balances and amounts.
Motivation
==========
There are many different types of balances and amounts, and they need
to have a clear definition.
Furthermore, the user in some situations needs to know/decide whether
an amount that the user chooses includes fees or not.
Proposed Solution
=================
Amounts
-------
* ``effective``: An effective amount always represents the direct effect on the
wallet's balance of the same currency.
* ``raw``: The raw amount always refers to the amount with fees applied.
The exact interpretation of that depends on the transaction type.
* ``instructed``: An instructed amount always refers to the amount that
a user has explicitly specified as an input. It is not directly a property
of transactions, but might be added as metadata to transactions for
informational purposes. How the instructed amount is interpreted
differs based on the "instructed amount mode" that is specified
together with the amount.
* ``counterparty-effective``: An amount that **estimates** the effect
of the transaction of the balance (either wallet or bank account) of the other
party. This is usually a conservative estimate, i.e. when sending money,
this is the lower bound for the funds that the other party will obtain
*after* fees.
Instructed Amount Modes
-----------------------
* ``raw-mode``: The instructed amount represents the raw amount. This is the default.
* ``effective-mode``: The instructed amount represents the effective amount, i.e.
the direct change to the balance.
* ``counterparty-effective-mode``: The instructed amount represents the effective
amount seen from the counterparty. In other words, it is the direct
difference to the counterparty's balance.
Balances
--------
The following types of balances are defined:
- ``available``: Balance that the wallet believes will certainly be available
for spending, modulo any failures of the exchange or double spending issues.
This includes available coins *not* allocated to any
spending/refresh/... operation. Pending withdrawals are *not* counted
towards this balance, because they are not certain to succeed.
Pending refreshes *are* counted towards this balance.
This balance type is nice to show to the user, because it does not
temporarily decrease after payment when we are waiting for refreshes
- ``material``: Balance that the wallet believes it could spend *right now*,
without waiting for any operations to complete.
This balance type is important when showing "insufficient balance" error messages.
- ``age-acceptable``: Subset of the material balance that can be spent
with age restrictions applied.
- ``counterparty-acceptable``: Subset of the material balance that can be spent with a particular
merchant or peer-to-peer transfer.
- ``counterparty-depositable``: Subset of the receiver-acceptable balance that the counterpary
can accept via their supported wire methods.
- ``exchange-depositable``: Subset of the receiver-acceptable balance that the counterpary
can accept via their supported wire methods.
While not quite a balance, we also define the following balance-related term:
- ``max-merchant-effective-deposit-amount``: Estimated maximum amount that the
wallet could pay for, under the assumption that the merchant pays absolutely
no fees.
Raw Amount Definitions
----------------------
Raw amount is…
Manual Withdrawal
… the money that is wired from the user's bank account to the
exchange's bank account for the withdrawal.
Deposit
… the amount leaving the exchange account without the wire fees.
Peer Pull Credit
… the amount that is withdrawn from the purse (via merge reserve) that
the counterparty fills.
Peer Push Debit
… what the counterparty expects in the purse.
Peer Push Credit
… the purse_value in the exchange to be withdrawn.
Merchant Payment
… the amount the merchant should get if is not doing aggregated transaction.
Wire fees are ignored.
Peer Pull Debit
… the net value of the invoice without fees.
Refund
… the amount that the merchant refunded.
Details per Transaction Type
----------------------------
.. warning::
This section is possibly incomplete / out of date.
Manual Withdrawal
~~~~~~~~~~~~~~~~~
.. code:: none
if instructed_amount mode = raw
raw_amount = instructed_amount
effective_amount = instructed_amount - coins.withdrawal_fee
if instructed_amount mode = effective
raw_amount = instructed_amount + coins.withdrawal_fee
effective_amount = instructed_amount
Deposit
~~~~~~~
.. code:: none
if instructed_amount mode = raw
raw_amount = instructed_amount
effective_amount = instructed_amount + coins.deposit_fee + coins.refresh_fee + wire.transfer_fee
if instructed_amount mode = effective
raw_amount = instructed_amount - coins.deposit_fee - coins.refresh_fee - wire.transfer_fee
effective_amount = instructed_amount
Peer Pull Credit
~~~~~~~~~~~~~~~~
.. code:: none
if instructed_amount mode = raw
raw_amount = instructed_amount
effective_amount = instructed_amount - coins.withdrawal_fee - purse_fee
if instructed_amount mode = effective
raw_amount = instructed_amount + coins.withdrawal_fee + purse_fee
effective_amount = instructed_amount
if instructed_amount mode = counterparty
raw_amount = instructed_amount - coins.counterparty_deposit_fee
effective_amount = instructed_amount - coins.counterparty_deposit_fee - coins.withdrawal_fee - purse_fee
counterparty_raw_amount = raw_amount
counterparty_effective_amount = raw_amount + coins.counterparty_deposit_fee
.. note::
counterparty_effective_amount is an estimation since refresh fee is not included.
Refresh fee can't be calculated because depends on the coins available in the wallet
of the counterparty
.. note::
coins.counterparty_deposit_fee is the minimum deposit_fee that can be calculated for the
given exchange. Counter-party may pay more if it have different preferences doing the coin
selection.
Peer Push Debit
~~~~~~~~~~~~~~~
.. code:: none
coins = select-coin-for-operation(debit, mode, instructed_amount)
if instructed_amount mode = raw
raw_amount = instructed_amount
effective_amount = instructed_amount + coins.deposit_fee + purse_fee
if instructed_amount mode = effective
raw_amount = instructed_amount - coins.deposit_fee - purse_fee
effective_amount = instructed_amount
if instructed_amount mode = counterparty
raw_amount = instructed_amount + coins.counterparty_withdraw_fee
effective_amount = instructed_amount - coins.counterparty_withdraw_fee - coins.withdrawal_fee - purse_fee
counterparty_raw_amount = raw_amount
counterparty_effective_amount = raw_amount - coins.counterparty_withdraw_fee
.. note::
``coins.counterparty_withdraw_fee`` is the minimum withdraw_fee that can be calculated for the
given exchange. Counter-party may pay more if it have different preferences doing the coin
selection.
.. note ::
how much wire_fee the merchant is willing to pay
merchant_wire_fee = min(wire.transfer_fee / contractTerms.amortization_factor, contractTerms.max_wire_fee)
merchant_deposit_fee = min(contractTerms.max_fee, contract_wire_fee)
Merchant Payment
~~~~~~~~~~~~~~~~
.. code:: none
instructed_amount = contractTerms.amount
coins = select-coin-for-operation(debit, mode, raw_amount)
raw_amount = instructed_amount - merchant_deposit_fee
effective_amount = instructed_amount + coins.deposit_fee + coins.refresh_fee + (wire.transfer_fee - merchant_wire_fee)
.. note::
The current coin-selection algorithm the order_price is neither raw_amount nor effective_amount.
We can calculate the raw_amount of the payment as (contractTerms.amount - max_merchant_fee) and then this
operation becomes equivalent than a deposit (in terms of fee calculation).
Peer Push Credit
~~~~~~~~~~~~~~~~
``instructed_amount`` = p2pContract.amount
``coins`` = select-coin-for-operation(credit, mode, raw_amount)
``raw_amount`` = instructed_amount
``effective_amount`` = instructed_amount - coins.withdrawal_fee
.. note::
In the case that the withdrawal_fee of the coin selection for the push-credit amount
is higher than the wire_fee of the exchange, can the wallet ask the exchange to make
a wire transfer of the purse instead of proceeding?
Peer Pull Debit
~~~~~~~~~~~~~~~
``instructed_amount`` = p2pContract.amount
``coins`` = select-coin-for-operation(debit, mode, raw_amount)
``raw_amount`` = instructed_amount
``effective_amount`` = instructed_amount + coins.deposit_fee + coins.refresh_fee + wire.transfer_fee
Refund
~~~~~~
``instructed_amount`` = refund.amount
``raw_amount`` = instructed_amount
``effective_amount`` = instructed_amount - refund_fee - refresh_fee
.. note::
There may be the case that the merchant should refund all the value of the purchase
and that may include paying for the refund_fee.
Is there a way that the merchant can initiate a refund of purchase + refund_fee so
the wallet will get the same effective_amount?
Illustrative Example
--------------------
.. warning::
This section is possibly incomplete / out of date.
To explain the differences between raw, effective and instructed amounts, consider the following scenario: Alice wants to send money
to Bob via a P2P push payment.
Example 1:
* Alice starts a withdrawal of ``KUDOS:10`` from her bank's web interface into her Taler
wallet. The instructed amount is ``KUDOS:10`` and (by default for bank-integrated withdrawals),
the mode is ``raw-mode``. After fees, ``KUDOS:9.8`` arrive in her Taler wallet.
Example 3:
* Alice wants to pay for a ``KUDOS:10`` monthly magazine subscription. Her Taler wallet is empty though.
* She starts withdrawal through her Android wallet app, where she selects ``KUDOS:10`` as the instructed
amount with ``mode=effective-mode``. This translates to ``amountEffective=KUDOS:10`` and ``amountRaw=KUDOS:10.10``.
* Alice is redirected to her banking app where she transfers ``KUDOS:10.10`` to the exchange.
* Her Taler wallet balance will be ``KUDOS:10.10`` after the withdrawal completes.
Note that on the amount she chooses and the fees / denom structure of the exchange, the ``amountEffective`` might be *higher*
than the instructed amount.
FIXME(dold): That flow does not work if withdrawal starts in the bank. Maybe there needs to be a mechanism
where the wallet tells the bank the adjusted amount that needs to be transferred? That would be a new
feature in the bank integration API.
Example 4:
* Alice has ``KUDOS:10`` in her wallet.
* Alice wants to initiate a peer-push payment with ``amountInstructed=KUDOS:8``
and ``mode=effective-mode``. That means that after the payment, she expects
exactly ``KUDOS:2`` to remain in her wallet.
* Due to the fee configuration, her wallet computes ``amountRaw=KUDOS:7.5`` and ``amountEffective=KUDOS:7.8``.
The effective amount in this case does **not** equal the instructed amount, despite the ``mode=effective-mode``.
That's because there no amount that can be spend so that the spend amount with resulting refresh
fees equal ``KUDOS:8``.
* Alice confirms the peer-push payment initiation, and exactly ``KUDOS:7.5`` are credited
to the purse that her wallet creates.
* Bob merges the purse into his reserve. Bob's wallet automatically withdraws
from the reserve, and his wallet balance increases by ``KUDOS:7.1``, since
withdrawal fees are deducted.
Discussion / Q&A
================
(This should be filled in with results from discussions on mailing lists / personal communication.)