013-peer-to-peer-payments.rst (53372B)
1 .. _dd-13: 2 3 DD 13: Wallet-to-Wallet Payments 4 ################################ 5 6 Summary 7 ======= 8 9 This design document proposes an extension of the Taler protocol that allows 10 payments from wallet-to-wallet without a merchant. 11 12 13 Motivation 14 ========== 15 16 To be usable as an electronic payment system with cash-like properties, 17 customers should be able to transfer money between themselves without 18 needing to setup anything beyond their wallet(s). 19 20 This will be used for payments via e-mail and other messaging apps, as well as 21 possibly for transfers via NFC/QR code between mobile phones. 22 23 Invoice Flow User Experience 24 ---------------------------- 25 26 .. graphviz:: 27 28 digraph invoice { 29 ranksep="0.5" 30 { rank = same; "inbox"; "begin"; } 31 { rank = same; "sending"; "receiving2"; } 32 { rank = same; "receiving"; "paying"; } 33 { rank = same; "mid"; "midbox"; } 34 { rank = same; "body"; "amount"; } 35 begin [label="Payer Inbox",shape=box]; 36 body [label="compose\nE-mail message"]; 37 amount [label="specify\ninvoice details"]; 38 receiving [label="receiving...",shape=diamond]; 39 sending [label="transmitting...",shape=diamond]; 40 mid [label="Payee Inbox",shape=box]; 41 notified [label="Notification:\npayment received"]; 42 end [label="Payee Inbox",shape=box]; 43 begin -> body [label="(1) new"]; 44 body -> amount [label="(2) attach invoice"]; 45 amount -> body [label="(3) Ok"]; 46 body -> sending [label="(4) send"]; 47 sending -> mid [style=dashed]; 48 mid -> receiving [style=dashed]; 49 receiving -> notified [style=dashed]; 50 notified -> end [label="(9) Acknowledge"]; 51 inbox [label="Payer Inbox",shape=box]; 52 receiving2 [label="receiving...",shape=diamond]; 53 midbox [label="Payer Inbox",shape=box]; 54 open [label="message with\nattached invoice"]; 55 confirm [label="review invoice"]; 56 paying [label="paying...", shape=diamond]; 57 paid [label="message with\npaid invoice"]; 58 finbox [label="Payer Inbox",shape=box]; 59 inbox -> receiving2 [style=dashed]; 60 receiving2 -> sending [label="Internet\n(pEp)",style=dashed,dir=back]; 61 receiving2 -> midbox [style=dashed]; 62 midbox -> open [label="(5) select message"]; 63 open -> confirm [label="(6) view invoice"]; 64 confirm -> paying [label="(7) pay"]; 65 paying -> paid [style=dashed]; 66 paid -> finbox [label="(8) back"]; 67 paying -> receiving [style=dashed, label="Internet\n(Taler)"]; 68 } 69 70 Donation Flow User Experience 71 ----------------------------- 72 73 .. graphviz:: 74 75 digraph donation { 76 ranksep="0.5" 77 { rank = same; "inbox"; "begin"; } 78 { rank = same; "sending"; "receiving2"; } 79 { rank = same; "body"; "amount"; } 80 { rank = same; "mid"; "midbox"; } 81 { rank = same; "accepting"; "timeout"; "receiving"; } 82 begin [label="Donor Inbox",shape=box]; 83 body [label="compose\nE-mail message"]; 84 amount [label="specify\npayment details"]; 85 receiving [label="receiving...",shape=diamond]; 86 timeout [label="timeout...",shape=diamond]; 87 sending [label="transmitting...",shape=diamond]; 88 mid [label="Donor Inbox",shape=box]; 89 notified [label="Notification:\npayment confirmed"]; 90 notified2 [label="Notification:\npayment refunded"]; 91 end [label="Donor Inbox",shape=box]; 92 begin -> body [label="(1) new"]; 93 body -> amount [label="(2) attach payment"]; 94 amount -> body [label="(3) Ok"]; 95 body -> sending [label="(4) send"]; 96 sending -> mid [style=dashed]; 97 mid -> receiving [style=dashed]; 98 receiving -> notified [style=dashed]; 99 mid -> timeout [style=dashed]; 100 timeout -> notified2 [style=dashed]; 101 notified -> end [label="(9a) Acknowledge"]; 102 notified2 -> end [label="(9b) Acknowledge"]; 103 inbox [label="Recipient Inbox",shape=box]; 104 receiving2 [label="receiving...",shape=diamond]; 105 midbox [label="Recipient Inbox",shape=box]; 106 open [label="message with\nattached payment"]; 107 confirm [label="accept payment?"]; 108 accepting [label="accepting...", shape=diamond]; 109 paid [label="message with\naccepted payment"]; 110 finbox [label="Recipient Inbox",shape=box]; 111 inbox -> receiving2 [style=dashed]; 112 receiving2 -> sending [label="Internet\n(pEp)",style=dashed,dir=back]; 113 receiving2 -> midbox [style=dashed]; 114 midbox -> open [label="(5) select message"]; 115 open -> confirm [label="(6) review payment details"]; 116 confirm -> accepting [label="(7) yes"]; 117 accepting -> paid [style=dashed]; 118 paid -> finbox [label="(8) back"]; 119 accepting -> receiving [style=dashed, label="Internet\n(Taler)"]; 120 } 121 122 Requirements 123 ============ 124 125 * The protocol must permit transacting arbitrary amounts in any currency, 126 as long as both parties trust the exchange involved. 127 * The control data for wallet-to-wallet payments should be small 128 enough to fit into a QR code or short message (so ideally less than 64 bytes). 129 * No other direct communication channel between payer and payee should 130 be required. 131 * The wallet-to-wallet payment must be possible without trusting the other 132 party beyond the point where the money has been received by the payee. Thus, 133 sharing of coin private keys is not sufficient, we need transactional semantics 134 resulting in exclusive control over the funds by the recipient. 135 * The wallet-to-wallet payment protocol must not allow users to circumvent income 136 transparency. That is, each wallet-to-wallet transaction must be visible 137 on a KYCed transaction ledger (such as a bank account). 138 * The money received via a wallet-to-wallet payment must be usable for 139 further Taler payments with minimal delay (after KYC). 140 * It must still be possible to associate payments with a contract that is 141 effectively (alas not necessarily directly) signed by both parties: 142 the payer with the coin private keys, and the payee with their KYC'ed 143 account private key. 144 * The contract must be able to satisfy laws like the German TSE law, 145 which implies that the payer must be able to obtain a payment receipt. 146 * Two payment scenarios must be possible: (1) one where the payee first 147 transmits a proposal to the payer (request-to-pay) that the payer 148 accepts by making the payment, and (2) completely uni-directional 149 payments where the payer includes a proposal with the payment and the 150 payee accepts the proposal by taking the offered payment. 151 * If the payment fails (i.e. the receiver refuses to accept the money 152 or the message is lost), the payer must automatically recover the 153 funds (minus applicable fees) without the need for further communication. 154 * If funds flow back to the payer due to an aborted payment, it must be 155 provable for the payer that these funds were not income but merely an aborted 156 transaction. Furthermore, in this case, no KYC should be required from the 157 payer. 158 * If a payment would partially succeed, i.e. because the payer inadvertedly 159 used some double-spent coins and some valid coins, this must fail before the 160 uni-directional communication and be correctable payer-side. In other words, 161 the actual payment must be atomic. 162 * The usual properties of Taler (everything auditable, unlinkability, 163 high-performance in terms of CPU, bandwidth, latency, storage 164 requirements, and the ability to levy fees on every operation that 165 is costly for the exchange) need to be preserved. 166 * The system must handle the case where a customer no longer intends to 167 use the KYCed account (due to disuse, death, or key compromise). 168 169 170 171 New Terminology 172 =============== 173 174 * An ``account`` is a non-expiring reserve for which entity knowing the 175 reserve private key has completed a KYC procedure sufficient to enable 176 receiving income under that address. 177 * A ``purse`` is a public-private key pair where the public key is 178 an exchange address from which any owners of an account 179 can ``merge`` the amount left at a ``purse`` into their 180 account balance assuming they know the purse private key. 181 * A ``wad`` is an exchange-to-exchange wire transfer that wires money 182 into a group of accounts at the target exchange. 183 184 185 Proposed Solution 186 ================= 187 188 Principles 189 ---------- 190 191 * Purses are ephemeral and only serve for one transaction. 192 * The purse's transaction amount is fixed when the purse is created, and 193 specified together with the maximum deposit fee acceptable to the payee. 194 Deposit fees exceeding this limit must be paid by the payer. 195 * Each purse is associated with a contract terms hash and an expiration date. 196 * The contract is optionally stored encrypted at the exchange. 197 The contract must be encrypted to the purse private key. 198 An additional ephemeral public key (for DH encryption) should be 199 part of the POSTed payload. 200 * The exchange deletes the encrypted contract at this expiration date. 201 * The exchange may limit the encrypted contract size and storage duration. 202 * Either payer or payee can create the purse and associate it with the contract. 203 * By merging the purse into the account, the payee accepts the contract. 204 * By paying the purse to the designated amount, the payer accepts the contract. 205 * Until the purse is fully paid, the payer can abort the payment. 206 * The exchange may charge a **purse fee** for managing the purse, but we 207 want most scenarios to not require it to be effectively charged. 208 * By associating a purse with an account upon creation, the purse fee can be 209 made optional for account holders as long as the number of purses created 210 per account is below a configurable threshold. 211 * By charging the purse fee only in case the payee did **not** merge the 212 purse into their account, the purse fee can be limited for payers to 213 the case where they are receiving a refund --- and here it could be 214 then entirely avoided if the refund fee is non-zero. 215 216 217 W2W Payment Metadata 218 -------------------- 219 220 The standard Taler Customer-to-Merchant payments always use a contract terms 221 JSON object to record the modalities of the payment and the resulting 222 obligations of a successful payment. 223 224 The contract terms concept does not directly carry over to W2W payments, 225 because: 226 227 * Either party may initiate the payment. 228 * The payee does not have a merchant public key, and 229 at the time of payment initiation, the payee account might not yet 230 be known. 231 * There is no nonce that the customer generates and uses to prove that they 232 uniquely "own" the contract terms. 233 * There is no negotiation of trusted auditors / exchanges possible. 234 235 As a result, some of the existing fields of the contract terms no longer apply 236 to wallet-to-wallet payments. 237 238 Contract metadata for W2W payments can be exchanged in three ways: 239 240 1. Inline, as part of the payment request / payment offer. In this case, 241 both parties are already aware of the contract's contents and 242 the exchange's contract exchange facility is simply not used. 243 2. The payee can create a **purse** and immediately associate it with 244 an **account** by sending a signed **merge** request together with 245 the (encrypted) contract. 246 247 a. The purse creation request created by the payee must include a 248 signature with the account private key of the payee signing the purse 249 public key and the hash of the contract, thereby affirming that 250 the contract was pre-approved by the account owner. 251 b. The exchange may wave the purse fee for a certain number of 252 active purses per account. Additional purses can be purchased 253 by paying the **purse fee**. 254 3. The payer can store a contract with the exchange by POSTing 255 an encrypted contract to the exchange as part of creating a **purse**. 256 257 a. The exchange charges the **purse fee** to payers for purses that 258 are refunded after not being **merged**. 259 b. When paying into a purse, the coin signature includes the purse 260 public key, the contract hash and the desired expiration date 261 (how long a merge is allowed). 262 c. Payment offers are not allowed if the amount transacted is below 263 the purse fee. 264 d. The exchange auto-refunds coins in **purses** with deposits 265 matching expired contracts. 266 267 .. note:: 268 269 While the **refund fee** amount can be reused, these types of refunds 270 are not approved by a merchant's signature. Thus, we will need 271 a new message type in the coin history to represent these events. 272 273 274 Account creation 275 ---------------- 276 277 An account is simply a reserve that has been subjected to 278 KYC. A reserve that has seen a purse merged into it must 279 be upgraded to an account before further withdraw (or close) 280 operations are allowed. The usual closure deadline for a 281 reserve is extended to the KYC deadline. 282 283 1. The payee generates a reserve key, which also yields a 284 ``payto://taler/$EXCHANGE_BASE_URL/$RESERVE_PUB`` 285 target address (for which the payee knows the corresponding 286 reserve private key). 287 2. When withdrawing from a reserve that has experienced 288 merge operations and thus must be an account, the exchange 289 first checks if the customer has satisfied the KYC requirements. 290 If not, the customer is redirected to a Web page where they 291 can perform the necessary KYC operation. 292 3. For this, the exchange wire gateway is extended with a request to 293 check the KYC status of a customer based on an ``RESERVE_PUB``. 294 Possible replies are ``in-progress`` and ``succeeded``. 295 An ``in-progress`` status should be accompanied with 296 information how the customer may complete the KYC check. 297 4. A new exchange endpoint ``/reserves/$RESERVE_PUB/kyc`` 298 allows wallets to request a KYC for a 299 ``$RESERVE_PUB``. Such a request may include the requirement to pay 300 a **KYC fee**. 301 The KYC fee may be charged to the reserve (a sufficient 302 balance can be provided by the wallet by creating a purse 303 and merging the purse with the reserve, if needed), 304 or could be waved if the reserve was established via a wire transfer 305 from a partner bank where KYC is free. For this, the Wire 306 gateway API is extended with a flag that informs the exchange 307 that the incoming wire transfer implies a free KYC check. 308 5. If the account owner fails to perform the KYC check, all funds 309 in an reserve remain inaccessible. After a configurable duration, 310 the funds may be considered forfeit and become the property of 311 the exchange where the reserve is located. 312 6. The exchange may charge an annual **account fee**, and can 313 close accounts where the account balance is insufficient to 314 cover the account fee. 315 316 317 Withdrawing from accounts 318 ------------------------- 319 320 1. When requesting an account's history (which can get quite long), 321 the exchange only returns the last 3 months of data. Requesting 322 the full history requires paying an **account history fee** 323 (which is not done via a 402, but simply charged to the account 324 when requested; full account histories for accounts with an 325 insufficient balance cannot be requested -- except of course 326 the wallet could simply top up the account balance first, see below). 327 2. If the exchange has **merged** a **purse** into an account, or 328 received an inbound wire transfer from a **wad** matching the 329 account (see below), it adds the respective amount(s) to the 330 account's balance, allowing the KYC'ed customer to withdraw the funds, 331 similar to withdrawals from a reserve. 332 3. The account history endpoint should also allow long-polling. 333 Note that long-polling should be limited to short durations, 334 as inbound transfers via ``taler-exchange-wirewatch`` cannot cause the long 335 polling to be resumed, only transfers within the same exchange can benefit 336 from long-polling acceleration. 337 338 339 Account deletion 340 ---------------- 341 342 1. A reserve owner can delete a reserve by signing a deletion message 343 with the reserve private key. 344 2. This basically resets the KYC data at the exchange, preventing 345 further use of the account. This is helpful in case a user is 346 concerned about having 347 accidentally disclosed the reserve private key to a third party. 348 3. If funds remain in the reserve, the exchange will close the 349 reserve and wire the funds to the associated bank account. 350 If no bank account is associated with the reserve, 351 an error message is generated instead. The 352 user can pass an extra override parameter to delete reserves 353 even if they still contain funds. 354 4. A related endpoint should exist for the exchange operator, possibly 355 using messages signed with a new exchange management key. 356 This could be useful in case customers die or are otherwise 357 in need for manual intervention that requires an account to 358 be deleted. In this case, 359 remaining funds in the account should be wired to a bank account 360 designated in the message with the management signature. The audit 361 report should contain a special note for all of these types of 362 account deletions. 363 364 365 366 Payment offers 367 -------------- 368 369 In this protocol variant, the payer is initiating the process. 370 371 1. The payer creates a **purse** by computing a public-private key pair. 372 2. The payer POSTs to the ``/purse/$PURSE_PUB/depost`` endpoint to 373 deposit coins into the purse and optionally upload the encrypted contract terms. 374 The deposit signatures should use ``payto://taler/$PURSE_PUB`` 375 as the target address and signing over the ``$CONTRACT_HASH`` as 376 usual in deposit operations. Note that the lack of a hostname 377 indicates that the target address is a local purse. 378 3. The payer shares the purse's private key and the base URL 379 of the exchange where the purse was created with the payee. 380 This can be done using a ``taler://purse/$BASE_URL/$PURSE_PRIV`` URL. 381 The chapter on ``Refinements`` below clarifies why this 382 step is not quite OK and was modified when implementing the design. 383 4. The payee uses the new ``/purse/$PURSE_PUB`` endpoint to retrieve 384 the encrypted contract (if available) and purse balance, which includes all 385 (coin) deposits and **merges** involving the purse. 386 5. The payee's wallet must ensure that either: 387 388 a. The purse has an attached encrypted contract terms, the contract 389 terms can be decrypted and are valid, and their hash matches the contract 390 terms hash of the purse. 391 b. The wallet received detached contract terms, and their hash matches 392 contract terms of the purse. 393 394 If neither case applies, the payee's wallet must reject the payment. 395 6. The payee can then POST to ``/purse/$PURSE_PUB/merge`` a 396 request signed by the purse's private key to **merge** the 397 funds into an account. A second signature must be provided 398 by the account private key, signing the ``$CONTRACT_HASH`` thereby 399 affirming that the payee accepted the contract. 400 The account is of the form ``payto://taler/$EXCHANGE_BASE_URL/$ACCOUNT_PUB``. 401 7. Processing continues depending on the location of the account: 402 403 a. If the ``$EXCHANGE_BASE_URL`` matches the local exchange, then 404 the exchange processes the **merge** request akin to the logic 405 for payments into known accounts, as detailed above. 406 b. If the ``$EXCHANGE_BASE_URL`` does not match the local exchange, 407 a **wad fee** is charged, and the remaining amount are placed into a **wad** 408 to inform the target exchange, as detailed below. Wad fees may be covered 409 by the merchant, just like deposit fees, depending on the contract. 410 8. The exchange confirms the merge (per response to the **merge** request). 411 This allows the payee software to instantly 412 affirm to the users that the transaction is final (even if it may not 413 be instantly available to the payee if the payee did not complete the 414 KYC process for the account). 415 9. The payer uses the GET ``/purse/$PURSE_PUB`` endpoint 416 to obtain the receipt from the payee (in the form of the 417 **merge** signature). Query parameters are used to avoid 418 downloading the (already known) encrypted contract and the 419 deposit operations. Long-polling must also be possible for 420 this request. 421 422 423 424 Payment requests 425 ---------------- 426 427 1. The payee creates a **purse** by computing a public-private key pair. 428 2. The payee POSTs to the ``/purse/$PURSE_PUB/merge`` endpoint to 429 both upload the encrypted contract, associate it with the payee's 430 account and signal its agreement to the contract. The 431 **merge** request must be signed by the purse's private key. 432 A second signature must be provided by the account private key, 433 signing the ``$CONTRACT_HASH`` thereby affirming that the payee 434 accepted the contract. 435 3. The payee provides the ``$PURSE_PRIV`` to the payer. 436 4. The payer computes the corresponding public key and uses the 437 new ``/purse/$PURSE_PUB`` endpoint to retrieve 438 the encrypted contract and the merge request, which signifies that 439 the payee would agree to the contract. 440 5. The payer software decrypts the encrypted contract using the purse private 441 key and the payer accepts the contract in the user interface. 442 6. Processing continues depending on the source of the coins: 443 444 a. If the payer's coins originate from the same exchange, the 445 payer software POSTs to the ``/purse/$PURSE_PUB/depost`` endpoint to 446 deposit coins into the purse. The deposit signatures should use 447 ``payto://taler/$PURSE_PUB`` 448 as the target address and signing over the ``$CONTRACT_HASH`` as 449 usual in deposit operations. Note that the lack of a hostname 450 indicates that the target address is a local purse. 451 b. If the payer's coins originate from another exchange, the 452 payer software deposits the coins at the originating exchange 453 using the traditional ``/deposit`` endpoint and a target account of the form 454 ``payto://taler/$EXCHANGE_BASE_URL/$ACCOUNT_PUB``. In this case, 455 the remote exchange charges a **wad fee** and places the remaining 456 amount into a **wad** to inform the target exchange, as detailed below. 457 7. The exchange confirms the deposit. This allows the payer software to instantly 458 affirm to the users that the transaction is final, or to abort or try again 459 in case of errors. 460 8. The payee uses the GET ``/purse/$PURSE_PUB`` endpoint (possibly with long-polling) 461 to be notified about the successful deposit and subsequent completion of the 462 **merge** request. 463 464 465 Payment into accounts at remote exchanges 466 ----------------------------------------- 467 468 In case the coins and the accounts in the transaction flows above are at 469 different exchanges, an aggregated exchange-to-exchange payment (short 470 **wad**) is used. 471 472 1. Exchanges specify a new **wad fee** that they charge for exchange-to-exchange 473 payments. They also specify their wad policy, that is how often they 474 perform exchange-to-exchange transfers. 475 476 .. note:: 477 478 We may want to consider allowing for different wad-speed levels, where 479 express payments (without aggregation) are allowed in return for higher 480 wad fees. 481 482 2. The payer's exchange creates a **wad** by grouping all wad requests 483 to the same target exchange. It executes 484 the transaction when either the **wad threshold** (maximum number 485 of transactons aggregated per wad) or the **wad delay** (maximum 486 delay for transfers) has been reached. 487 3. If the (aggregated) wire transfer fails (say the 488 ``/wire`` endpoint of the payee exchange does not 489 resolve to a valid bank account), the 490 originating exchange automatically creates a full refund for 491 all involved coins (**refund fees** apply). 492 493 .. note:: 494 495 While the **refund fee** amount can be reused, these types of refunds 496 are not approved by a merchant's signature. Thus, we will need 497 a new message type in the coin history to represent these events. 498 499 4. The payee's exchange observes the wire transfer with a wire transfer 500 subject with the originating exchange base URL and a ``$WATID``, 501 and uses a GET ``/wad/$WATID`` request to obtain 502 details about the target accounts. 503 5. When the payer's exchange is requested to provide information about 504 aggregated transfers under the ``$WATID``, it provides a signed list of 505 account public keys and associated amounts that must add up to an 506 amount below the total amount transferred. If they do not, the 507 payee's exchange does not credit any of the accounts and instead 508 preserves the bogus reply (to justify its inaction with its own 509 auditor) and reports the issue to the auditor of the payer's exchange 510 (keeping the received funds for future manual resolution). 511 6. ``taler-exchange-wirewatch`` and the Taler wire gateway API will 512 need to be extended to allow passing inbound wire transfers with ``$WATID`` 513 and exchange base URL to the exchange. Furthermore, another tool 514 is needed to lookup the **wad** data at remote exchanges. 515 7. If the payee trusts the originating exchange, it may consider the 516 transaction ``final`` once the originating exchange has affirmed the 517 deposit (assuming the payer has a way to submit the evidence of that 518 payment, which may not apply in uni-directional scenarios). 519 Otherwise, the payee may simply only trust its own exchange, 520 resulting in the transfer only being considered final after the 521 receiving exchange has confirmed that the **wad** has arrived. 522 523 524 Examples 525 --------- 526 527 Cross-exchange W2W payment request: 528 529 * Bob borrowed 15 EUR from Alice to buy a train ticket. A few days later, 530 Alice wants her money back. She creates a request for payment in her wallet. 531 The wallet creates a purse for 15 EUR at the only exchange that Alice is currently 532 using. The wallet shows her a 533 ``taler://purse/{EXCHANGE_URL}/{PURSE_PRIV}`` 534 link that she can share with Bob. Bob receives the link and opens it with 535 his Taler wallet. Bob is using a different EUR exchange than Alice. Bob's 536 wallet makes a ``/deposit`` request to his own exchange. Shortly after, Alice's 537 exchange receives the wad from Bob's exchange, and credits the money into 538 Alice's purse. 539 540 * Q: How does Bob find out if Alice's exchange supports a wad transfer from 541 Bob's exchange? A: This needs to be part of the wad policy. 542 * Q: How does Bob get a "receipt" to prove that he paid Alice? 543 A: He has Alice's account public key and the associated signature 544 chain leading to her payment request. If he paid someone else by accident, 545 the KYC of Alice's exchange could be used to find out who received the funds. 546 547 Cross-exchange W2W payment offer: 548 549 * Carol wants to send some money to Dave as a birthday gift. Carol knows that 550 Dave is using Taler, but she does not know which exchange he is using. She 551 opens her Taler wallet and initiates a P2P payment. She sends the resulting 552 ``taler://purse/{EXCHANGE_URL}/{PURSE_PRIV}`` in an e-mail to Dave. 553 Dave opens they link in the e-mail with his Taler wallet. 554 Since Dave is using a different exchange than Carol, Dave's wallet 555 issues a **merge** request to Carol's exchange pointing Carol's exchange 556 to Dave's account at his exchange. Shortly after, 557 Dave's exchange receives a **wad** from Carol's exchange, 558 and credits Dave's account with the money. 559 560 561 State machine for Purses 562 ------------------------ 563 564 .. code-block:: none 565 566 // The "OPEN-ACCOUNT" start state implies that the purse is associated 567 // with an account and a merge request for that account. 568 -> OPEN-ACCOUNT 569 570 // "Partial" means that it is filled with a fraction of the coins 571 // indicated in the creation request. 572 OPEN-ACCOUNT -> PARTIAL 573 574 // The purse was filled with as many coins 575 // as indicated in the creation request, resulting in the transaction to complete. 576 OPEN-ACCOUNT -> ACCEPTED 577 578 // The offer expired before any payment was received. 579 OPEN-ACCOUNT -> CLOSED 580 581 // The purse was filled with as many coins 582 // as indicated in the creation request, resulting in the transaction to complete. 583 PARTIAL -> ACCEPTED 584 585 // During an abort, already deposited coins are being taken out of the purse. 586 PARTIAL -> OPEN-ACCOUNT 587 588 // All coins put into the purse are refunded because the 589 // payer never completed the purchase before the timeout. 590 PARTIAL -> CLOSED 591 592 // The "OPEN-DEPOSIT" start state implies that the purse is filled with 593 // deposited coins. 594 -> OPEN-DEPOSIT 595 596 // Paid and merged with an account (locally or via a wad) 597 OPEN-DEPOSIT -> ACCEPTED 598 599 // The offer expired without a merge request. 600 OPEN-DEPOSIT -> CLOSED 601 602 603 Additional considerations 604 ------------------------- 605 606 * Creation of additional accounts per customer can 607 be discouraged by asking for higher fees. 608 * The global transaction volume of one customer can be easily 609 determined by authorities, which can then trigger further audits 610 of the customer 611 * As a technically expensive but more water-tight measure, normal 612 withdrawals from reserves could be disallowed. Instead, 613 a modified refresh protocol could ensure that whoever has knowledge 614 of the account private key can also learn the private keys 615 of coins withdrawn from that account, thereby removing 616 Taler's "one-hop withdrawal loohole". 617 618 619 Exchange database schema changes 620 -------------------------------- 621 622 We need to exchange the existing reserves table to include bits for KYC-needed 623 and KYC-passed. Also, we need to store the payto://-URI of the bank account. 624 625 Finally, we may need to keep some link to the KYC data, even though the 626 exchange technically does not need it, but likely there might be regulatory 627 reasons to have that association for legal inquiries. (However, it would 628 also be possible to keep that link only in the external KYC service's 629 database.) 630 631 .. sourcecode:: sql 632 633 -- Everything in one big transaction 634 BEGIN; 635 -- Check patch versioning is in place. 636 SELECT _v.register_patch('exchange-TBD', NULL, NULL); 637 -- 638 CREATE TABLE IF NOT EXISTS partners 639 (partner_serial_id BIGSERIAL UNIQUE 640 ,partner_master_pub BYTEA NOT NULL CHECK(LENGTH(reserve_pub)=32) 641 ,start_date INT8 NOT NULL 642 ,end_date INT8 NOT NULL 643 ,wad_frequency INT8 NOT NULL 644 ,wad_fee_val INT8 NOT NULL 645 ,wad_fee_frac INT4 NOT NULL 646 ,master_sig BYTEA NOT NULL CHECK (LENGTH(master_sig)=64)) 647 ,partner_base_url TEXT NOT NULL 648 ); 649 COMMENT ON TABLE partners 650 IS 'exchanges we do wad transfers to'; 651 COMMENT ON COLUMN partners.partner_master_pub 652 IS 'offline master public key of the partner'; 653 COMMENT ON COLUMN partners.start_date 654 IS 'starting date of the partnership'; 655 COMMENT ON COLUMN partners.end_date 656 IS 'end date of the partnership'; 657 COMMENT ON COLUMN partners.wad_frequency 658 IS 'how often do we promise to do wad transfers'; 659 COMMENT ON COLUMN partners.wad_fee_val 660 IS 'how high is the fee for a wallet to be added to a wad to this partner'; 661 COMMENT ON COLUMN partners.partner_base_url 662 IS 'base URL of the REST API for this partner'; 663 COMMENT ON COLUMN partners.master_sig 664 IS 'signature of our master public key affirming the partnership, of purpose TALER_SIGNATURE_MASTER_PARTNER_DETAILS'; 665 -- 666 ALTER TABLE reserves 667 ADD COLUMN kyc_needed BOOLEAN NOT NULL DEFAULT (false) 668 ADD COLUMN kyc_passed BOOLEAN NOT NULL DEFAULT (false) 669 ADD COLUMN payto_uri TEXT DEFAULT (NULL) 670 ADD COLUMN kyc_link TEXT DEFAULT (NULL); 671 COMMENT ON COLUMN reserves.kyc_needed 672 IS 'set to true once a reserve was merged with a purse'; 673 COMMENT ON COLUMN reserves.kyc_passed 674 IS 'set to true once the user performed the KYC check'; 675 COMMENT ON COLUMN reserves.payto_uri 676 IS 'bank account details to use in case reserve is closed'; 677 COMMENT ON COLUMN reserves.kyc_link 678 IS 'optional link to KYC data'; 679 -- 680 CREATE TABLE IF NOT EXISTS kyc_requests 681 (kyc_request_serial_id BIGSERIAL UNIQUE 682 ,reserve_uuid INT8 NOT NULL REFERENCES reserves (reserve_uuid) ON DELETE CASCADE 683 ,kyc_date INT8 NOT NULL 684 ,kyc_retry INT8 NOT NULL 685 ,kyc_fee_val INT8 NOT NULL 686 ,kyc_fee_frac INT4 NOT NULL 687 ,reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)) 688 ,kyc_id TEXT NOT NULL 689 ,PRIMARY KEY (reserve_uuid, kyc_date) 690 ); 691 COMMENT ON TABLE kyc_requests 692 IS 'KYC processes initiated by the owner of a reserve'; 693 COMMENT ON COLUMN kyc_requests.reserve_uuid 694 IS 'Reserve for which the KYC request was triggered.'; 695 COMMENT ON COLUMN kyc_requests.reserve_sig 696 IS 'Signature affirming the KYC request'; 697 COMMENT ON COLUMN kyc_requests.kyc_fee_val 698 IS 'Amount paid by the reserve for the KYC process.'; 699 COMMENT ON COLUMN kyc_requests.kyc_date 700 IS 'When was the KYC process originally initiated.'; 701 COMMENT ON COLUMN kyc_requests.kyc_retry 702 IS 'Timestamp when we should next query the KYC backend for the KYC status. The maximum possible numeric value indicates that we do not need to ever check the status of this KYC process again.'; 703 COMMENT ON COLUMN kyc_requests.kyc_id 704 IS 'ID of the KYC process, used to compute the URL returned to the client as well as for the exchange to check if the KYC has completed. Format depends on the KYC process of the bank.'; 705 -- 706 CREATE TABLE IF NOT EXISTS mergers 707 (merge_request_serial_id BIGSERIAL UNIQUE 708 ,reserve_uuid BYTEA NOT NULL REFERENCES reserves (reserve_uuid) ON DELETE CASCADE 709 ,partner_serial_id INT8 REFERENCES partners(partner_serial_id) ON DELETE CASCADE, 710 ,reserve_pub BYTEA NOT NULL CHECK (LENGTH(reserve_pub)=32), 711 ,purse_pub BYTEA NOT NULL CHECK (LENGTH(purse_pub)=32), 712 ,reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)) 713 ,purse_sig BYTEA NOT NULL CHECK (LENGTH(purse_sig)=64)) 714 ,merge_timestamp INT8 NOT NULL 715 ,purse_expiration INT8 NOT NULL 716 ,h_contract_terms BYTEA NOT NULL CHECK (LENGTH(h_contract_terms)=64)) 717 ,purse_val INT8 NOT NULL 718 ,purse_frac INT4 NOT NULL 719 ,PRIMARY KEY (purse_pub) 720 ); 721 COMMENT ON TABLE mergers 722 IS 'Merge requests where a purse- and account-owner requested merging the purse into the account'; 723 COMMENT ON COLUMN mergers.reserve_uuid 724 IS 'identifies the reserve'; 725 COMMENT ON COLUMN mergers.partner_serial_id 726 IS 'identifies the partner exchange, NULL in case the target reserve lives at this exchange'; 727 COMMENT ON COLUMN mergers.reserve_pub 728 IS 'public key of the target reserve'; 729 COMMENT ON COLUMN mergers.purse_pub 730 IS 'public key of the purse'; 731 COMMENT ON COLUMN mergers.reserve_sig 732 IS 'signature by the reserve private key affirming the merge'; 733 COMMENT ON COLUMN mergers.purse_sig 734 IS 'signature by the purse private key affirming the merge'; 735 COMMENT ON COLUMN mergers.merge_timestamp 736 IS 'when was the merge message signed'; 737 COMMENT ON COLUMN mergers.purse_expiration 738 IS 'when is the purse set to expire'; 739 COMMENT ON COLUMN mergers.h_contract_terms 740 IS 'hash of the contract terms both sides are to agree upon'; 741 COMMENT ON COLUMN mergers.purse_val 742 IS 'amount to be transferred from the purse to the reserve (excludes deposit fees)'; 743 CREATE INDEX IF NOT EXISTS mergers_reserve_uuid 744 ON mergers (reserve_uuid); 745 COMMENT ON INDEX mergers_reserve_uuid 746 IS 'needed in reserve history computation'; 747 -- 748 CREATE TABLE IF NOT EXISTS contracts 749 (contract_serial_id BIGSERIAL UNIQUE 750 ,purse_pub BYTEA NOT NULL CHECK (LENGTH(purse_pub)=32), 751 ,pub_ckey BYTEA NOT NULL CHECK (LENGTH(pub_ckey)=32)), 752 ,e_contract BYTEA NOT NULL, 753 ,PRIMARY KEY (purse_pub) 754 ); 755 COMMENT ON TABLE contracts 756 IS 'encrypted contracts associated with purses'; 757 COMMENT ON COLUMN contracts.purse_pub 758 IS 'public key of the purse that the contract is associated with'; 759 COMMENT ON COLUMN contracts.pub_ckey 760 IS 'Public ECDH key used to encrypt the contract, to be used with the purse private key for decryption'; 761 COMMENT ON COLUMN contracts.e_contract 762 IS 'AES-GCM encrypted contract terms (contains gzip compressed JSON after decryption)'; 763 -- 764 CREATE TABLE IF NOT EXISTS history_requests 765 (reserve_uuid INT8 NOT NULL REFERENCES reserves(reserve_uuid) ON DELETE CASCADE, 766 ,request_timestamp INT8 NOT NULL 767 ,reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)) 768 ,history_fee_val INT8 NOT NULL 769 ,history_fee_frac INT4 NOT NULL 770 ,PRIMARY KEY (reserve_uuid,request_timestamp) 771 ); 772 COMMENT ON TABLE history_requests 773 IS 'Paid history requests issued by a client against a reserve'; 774 COMMENT ON COLUMN history_requests.request_timestamp 775 IS 'When was the history request made'; 776 COMMENT ON COLUMN history_requests.reserve_sig 777 IS 'Signature approving payment for the history request'; 778 COMMENT ON COLUMN history_requests.history_fee_val 779 IS 'History fee approved by the signature'; 780 -- 781 CREATE TABLE IF NOT EXISTS close_requests 782 (reserve_uuid INT8 NOT NULL REFERENCES reserves(reserve_uuid) ON DELETE CASCADE, 783 ,close_timestamp INT8 NOT NULL 784 ,reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)) 785 ,close_val INT8 NOT NULL 786 ,close_frac INT4 NOT NULL 787 ,PRIMARY KEY (reserve_uuid,close_timestamp) 788 ); 789 COMMENT ON TABLE close_requests 790 IS 'Explicit requests by a reserve owner to close a reserve immediately'; 791 COMMENT ON COLUMN close_requests.close_timestamp 792 IS 'When the request was created by the client'; 793 COMMENT ON COLUMN close_requests.reserve_sig 794 IS 'Signature affirming that the reserve is to be closed'; 795 COMMENT ON COLUMN close_requests.close_val 796 IS 'Balance of the reserve at the time of closing, to be wired to the associated bank account (minus the closing fee)'; 797 798 -- 799 CREATE TABLE IF NOT EXISTS purse_requests 800 (purse_deposit_serial_id BIGSERIAL UNIQUE 801 ,purse_pub BYTEA NOT NULL CHECK (LENGTH(purse_pub)=32), 802 ,purse_expiration INT8 NOT NULL 803 ,h_contract_terms BYTEA NOT NULL CHECK (LENGTH(h_contract_terms)=64) 804 ,amount_with_fee_val INT8 NOT NULL 805 ,amount_with_fee_frac INT4 NOT NULL 806 ,purse_sig BYTEA NOT NULL CHECK(LENGTH(purse_sig)=64) 807 ,PRIMARY KEY (purse_pub,coin_pub) 808 ); 809 COMMENT ON TABLE purse_requests 810 IS 'Requests establishing purses, associating them with a contract but without a target reserve'; 811 COMMENT ON COLUMN purse_requests.purse_pub 812 IS 'Public key of the purse'; 813 COMMENT ON COLUMN purse_requests.purse_expiration 814 IS 'When the purse is set to expire'; 815 COMMENT ON COLUMN purse_requests.h_contract_terms 816 IS 'Hash of the contract the parties are to agree to'; 817 COMMENT ON COLUMN purse_requests.amount_with_fee_val 818 IS 'Total amount expected to be in the purse'; 819 COMMENT ON COLUMN purse_requests.purse_sig 820 IS 'Signature of the purse affirming the purse parameters, of type TALER_SIGNATURE_PURSE_REQUEST'; 821 -- 822 CREATE TABLE IF NOT EXISTS purse_deposits 823 (purse_deposit_serial_id BIGSERIAL UNIQUE 824 ,purse_pub BYTEA NOT NULL CHECK (LENGTH(purse_pub)=32), 825 ,coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub) ON DELETE CASCADE 826 ,amount_with_fee_val INT8 NOT NULL 827 ,amount_with_fee_frac INT4 NOT NULL 828 ,coin_sig BYTEA NOT NULL CHECK(LENGTH(coin_sig)=64) 829 ,PRIMARY KEY (purse_pub,coin_pub) 830 ); 831 COMMENT ON TABLE purse_deposits 832 IS 'Requests depositing coins into a purse'; 833 COMMENT ON COLUMN purse_deposits.purse_pub 834 IS 'Public key of the purse'; 835 COMMENT ON COLUMN purse_deposits.coin_pub 836 IS 'Public key of the coin being deposited'; 837 COMMENT ON COLUMN purse_deposits.amount_with_fee_val 838 IS 'Total amount being deposited'; 839 COMMENT ON COLUMN purse_deposits.coin_sig 840 IS 'Signature of the coin affirming the deposit into the purse, of type TALER_SIGNATURE_PURSE_DEPOSIT'; 841 -- 842 CREATE TABLE IF NOT EXISTS wads_out 843 (wad_out_serial_id BIGSERIAL UNIQUE 844 ,wad_id BYTEA PRIMARY KEY CHECK (LENGTH(wad_id)=24) 845 ,partner_serial_id INT8 NOT NULL REFERENCES partners(partner_serial_id) ON DELETE CASCADE, 846 ,amount_val INT8 NOT NULL 847 ,amount_frac INT4 NOT NULL 848 ,execution_time INT8 NOT NULL 849 ,UNIQUE (exchange_url, execution_time) 850 ); 851 COMMENT ON TABLE wads_out 852 IS 'Wire transfers made to another exchange to transfer purse funds'; 853 COMMENT ON COLUMN wads_out.wad_id 854 IS 'Unique identifier of the wad, part of the wire transfer subject'; 855 COMMENT ON COLUMN wads_out.partner_serial_id 856 IS 'target exchange of the wad'; 857 COMMENT ON COLUMN wads_out.amount_val 858 IS 'Amount that was wired'; 859 COMMENT ON COLUMN wads_out.execution_time 860 IS 'Time when the wire transfer was scheduled'; 861 -- 862 CREATE TABLE IF NOT EXISTS wad_out_entries 863 (wad_out_entry_serial_id BIGSERIAL UNIQUE 864 ,wad_out_serial_id INT8 REFERENCES wads_out (wad_out_serial_id) ON DELETE CASCADE 865 ,reserve_pub BYTEA NOT NULL CHECK(LENGTH(reserve_pub)=32) 866 ,purse_pub BYTEA PRIMARY KEY CHECK(LENGTH(purse_pub)=32) 867 ,h_contract BYTEA NOT NULL CHECK(LENGTH(h_contract)=64) 868 ,purse_expiration INT8 NOT NULL 869 ,merge_timestamp INT8 NOT NULL 870 ,amount_with_fee_val INT8 NOT NULL 871 ,amount_with_fee_frac INT4 NOT NULL 872 ,wad_fee_val INT8 NOT NULL 873 ,wad_fee_frac INT4 NOT NULL 874 ,deposit_fees_val INT8 NOT NULL 875 ,deposit_fees_frac INT4 NOT NULL 876 ,reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)) 877 ,purse_sig BYTEA NOT NULL CHECK (LENGTH(purse_sig)=64)) 878 ); 879 CREATE INDEX IF NOT EXISTS wad_out_entries_index_by_wad 880 ON wad_out_entries (wad_out_serial_id); 881 COMMENT ON TABLE wad_out_entries 882 IS 'Purses combined into a wad'; 883 COMMENT ON COLUMN wad_out_entries.wad_out_serial_id 884 IS 'Wad the purse was part of'; 885 COMMENT ON COLUMN wad_out_entries.reserve_pub 886 IS 'Target reserve for the purse'; 887 COMMENT ON COLUMN wad_out_entries.purse_pub 888 IS 'Public key of the purse'; 889 COMMENT ON COLUMN wad_out_entries.h_contract 890 IS 'Hash of the contract associated with the purse'; 891 COMMENT ON COLUMN wad_out_entries.purse_expiration 892 IS 'Time when the purse expires'; 893 COMMENT ON COLUMN wad_out_entries.merge_timestamp 894 IS 'Time when the merge was approved'; 895 COMMENT ON COLUMN wad_out_entries.amount_with_fee_val 896 IS 'Total amount in the purse'; 897 COMMENT ON COLUMN wad_out_entries.wad_fee_val 898 IS 'Wat fee charged to the purse'; 899 COMMENT ON COLUMN wad_out_entries.deposit_fees_val 900 IS 'Total deposit fees charged to the purse'; 901 COMMENT ON COLUMN wad_out_entries.reserve_sig 902 IS 'Signature by the receiving reserve, of purpose TALER_SIGNATURE_ACCOUNT_MERGE'; 903 COMMENT ON COLUMN wad_out_entries.purse_sig 904 IS 'Signature by the purse of purpose TALER_SIGNATURE_PURSE_MERGE'; 905 -- 906 CREATE TABLE IF NOT EXISTS wads_in 907 (wad_in_serial_id BIGSERIAL UNIQUE 908 ,wad_id BYTEA PRIMARY KEY CHECK (LENGTH(wad_id)=24) 909 ,origin_exchange_url TEXT NOT NULL 910 ,amount_val INT8 NOT NULL 911 ,amount_frac INT4 NOT NULL 912 ,arrival_time INT8 NOT NULL 913 ,UNIQUE (wad_id, origin_exchange_url) 914 ); 915 COMMENT ON TABLE wads_in_entries 916 IS 'Incoming exchange-to-exchange wad wire transfers'; 917 COMMENT ON COLUMN wads_in.wad_id 918 IS 'Unique identifier of the wad, part of the wire transfer subject'; 919 COMMENT ON COLUMN wads_in.origin_exchange_url 920 IS 'Base URL of the originating URL, also part of the wire transfer subject'; 921 COMMENT ON COLUMN wads_in.amount_val 922 IS 'Actual amount that was received by our exchange'; 923 COMMENT ON COLUMN wads_in.arrival_time 924 IS 'Time when the wad was received'; 925 -- 926 CREATE TABLE IF NOT EXISTS wad_in_entries 927 (wad_in_entry_serial_id BIGSERIAL UNIQUE 928 ,wad_in_serial_id INT8 REFERENCES wads_in (wad_serial_id) ON DELETE CASCADE 929 ,reserve_pub BYTEA NOT NULL CHECK(LENGTH(reserve_pub)=32) 930 ,purse_pub BYTEA PRIMARY KEY CHECK(LENGTH(purse_pub)=32) 931 ,h_contract BYTEA NOT NULL CHECK(LENGTH(h_contract)=64) 932 ,purse_expiration INT8 NOT NULL 933 ,merge_timestamp INT8 NOT NULL 934 ,amount_with_fee_val INT8 NOT NULL 935 ,amount_with_fee_frac INT4 NOT NULL 936 ,wad_fee_val INT8 NOT NULL 937 ,wad_fee_frac INT4 NOT NULL 938 ,deposit_fees_val INT8 NOT NULL 939 ,deposit_fees_frac INT4 NOT NULL 940 ,reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)) 941 ,purse_sig BYTEA NOT NULL CHECK (LENGTH(purse_sig)=64)) 942 ); 943 COMMENT ON TABLE wad_in_entries 944 IS 'list of purses aggregated in a wad according to the sending exchange'; 945 COMMENT ON COLUMN wad_in_entries.wad_in_serial_id 946 IS 'wad for which the given purse was included in the aggregation'; 947 COMMENT ON COLUMN wad_in_entries.reserve_pub 948 IS 'target account of the purse (must be at the local exchange)'; 949 COMMENT ON COLUMN wad_in_entries.purse_pub 950 IS 'public key of the purse that was merged'; 951 COMMENT ON COLUMN wad_in_entries.h_contract 952 IS 'hash of the contract terms of the purse'; 953 COMMENT ON COLUMN wad_in_entries.purse_expiration 954 IS 'Time when the purse was set to expire'; 955 COMMENT ON COLUMN wad_in_entries.merge_timestamp 956 IS 'Time when the merge was approved'; 957 COMMENT ON COLUMN wad_in_entries.amount_with_fee_val 958 IS 'Total amount in the purse'; 959 COMMENT ON COLUMN wad_in_entries.wad_fee_val 960 IS 'Total wad fees paid by the purse'; 961 COMMENT ON COLUMN wad_in_entries.deposit_fees_val 962 IS 'Total deposit fees paid when depositing coins into the purse'; 963 COMMENT ON COLUMN wad_in_entries.reserve_sig 964 IS 'Signature by the receiving reserve, of purpose TALER_SIGNATURE_ACCOUNT_MERGE'; 965 COMMENT ON COLUMN wad_in_entries.purse_sig 966 IS 'Signature by the purse of purpose TALER_SIGNATURE_PURSE_MERGE'; 967 CREATE INDEX IF NOT EXISTS wad_in_entries_wad_in_serial 968 ON wad_in_entries (wad_in_serial_id); 969 CREATE INDEX IF NOT EXISTS wad_in_entries_reserve_pub 970 ON wad_in_entries (reserve_pub); 971 COMMENT ON INDEX wad_in_entries_wad_in_serial 972 IS 'needed to lookup all transfers associated with a wad'; 973 COMMENT ON INDEX wad_in_entries_reserve_pub 974 IS 'needed to compute reserve history'; 975 -- 976 CREATE TABLE IF NOT EXISTS p2pfees 977 (p2pfees_serial_id BIGSERIAL UNIQUE 978 ,start_date INT8 NOT NULL 979 ,end_date INT8 NOT NULL 980 ,kyc_timeout INT8 NOT NULL 981 ,purse_timeout INT8 NOT NULL 982 ,history_retention INT8 NOT NULL 983 ,purse_account_limit INT NOT NULL 984 ,kyc_fee_val INT8 NOT NULL 985 ,kyc_fee_frac INT4 NOT NULL 986 ,history_fee_val INT8 NOT NULL 987 ,history_fee_frac INT4 NOT NULL 988 ,account_fee_val INT8 NOT NULL 989 ,account_fee_frac INT4 NOT NULL 990 ,purse_fee_val INT8 NOT NULL 991 ,purse_fee_frac INT4 NOT NULL 992 ,master_sig BYTEA NOT NULL CHECK (LENGTH(master_sig)=64)) 993 ); 994 -- 995 CREATE TABLE IF NOT EXISTS partner_accounts 996 (payto_uri VARCHAR PRIMARY KEY 997 ,partner_serial_id INT8 REFERENCES partners(partner_serial_id) ON DELETE CASCADE, 998 ,partner_master_sig BYTEA CHECK (LENGTH(partner_master_sig)=64) 999 ,last_seen INT8 NOT NULL 1000 ); 1001 CREATE INDEX IF NOT EXISTS partner_accounts_index_by_partner_and_time 1002 ON partner_accounts (partner_serial_id,last_seen); 1003 COMMENT ON TABLE partner_accounts 1004 IS 'Table with bank accounts of the partner exchange. Entries never expire as we need to remember the signature for the auditor.'; 1005 COMMENT ON COLUMN wire_accounts.payto_uri 1006 IS 'payto URI (RFC 8905) with the bank account of the partner exchange.'; 1007 COMMENT ON COLUMN wire_accounts.partner_master_sig 1008 IS 'Signature of purpose TALER_SIGNATURE_MASTER_WIRE_DETAILS by the partner master public key'; 1009 COMMENT ON COLUMN wire_accounts.last_seen 1010 IS 'Last time we saw this account as being active at the partner exchange. Used to select the most recent entry, and to detect when we should check again.'; 1011 -- Complete transaction 1012 COMMIT; 1013 1014 1015 1016 Alternatives 1017 ============ 1018 1019 * The payer could directly give deposit permissions to the payee. 1020 This has two problems: 1021 1022 1. The payer does not know the wire details of the payee. 1023 Thus we would need to introduce some "wildcard deposit permission", 1024 where the exchange allows any wire details on ``/deposit``. 1025 2. The payment information would be rather large, making it difficult 1026 to transfer via a QR code or short text message. 1027 1028 * Account history exceeding a configurable time limit (like 6 years) 1029 could be subject to garbage collection. However, doing so may be difficult to 1030 square with onboarding new auditors in the presence of existing 1031 accounts, as the auditors could then not reconstruct the account 1032 balances from cryptographic proofs. 1033 1034 * Accounts without KYC check could be eventually closed. However, 1035 even if the coins used to fill the account are refunded, it 1036 would be difficult to inform the originating wallet that the 1037 coins have received a refund. This applies even more strongly 1038 in case of accounts filled via wads, where in theory the 1039 originating exchange may not even be in business anymore. 1040 Thus, it is cleaner and simpler to declare such funds forfeit. 1041 1042 1043 Drawbacks 1044 ========= 1045 1046 The overall changes required are not small: 1047 1048 * New **KYC fee**, **wad fee** and **account history fee** 1049 required in ``/keys`` endpoint (similar to closing and wire fees), 1050 requires some work across toolchain (offline signature, etc.) 1051 * New ``taler`` wire method needs special case to possibly bypass 1052 (same exchange scenario, with long-poll trigger) the usual aggregation logic. 1053 * New exchange table(s) required to store inbound amounts by account. 1054 Likely two tables, one for local exchange p2p and one for remote exchange p2p 1055 payments. 1056 * New exchange table for purses required (for remote p2p payments). 1057 * New exchange logic required to make ``transfers`` requests for purses 1058 (another separate process). 1059 * New ``/account/$ACCOUNT_PUB/kyc`` endpoint required. 1060 * New ``/purse/$PURSE_PUB/merge`` endpoint required. 1061 * Additional tables to be verified by the auditor. 1062 * ``taler-exchange-wirewatch`` needs to support receiving purses closures 1063 and exchange-to-exchange wire transfers with WTIDs. 1064 1065 Aside from implementation complexity, the solution has the following drawbacks: 1066 1067 * If a W2W payment failed (say the receiver lost the account private key), 1068 the customer's money can be forfeit. Alas, this should be very, very rare 1069 as the wallet software can trivially ensure that a backup was made of the 1070 account private key before initiating the KYC process. 1071 1072 1073 Refinements 1074 =========== 1075 1076 In the original design, a payer making a payment offer sends the purse private 1077 key to the payee, so that the payee can sign the merge request with it. This 1078 creates a security issue, as theoretically the payee could sign a different 1079 contract with the purse private key, and conspire with the exchange to replace 1080 the original contract. In this case, the payer would be making a payment to 1081 the "wrong" contract, and have no proof of the exchange an payee conspiring 1082 against it. 1083 1084 A simple fix seems possible: instead of having simply one public-private key 1085 pair for a purse, we have a PayerContractKey and a PurseMergeKey pair. The payer 1086 would pay into a purse identified by the PayerContractKey and associate a 1087 PurseMergeKey with the purse. The payer can then safely share the 1088 PayeeMergeKey with the payee, as it is ONLY useful for the merge and not to 1089 sign the contract. Payments would be made into a purse identified by the 1090 PurseContractKey. 1091 1092 When payments flow in the other direction, the split of the keys seems 1093 unnecessary (as only a public key is transmitted anyway. However, schema-wise, 1094 signing the contract with the PurseContractKey and the merge with the 1095 PurseMergeKey would still work. Only the public PurseContractKey would need 1096 to be sent to the payer. 1097 1098 1099 1100 Q / A 1101 ===== 1102 1103 * Q: Why are direct payments into accounts allowed? 1104 1105 * A: Direct payments into accounts may be used by the customer 1106 to fund the expenses for using the account. They should not 1107 be used for payments between customers, as contract terms for 1108 the ``/deposit`` of coins cannot be negotiated. Furthermore, 1109 the sender of the payment cannot be sure that the account of 1110 the sender is still valid. 1111 1112 * Q: Who "owns" a purse? The payer of payee? 1113 1114 * Both. Ownership is shared. Either the payer issues 1115 a refund on the purse, or the payee claims it by merging 1116 it with one of their accounts. 1117 1118 * Q: Are purses created with a pre-determined "capacity"? 1119 1120 * A: Yes. Otherwise there would be weird failure modes when the payee 1121 merges the purse before the payer fully deposited into it. 1122 1123 * Q: Are account public keys considered private or public data? 1124 1125 * A: Public. The payer needs a signature from the payee affirming 1126 that they accepted the contract, and this requires a key that 1127 is linked to the KYC process to be meaningful. However, the 1128 software should NOT permit direct payments into foreign accounts 1129 because it would be too easy to accidentally send payments that 1130 nobody can receive, because the account public key is wrong/lost. 1131 1132 * Q: Why do traditional merchant payments not use purses? 1133 1134 * Refunds are not possible with purses after they are closed. 1135 * The customer cannot prove that they own the contract terms 1136 (Contract terms claiming requires interactivity that is not 1137 possible in all W2W scenarios.) Thus, while payers can prove 1138 that they paid, the payee may claim someone else also 1139 bought the same product. A secure channel must thus be used to 1140 exchange the purchase offer. 1141 1142 * Q: What determines when a wad transfer can happen between two exchanges? 1143 1144 * Exchanges explicitly state which other exchanges they are willing 1145 to do wad transfers with (and how often, at what cost). This may involve 1146 abstract policies like sharing an auditor, using the same currency and the 1147 same (banking) protocol, or other constraints (like a specific list of 1148 exchanges). 1149 1150 * Q: What happens if the owner of a reserve never drains it? 1151 1152 * Reserves are eventually closed. If the reserve is associated 1153 with a bank account, the remaining funds are sent to that bank 1154 account. If the reserve was created via a merge, and the owner 1155 failed to associate a bank account with it (say because the 1156 KYC step never happened), then the reserve balance is forfeit 1157 to the exchange upon expiration.