041-wallet-balance-amount-definitions.rst (13529B)
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: 2026-09-05 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 Confirmed and final transaction amounts 51 --------------------------------------- 52 53 The wallet API's ``amountEffective`` preserves the amount shown when the user 54 confirmed a transaction. ``amountRaw`` retains its existing meaning. 55 ``amountEffectiveFinal`` reports the actual wallet balance effect after the 56 transaction and its change/recovery operations have settled. It is a 57 nonnegative amount; the transaction type determines debit or credit. 58 59 The final amount is absent while settlement is pending or suspended, and when 60 historical evidence cannot establish an exact amount. A failed recovery counts 61 only completed outputs. Aborting before funds are consumed has a zero final 62 cost; fees and unrecovered funds otherwise remain a debit. For incoming 63 transactions, only coins actually issued count as the final credit. 64 65 Ordinary merchant refunds remain separate credits and do not reduce a 66 successful payment's final cost. Abort refunds are included in the original 67 unsuccessful payment's final cost; their informational refund records carry 68 ``isAbortRecovery`` and must not be counted a second time. Associated refreshes 69 have zero independent effect; standalone refreshes report their own loss. 70 Settled amounts survive deletion of supporting records. Explicitly reopening 71 an operation invalidates its final amount until it settles again. 72 73 74 Instructed Amount Modes 75 ----------------------- 76 77 * ``raw-mode``: The instructed amount represents the raw amount. This is the default. 78 * ``effective-mode``: The instructed amount represents the effective amount, i.e. 79 the direct change to the balance. 80 * ``counterparty-effective-mode``: The instructed amount represents the effective 81 amount seen from the counterparty. In other words, it is the direct 82 difference to the counterparty's balance. 83 84 Balances 85 -------- 86 87 The following types of balances are defined: 88 89 - ``available``: Balance that the wallet believes will certainly be available 90 for spending, modulo any failures of the exchange or double spending issues. 91 This includes available coins *not* allocated to any 92 spending/refresh/... operation. Pending withdrawals are *not* counted 93 towards this balance, because they are not certain to succeed. 94 Pending refreshes *are* counted towards this balance. 95 This balance type is nice to show to the user, because it does not 96 temporarily decrease after payment when we are waiting for refreshes 97 98 - ``material``: Balance that the wallet believes it could spend *right now*, 99 without waiting for any operations to complete. 100 This balance type is important when showing "insufficient balance" error messages. 101 102 - ``age-acceptable``: Subset of the material balance that can be spent 103 with age restrictions applied. 104 105 - ``counterparty-acceptable``: Subset of the material balance that can be spent with a particular 106 merchant or peer-to-peer transfer. 107 108 - ``counterparty-depositable``: Subset of the receiver-acceptable balance that the counterpary 109 can accept via their supported wire methods. 110 111 - ``exchange-depositable``: Subset of the receiver-acceptable balance that the counterpary 112 can accept via their supported wire methods. 113 114 While not quite a balance, we also define the following balance-related term: 115 116 - ``max-merchant-effective-deposit-amount``: Estimated maximum amount that the 117 wallet could pay for, under the assumption that the merchant pays absolutely 118 no fees. 119 120 121 122 123 Raw Amount Definitions 124 ---------------------- 125 Raw amount is… 126 127 Manual Withdrawal 128 … the money that is wired from the user's bank account to the 129 exchange's bank account for the withdrawal. 130 131 Deposit 132 … the amount leaving the exchange account without the wire fees. 133 134 Peer Pull Credit 135 … the amount that is withdrawn from the purse (via merge reserve) that 136 the counterparty fills. 137 138 Peer Push Debit 139 … what the counterparty expects in the purse. 140 141 Peer Push Credit 142 … the purse_value in the exchange to be withdrawn. 143 144 Merchant Payment 145 … the amount the merchant should get if is not doing aggregated transaction. 146 Wire fees are ignored. 147 148 Peer Pull Debit 149 … the net value of the invoice without fees. 150 151 Refund 152 … the amount that the merchant refunded. 153 154 155 156 Details per Transaction Type 157 ---------------------------- 158 159 .. warning:: 160 161 This section is possibly incomplete / out of date. 162 163 Manual Withdrawal 164 ~~~~~~~~~~~~~~~~~ 165 166 .. code:: none 167 168 if instructed_amount mode = raw 169 raw_amount = instructed_amount 170 171 effective_amount = instructed_amount - coins.withdrawal_fee 172 173 if instructed_amount mode = effective 174 raw_amount = instructed_amount + coins.withdrawal_fee 175 176 effective_amount = instructed_amount 177 178 Deposit 179 ~~~~~~~ 180 181 .. code:: none 182 183 if instructed_amount mode = raw 184 raw_amount = instructed_amount 185 186 effective_amount = instructed_amount + coins.deposit_fee + coins.refresh_fee + wire.transfer_fee 187 188 if instructed_amount mode = effective 189 raw_amount = instructed_amount - coins.deposit_fee - coins.refresh_fee - wire.transfer_fee 190 191 effective_amount = instructed_amount 192 193 Peer Pull Credit 194 ~~~~~~~~~~~~~~~~ 195 196 .. code:: none 197 198 if instructed_amount mode = raw 199 raw_amount = instructed_amount 200 201 effective_amount = instructed_amount - coins.withdrawal_fee - purse_fee 202 203 if instructed_amount mode = effective 204 raw_amount = instructed_amount + coins.withdrawal_fee + purse_fee 205 206 effective_amount = instructed_amount 207 208 if instructed_amount mode = counterparty 209 raw_amount = instructed_amount - coins.counterparty_deposit_fee 210 211 effective_amount = instructed_amount - coins.counterparty_deposit_fee - coins.withdrawal_fee - purse_fee 212 213 counterparty_raw_amount = raw_amount 214 215 counterparty_effective_amount = raw_amount + coins.counterparty_deposit_fee 216 217 .. note:: 218 219 counterparty_effective_amount is an estimation since refresh fee is not included. 220 Refresh fee can't be calculated because depends on the coins available in the wallet 221 of the counterparty 222 223 .. note:: 224 coins.counterparty_deposit_fee is the minimum deposit_fee that can be calculated for the 225 given exchange. Counter-party may pay more if it have different preferences doing the coin 226 selection. 227 228 229 Peer Push Debit 230 ~~~~~~~~~~~~~~~ 231 232 .. code:: none 233 234 coins = select-coin-for-operation(debit, mode, instructed_amount) 235 236 if instructed_amount mode = raw 237 raw_amount = instructed_amount 238 239 effective_amount = instructed_amount + coins.deposit_fee + purse_fee 240 241 if instructed_amount mode = effective 242 raw_amount = instructed_amount - coins.deposit_fee - purse_fee 243 244 effective_amount = instructed_amount 245 246 if instructed_amount mode = counterparty 247 raw_amount = instructed_amount + coins.counterparty_withdraw_fee 248 249 effective_amount = instructed_amount - coins.counterparty_withdraw_fee - coins.withdrawal_fee - purse_fee 250 251 counterparty_raw_amount = raw_amount 252 253 counterparty_effective_amount = raw_amount - coins.counterparty_withdraw_fee 254 255 .. note:: 256 ``coins.counterparty_withdraw_fee`` is the minimum withdraw_fee that can be calculated for the 257 given exchange. Counter-party may pay more if it have different preferences doing the coin 258 selection. 259 260 261 .. note :: 262 how much wire_fee the merchant is willing to pay 263 264 merchant_wire_fee = min(wire.transfer_fee / contractTerms.amortization_factor, contractTerms.max_wire_fee) 265 266 merchant_deposit_fee = min(contractTerms.max_fee, contract_wire_fee) 267 268 269 Merchant Payment 270 ~~~~~~~~~~~~~~~~ 271 272 .. code:: none 273 274 275 instructed_amount = contractTerms.amount 276 277 coins = select-coin-for-operation(debit, mode, raw_amount) 278 279 raw_amount = instructed_amount - merchant_deposit_fee 280 281 effective_amount = instructed_amount + coins.deposit_fee + coins.refresh_fee + (wire.transfer_fee - merchant_wire_fee) 282 283 .. note:: 284 The current coin-selection algorithm the order_price is neither raw_amount nor effective_amount. 285 We can calculate the raw_amount of the payment as (contractTerms.amount - max_merchant_fee) and then this 286 operation becomes equivalent than a deposit (in terms of fee calculation). 287 288 Peer Push Credit 289 ~~~~~~~~~~~~~~~~ 290 291 292 ``instructed_amount`` = p2pContract.amount 293 294 ``coins`` = select-coin-for-operation(credit, mode, raw_amount) 295 296 ``raw_amount`` = instructed_amount 297 298 ``effective_amount`` = instructed_amount - coins.withdrawal_fee 299 300 .. note:: 301 In the case that the withdrawal_fee of the coin selection for the push-credit amount 302 is higher than the wire_fee of the exchange, can the wallet ask the exchange to make 303 a wire transfer of the purse instead of proceeding? 304 305 Peer Pull Debit 306 ~~~~~~~~~~~~~~~ 307 308 309 ``instructed_amount`` = p2pContract.amount 310 311 ``coins`` = select-coin-for-operation(debit, mode, raw_amount) 312 313 ``raw_amount`` = instructed_amount 314 315 ``effective_amount`` = instructed_amount + coins.deposit_fee + coins.refresh_fee + wire.transfer_fee 316 317 Refund 318 ~~~~~~ 319 320 321 ``instructed_amount`` = refund.amount 322 323 ``raw_amount`` = instructed_amount 324 325 ``effective_amount`` = instructed_amount - refund_fee - refresh_fee 326 327 .. note:: 328 There may be the case that the merchant should refund all the value of the purchase 329 and that may include paying for the refund_fee. 330 331 Is there a way that the merchant can initiate a refund of purchase + refund_fee so 332 the wallet will get the same effective_amount? 333 334 335 336 Illustrative Example 337 -------------------- 338 339 .. warning:: 340 341 This section is possibly incomplete / out of date. 342 343 To explain the differences between raw, effective and instructed amounts, consider the following scenario: Alice wants to send money 344 to Bob via a P2P push payment. 345 346 Example 1: 347 348 * Alice starts a withdrawal of ``KUDOS:10`` from her bank's web interface into her Taler 349 wallet. The instructed amount is ``KUDOS:10`` and (by default for bank-integrated withdrawals), 350 the mode is ``raw-mode``. After fees, ``KUDOS:9.8`` arrive in her Taler wallet. 351 352 Example 3: 353 354 * Alice wants to pay for a ``KUDOS:10`` monthly magazine subscription. Her Taler wallet is empty though. 355 * She starts withdrawal through her Android wallet app, where she selects ``KUDOS:10`` as the instructed 356 amount with ``mode=effective-mode``. This translates to ``amountEffective=KUDOS:10`` and ``amountRaw=KUDOS:10.10``. 357 * Alice is redirected to her banking app where she transfers ``KUDOS:10.10`` to the exchange. 358 * Her Taler wallet balance will be ``KUDOS:10.10`` after the withdrawal completes. 359 360 Note that on the amount she chooses and the fees / denom structure of the exchange, the ``amountEffective`` might be *higher* 361 than the instructed amount. 362 363 FIXME(dold): That flow does not work if withdrawal starts in the bank. Maybe there needs to be a mechanism 364 where the wallet tells the bank the adjusted amount that needs to be transferred? That would be a new 365 feature in the bank integration API. 366 367 Example 4: 368 369 * Alice has ``KUDOS:10`` in her wallet. 370 * Alice wants to initiate a peer-push payment with ``amountInstructed=KUDOS:8`` 371 and ``mode=effective-mode``. That means that after the payment, she expects 372 exactly ``KUDOS:2`` to remain in her wallet. 373 * Due to the fee configuration, her wallet computes ``amountRaw=KUDOS:7.5`` and ``amountEffective=KUDOS:7.8``. 374 The effective amount in this case does **not** equal the instructed amount, despite the ``mode=effective-mode``. 375 That's because there no amount that can be spend so that the spend amount with resulting refresh 376 fees equal ``KUDOS:8``. 377 * Alice confirms the peer-push payment initiation, and exactly ``KUDOS:7.5`` are credited 378 to the purse that her wallet creates. 379 * Bob merges the purse into his reserve. Bob's wallet automatically withdraws 380 from the reserve, and his wallet balance increases by ``KUDOS:7.1``, since 381 withdrawal fees are deducted. 382 383 384 Discussion / Q&A 385 ================ 386 387 (This should be filled in with results from discussions on mailing lists / personal communication.)