taler-docs

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

041-wallet-balance-amount-definitions.rst (12191B)


      1 DD 41: Wallet Balance and Amount Definitions
      2 ############################################
      3 
      4 :Design status: Draft
      5 :Implementation status: Partial
      6 :DD shepherd: TBD
      7 :Historical contributors: Sebastian, Christian Grothoff, Florian Dold, Marc Stibane
      8 :First published: 2023-03-30
      9 :Last substantive change: 2024-09-12
     10 :Normative references: ``wallet/wallet-core.md``
     11 
     12 Summary
     13 =======
     14 
     15 This design document discusses terminology and concepts used in the wallet
     16 for balances and amounts.
     17 
     18 Motivation
     19 ==========
     20 
     21 There are many different types of balances and amounts, and they need
     22 to have a clear definition.
     23 
     24 Furthermore, the user in some situations needs to know/decide whether
     25 an amount that the user chooses includes fees or not.
     26 
     27 
     28 Proposed Solution
     29 =================
     30 
     31 Amounts
     32 -------
     33 
     34 * ``effective``: An effective amount always represents the direct effect on the
     35   wallet's balance of the same currency.
     36 * ``raw``: The raw amount always refers to the amount with fees applied.
     37   The exact interpretation of that depends on the transaction type.
     38 * ``instructed``: An instructed amount always refers to the amount that
     39   a user has explicitly specified as an input.  It is not directly a property
     40   of transactions, but might be added as metadata to transactions for
     41   informational purposes.  How the instructed amount is interpreted
     42   differs based on the "instructed amount mode" that is specified
     43   together with the amount.
     44 * ``counterparty-effective``: An amount that **estimates** the effect
     45   of the transaction of the balance (either wallet or bank account) of the other
     46   party. This is usually a conservative estimate, i.e. when sending money,
     47   this is the lower bound for the funds that the other party will obtain
     48   *after* fees.
     49 
     50 Instructed Amount Modes
     51 -----------------------
     52 
     53 * ``raw-mode``: The instructed amount represents the raw amount. This is the default.
     54 * ``effective-mode``: The instructed amount represents the effective amount, i.e.
     55   the direct change to the balance.
     56 * ``counterparty-effective-mode``: The instructed amount represents the effective
     57   amount seen from the counterparty. In other words, it is the direct
     58   difference to the counterparty's balance.
     59 
     60 Balances
     61 --------
     62 
     63 The following types of balances are defined:
     64 
     65 - ``available``: Balance that the wallet believes will certainly be available
     66   for spending, modulo any failures of the exchange or double spending issues.
     67   This includes available coins *not* allocated to any
     68   spending/refresh/... operation. Pending withdrawals are *not* counted
     69   towards this balance, because they are not certain to succeed.
     70   Pending refreshes *are* counted towards this balance.
     71   This balance type is nice to show to the user, because it does not
     72   temporarily decrease after payment when we are waiting for refreshes
     73 
     74 - ``material``: Balance that the wallet believes it could spend *right now*,
     75   without waiting for any operations to complete.
     76   This balance type is important when showing "insufficient balance" error messages.
     77 
     78 - ``age-acceptable``: Subset of the material balance that can be spent
     79   with age restrictions applied.
     80 
     81 - ``counterparty-acceptable``: Subset of the material balance that can be spent with a particular
     82   merchant or peer-to-peer transfer.
     83 
     84 - ``counterparty-depositable``: Subset of the receiver-acceptable balance that the counterpary
     85   can accept via their supported wire methods.
     86 
     87 - ``exchange-depositable``: Subset of the receiver-acceptable balance that the counterpary
     88   can accept via their supported wire methods.
     89 
     90 While not quite a balance, we also define the following balance-related term:
     91 
     92 - ``max-merchant-effective-deposit-amount``: Estimated maximum amount that the
     93   wallet could pay for, under the assumption that the merchant pays absolutely
     94   no fees.
     95 
     96 
     97 
     98 
     99 Raw Amount Definitions
    100 ----------------------
    101 Raw amount is…
    102 
    103 Manual Withdrawal
    104   … the money that is wired from the user's bank account to the
    105   exchange's bank account for the withdrawal.
    106 
    107 Deposit
    108   … the amount leaving the exchange account without the wire fees.
    109  
    110 Peer Pull Credit
    111   … the amount that is withdrawn from the purse (via merge reserve) that
    112   the counterparty fills.
    113 
    114 Peer Push Debit
    115   … what the counterparty expects in the purse.
    116 
    117 Peer Push Credit
    118   … the purse_value in the exchange to be withdrawn.
    119 
    120 Merchant Payment
    121   … the amount the merchant should get if is not doing aggregated transaction.
    122   Wire fees are ignored.
    123 
    124 Peer Pull Debit
    125   … the net value of the invoice without fees.
    126 
    127 Refund
    128   … the amount that the merchant refunded.
    129   
    130 
    131 
    132 Details per Transaction Type
    133 ----------------------------
    134 
    135 .. warning::
    136 
    137    This section is possibly incomplete / out of date.
    138 
    139 Manual Withdrawal
    140 ~~~~~~~~~~~~~~~~~
    141 
    142 .. code:: none
    143 
    144   if instructed_amount mode = raw
    145     raw_amount = instructed_amount
    146 
    147     effective_amount = instructed_amount - coins.withdrawal_fee
    148 
    149   if instructed_amount mode = effective
    150     raw_amount = instructed_amount + coins.withdrawal_fee
    151 
    152     effective_amount = instructed_amount
    153 
    154 Deposit
    155 ~~~~~~~
    156 
    157 .. code:: none
    158 
    159   if instructed_amount mode = raw
    160     raw_amount = instructed_amount
    161 
    162     effective_amount = instructed_amount + coins.deposit_fee + coins.refresh_fee + wire.transfer_fee
    163 
    164   if instructed_amount mode = effective
    165     raw_amount = instructed_amount - coins.deposit_fee - coins.refresh_fee - wire.transfer_fee
    166 
    167     effective_amount = instructed_amount
    168 
    169 Peer Pull Credit
    170 ~~~~~~~~~~~~~~~~
    171 
    172 .. code:: none
    173 
    174   if instructed_amount mode = raw
    175     raw_amount = instructed_amount
    176 
    177     effective_amount = instructed_amount - coins.withdrawal_fee - purse_fee
    178 
    179   if instructed_amount mode = effective
    180     raw_amount = instructed_amount + coins.withdrawal_fee + purse_fee
    181 
    182     effective_amount = instructed_amount
    183 
    184   if instructed_amount mode = counterparty
    185     raw_amount = instructed_amount - coins.counterparty_deposit_fee
    186 
    187     effective_amount = instructed_amount - coins.counterparty_deposit_fee - coins.withdrawal_fee - purse_fee
    188 
    189   counterparty_raw_amount = raw_amount
    190 
    191   counterparty_effective_amount = raw_amount + coins.counterparty_deposit_fee
    192 
    193   .. note::
    194 
    195     counterparty_effective_amount is an estimation since refresh fee is not included.
    196     Refresh fee can't be calculated because depends on the coins available in the wallet
    197     of the counterparty
    198 
    199   .. note::
    200     coins.counterparty_deposit_fee is the minimum deposit_fee that can be calculated for the
    201     given exchange. Counter-party may pay more if it have different preferences doing the coin
    202     selection.
    203 
    204 
    205 Peer Push Debit
    206 ~~~~~~~~~~~~~~~
    207 
    208 .. code:: none
    209 
    210   coins = select-coin-for-operation(debit, mode, instructed_amount)
    211 
    212   if instructed_amount mode = raw
    213     raw_amount = instructed_amount
    214 
    215     effective_amount = instructed_amount + coins.deposit_fee + purse_fee
    216 
    217   if instructed_amount mode = effective
    218     raw_amount = instructed_amount - coins.deposit_fee - purse_fee
    219 
    220     effective_amount = instructed_amount
    221 
    222   if instructed_amount mode = counterparty
    223     raw_amount = instructed_amount + coins.counterparty_withdraw_fee
    224 
    225     effective_amount = instructed_amount - coins.counterparty_withdraw_fee - coins.withdrawal_fee - purse_fee
    226 
    227   counterparty_raw_amount = raw_amount
    228 
    229   counterparty_effective_amount = raw_amount - coins.counterparty_withdraw_fee
    230 
    231   .. note::
    232     ``coins.counterparty_withdraw_fee`` is the minimum withdraw_fee that can be calculated for the
    233     given exchange. Counter-party may pay more if it have different preferences doing the coin
    234     selection.
    235 
    236 
    237 .. note ::
    238   how much wire_fee the merchant is willing to pay
    239 
    240   merchant_wire_fee = min(wire.transfer_fee / contractTerms.amortization_factor, contractTerms.max_wire_fee)
    241 
    242   merchant_deposit_fee = min(contractTerms.max_fee, contract_wire_fee)
    243 
    244 
    245 Merchant Payment
    246 ~~~~~~~~~~~~~~~~
    247 
    248 .. code:: none
    249 
    250 
    251   instructed_amount = contractTerms.amount
    252 
    253   coins = select-coin-for-operation(debit, mode, raw_amount)
    254 
    255   raw_amount = instructed_amount - merchant_deposit_fee
    256 
    257   effective_amount = instructed_amount + coins.deposit_fee + coins.refresh_fee + (wire.transfer_fee - merchant_wire_fee)
    258 
    259   .. note::
    260     The current coin-selection algorithm the order_price is neither raw_amount nor effective_amount.
    261     We can calculate the raw_amount of the payment as (contractTerms.amount - max_merchant_fee) and then this
    262     operation becomes equivalent than a deposit (in terms of fee calculation).
    263 
    264 Peer Push Credit
    265 ~~~~~~~~~~~~~~~~
    266 
    267 
    268   ``instructed_amount`` = p2pContract.amount
    269 
    270   ``coins`` = select-coin-for-operation(credit, mode, raw_amount)
    271 
    272   ``raw_amount`` = instructed_amount
    273 
    274   ``effective_amount`` = instructed_amount - coins.withdrawal_fee
    275 
    276   .. note::
    277     In the case that the withdrawal_fee of the coin selection for the push-credit amount
    278     is higher than the wire_fee of the exchange, can the wallet ask the exchange to make
    279     a wire transfer of the purse instead of proceeding?
    280 
    281 Peer Pull Debit
    282 ~~~~~~~~~~~~~~~
    283 
    284 
    285   ``instructed_amount`` = p2pContract.amount
    286 
    287   ``coins`` = select-coin-for-operation(debit, mode, raw_amount)
    288 
    289   ``raw_amount`` = instructed_amount
    290 
    291   ``effective_amount`` = instructed_amount + coins.deposit_fee + coins.refresh_fee + wire.transfer_fee
    292 
    293 Refund
    294 ~~~~~~
    295 
    296 
    297   ``instructed_amount`` = refund.amount
    298 
    299   ``raw_amount`` = instructed_amount
    300 
    301   ``effective_amount`` = instructed_amount - refund_fee - refresh_fee
    302 
    303   .. note::
    304     There may be the case that the merchant should refund all the value of the purchase
    305     and that may include paying for the refund_fee.
    306 
    307     Is there a way that the merchant can initiate a refund of purchase + refund_fee so
    308     the wallet will get the same effective_amount?
    309 
    310 
    311 
    312 Illustrative Example
    313 --------------------
    314 
    315 .. warning::
    316 
    317    This section is possibly incomplete / out of date.
    318 
    319 To explain the differences between raw, effective and instructed amounts, consider the following scenario: Alice wants to send money
    320 to Bob via a P2P push payment.
    321 
    322 Example 1:
    323 
    324 * Alice starts a withdrawal of ``KUDOS:10`` from her bank's web interface into her Taler
    325   wallet. The instructed amount is ``KUDOS:10`` and (by default for bank-integrated withdrawals),
    326   the mode is ``raw-mode``.  After fees, ``KUDOS:9.8`` arrive in her Taler wallet.
    327 
    328 Example 3:
    329 
    330 * Alice wants to pay for a ``KUDOS:10`` monthly magazine subscription. Her Taler wallet is empty though.
    331 * She starts withdrawal through her Android wallet app, where she selects ``KUDOS:10`` as the instructed
    332   amount with ``mode=effective-mode``. This translates to ``amountEffective=KUDOS:10`` and ``amountRaw=KUDOS:10.10``.
    333 * Alice is redirected to her banking app where she transfers ``KUDOS:10.10`` to the exchange.
    334 * Her Taler wallet balance will be ``KUDOS:10.10`` after the withdrawal completes.
    335 
    336 Note that on the amount she chooses and the fees / denom structure of the exchange, the ``amountEffective`` might be *higher*
    337 than the instructed amount.
    338 
    339 FIXME(dold): That flow does not work if withdrawal starts in the bank. Maybe there needs to be a mechanism
    340 where the wallet tells the bank the adjusted amount that needs to be transferred? That would be a new
    341 feature in the bank integration API.
    342 
    343 Example 4:
    344 
    345 * Alice has ``KUDOS:10`` in her wallet.
    346 * Alice wants to initiate a peer-push payment with ``amountInstructed=KUDOS:8``
    347   and ``mode=effective-mode``. That means that after the payment, she expects
    348   exactly ``KUDOS:2`` to remain in her wallet.
    349 * Due to the fee configuration, her wallet computes ``amountRaw=KUDOS:7.5`` and ``amountEffective=KUDOS:7.8``.
    350   The effective amount in this case does **not** equal the instructed amount, despite the ``mode=effective-mode``.
    351   That's because there no amount that can be spend so that the spend amount with resulting refresh
    352   fees equal ``KUDOS:8``.
    353 * Alice confirms the peer-push payment initiation, and exactly ``KUDOS:7.5`` are credited
    354   to the purse that her wallet creates.
    355 * Bob merges the purse into his reserve. Bob's wallet automatically withdraws
    356   from the reserve, and his wallet balance increases by ``KUDOS:7.1``, since
    357   withdrawal fees are deducted.
    358 
    359 
    360 Discussion / Q&A
    361 ================
    362 
    363 (This should be filled in with results from discussions on mailing lists / personal communication.)