summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--design-documents/007-payment.rst143
-rw-r--r--design-documents/fees.rst120
-rw-r--r--design-documents/index.rst1
3 files changed, 264 insertions, 0 deletions
diff --git a/design-documents/007-payment.rst b/design-documents/007-payment.rst
new file mode 100644
index 00000000..206d1f77
--- /dev/null
+++ b/design-documents/007-payment.rst
@@ -0,0 +1,143 @@
+Design Doc 007: Specification of the Payment Flow
+#################################################
+
+Summary
+=======
+
+This design document describes how the payment flow works in the browser, and how
+features like session IDs, re-purchase detection and refunds interact.
+
+Requirements
+============
+
+* The payment flow must both support wallets that are integrated in the browser,
+ as well as external wallets (mobile phone, command line)
+* The initiator of the payment can be a Website or another channel,
+ such as an e-mail or a messaging service.
+* For paid digital content, there should be a reasonable technical barrier to
+ sharing the content with unauthorized users
+* A simple API should be offered to shops
+* Sharing of links or re-visiting of bookmarks should result in well-defined,
+ behavior instead of random, ugly error messages.
+
+Proposed Solution
+=================
+
+Session-bound payment flow for Web resources
+--------------------------------------------
+
+In this payment flow, the user initiates the payment by navigating to a
+paywalled Web resource. Let *resource-URL* be the URL of the paywalled resource.
+
+When *resource-URL* is requested, the storefront runs the following steps:
+
+1. Extract the the *order-ID* (or null) and *resource name* from the *resource-URL*.
+2. Extract the *session-ID* (or null) from the request's signed cookie
+3. If *session-ID* and *order-ID* is non-null and the storefront's
+ *session-payment-cache* contains the tuple (*order-ID*, *resource-name*, *session-ID*),
+ return to the client the content for *resource name*. **Terminate.**
+4. If the *session-ID* is null, assign a fresh session ID and set it in a cookie to be sent with the response
+5. If *order-ID* is null, create a new order for *resource-name* by doing a ``POST /private/orders`` to
+ the merchant backend. Store the new order ID as *order-ID*.
+6. Check the status of the payment for *order-ID* under *session-ID* by doing a ``GET /private/orders/{order-ID}?session_id={session-ID}``.
+ This results in the *order-status*, *refund-amount* and the *client-order-status-URL*.
+7. If the *order-status* is paid and *refund-amount* is non-zero,
+ return to the client the refund info page for *resource name*. **Terminate.**
+8. If the *order-status* is paid, store the tuple (*order-ID*, *resource-name*, *session-ID*) in *session-payment-cache*
+ and return to the client the content for *resource name*. **Terminate.**
+9. Otherwise, the *order-status* is unpaid. Redirect the client to *client-order-status-URL*. **Terminate.**
+
+
+The merchant backend runs the following steps to generate the
+*client-order-status-URL* when processing a request for ``GET
+/private/orders/{order-ID}?session_id={session-ID}``:
+
+1. Let *session-ID* be the session ID of the request (note: **not** the last paid session ID)
+2. If *order-ID* does not identify an existing order, return an error. **Terminate**.
+3. If *order-ID* identifies an order that is *unclaimed* and has claim token *claim-token*, return the URL
+
+ ::
+
+ {backendBaseUrl}/orders/{order-ID}?token={claim-token}&session_id={session-ID}
+
+ **Terminate.**
+4. If *order-ID* identifies an order that is either *claimed* or *paid* and has contract terms hash *contract-hash*, return the URL
+
+ ::
+
+ {backendBaseUrl}/orders/{order-ID}?h_contract={contract-hash}&session_id={session-ID}
+
+The merchant backend runs the following steps to generate the HTML page for
+``GET /orders/{order-ID}?session_id={session-ID}&claim_token={claim-token}&h_contract={contract-hash}``:
+
+1. If *order-ID* does not identify an existing order, render an error page. **Terminate.**
+2. If *order-ID* identifies a paid order *ord*, run these steps:
+
+ 1. If the *contract-hash* request parameter does not match the contract terms hash of *ord*,
+ return a 403 Forbidden response. **Terminate.**
+ 2. If *ord* has refunds that are not picked up, prompt the URI
+
+ ::
+
+ taler{proto_suffix}://refund/{/merchant_prefix*}/{order-id}/{session-id}
+
+ Redirect to the *fulfillment-URL* of *ord* once the refund is picked up and
+ payment has been proven under *session-ID*.
+
+ **Terminate.**
+
+ 3. Prompt the URI
+
+ ::
+
+ taler{proto_suffix}://pay/{/merchant_prefix*}/{order-id}/{session-id}
+
+ Redirect to the *fulfillment-URL* of *ord* once
+ payment has been proven under *session-ID*.
+
+ **Terminate.**
+
+
+3. If *order-ID* identifies an unpaid order *ord*, run these steps:
+
+ 1. If the the *claim-token* request parameter does not matches the claim token of
+ *ord*, return a 403 Forbidden response. **Terminate**.
+ 2. Prompt the URI
+
+ ::
+
+ taler{proto_suffix}://pay/{/merchant_prefix*}/{order-id}/{session-ID}?c={claim-token}
+
+ Redirect to the *fulfillment-URL* of *ord* once
+ payment has been proven under *session-ID*.
+
+ If there is a non-null *already-paid-order-ID* for *session-ID*, redirect
+ to the *fulfillment-URL* of *already-paid-order-ID*
+
+ **Terminate.**
+
+
+Discussion / Q&A
+================
+
+Covered Scenarios
+-----------------
+
+* **Re-purchase detection**. Let's say a detached wallet has already successfully paid for a resource URL.
+ A browser navigates to the resource URL. The storefront will generate a new order and assign a session ID.
+ Upon scanning the QR code, the wallet will detect that it already has puchased the resource (checked via the fulfillment URL).
+ It will then prove the payment of the **old** order ID under the **new** session ID.
+
+
+Problematic Scenarios
+---------------------
+
+Let's say I bought some article a few months ago and I lost my wallet. I still have the augmented fulfillment URL
+for the article bookmarked. When I re-visit the URL, I will be prompted via QR code, but I can *never* prove
+that I already paid, because I lost my wallet!
+
+In this case, it might make sense to include some "make new purchase" link on the client order status page.
+It's not clear if this is a common/important scenario though.
+
+But we might want to make clear on the client order status page that it's showing a QR code for something
+that was already paid.
diff --git a/design-documents/fees.rst b/design-documents/fees.rst
new file mode 100644
index 00000000..96459423
--- /dev/null
+++ b/design-documents/fees.rst
@@ -0,0 +1,120 @@
+Design Doc 003: Fee Structure Metrics
+#####################################
+
+.. note::
+
+ This design document is currently a draft, it
+ does not reflect any implementation decisions yet.
+
+Summary
+=======
+
+We discuss criterea for evaluating an exchange's denomination and fee structure.
+
+Motivation
+==========
+
+Currently, users of a Taler wallet can't easily judge the fee structure of an
+exchange and what it will mean for them. Thus we want to define some metrics
+that allow a user to make more informed decisions.
+
+Similarly, the fee structure metrics might be used by exchange operators
+as a senity check.
+
+An auditor might also enforce ranges on these metrics as a condition for
+auditing a denomination structure.
+
+Requirements
+============
+
+* Privacy: A denomination structure that has too many denominations
+ will result in reduced anonymity.
+* Efficiency: A denomination structure that has too few denominations
+ is inefficient.
+* Predictability:
+
+ * The amount of fees for an operation should not come
+ as a total surprise for the user.
+
+ * The user should know beforehand when they have to be online
+ to refresh their balance, and they should know how much
+ this will cost them.
+
+The metrics for the exchange should be advisory, i.e. an informed user should
+be able to accept the withdrawal anyway.
+
+The exchange's business interests may be in conflict with (1) a transparency of
+cost for the user and and (2) restrictions on denomination/fee structures.
+Thus the metrics should still allow some degree of variability between
+exchanges.
+
+We make the assumption that wallet always perfer operations with better
+privacy. For example, a single coin should only be used for at most one
+spend operation and at most one refresh operation.
+
+Proposed Solution
+=================
+
+The following yes/no criteria are applied to determine if a denomination/fee structure
+is *reasonable*:
+
+* For a denomination of value ``v``, either
+
+ (a) ``v`` must be the the smallest offered denomination, or
+ (b) there must be another denomination with a value of at least ``v / 10``.
+
+Is there a relationship between the smallest denomination and the size of fees?
+
+Idea: When when only doing spends on a coin that are a multiple of the smallest spending amount,
+we constrain the number of coins that are refreshed into.
+
+When evaluating the e2e cost of a denomiation, look at:
+ * the cost of withdrawing the coin by itself and spending it fully, directly
+ * the cost of withdrawing the coin, directly refreshing it into the next smallest
+ fully fitting currency (or use greedy fit!) and add up the withdraw, refresh and re-withdraw fees.
+ * percentage is always computed with sum against the full coin's value
+ * smallest coins are an exception
+
+Actually, smallest spendable amount should be a multiple of the smallest coins, since
+we still need to deal with fees even at that level
+
+
+Refund fees should not be higher than if the user got a refund through
+a different channel than Taler and then purchased the product again.
+
+
+
+The following metrics are also defined:
+
+* Shortest time from withdrawal expiration to deposit expiration.
+* Upkeep, i.e. how much does it cost the customer to keep coins in their wallet
+ per time period, on average over a long period.
+* Assurance period, i.e. the time span for which the exchange has already announced
+ its fees.
+* Spending amount range.
+* End-to-end fee range. This is the minimum/maximum cost to withdraw electronic cash
+ (within the spending range), spend some of it and then obtain change for the transaction.
+* Merchant contribution range. This is the percentage of the end-to-end fees that the merchant
+ can cover if they choose to do so.
+
+
+Alternatives
+============
+
+* Users can manually study the fee structure.
+* The auditor could impose a fee structure and not
+ allow any variability between exchanges
+
+Drawbacks
+=========
+
+* The approach does not work well in some special-purpose deployments,
+ where the coin structure is taylored to the products of merchants,
+ and refreshing would never even happen.
+
+* The approach also does not consider more "creative" fee structures,
+ such as ones where coins that are valid for a longer time have higher
+ fees.
+
+Discussion / Q&A
+================
diff --git a/design-documents/index.rst b/design-documents/index.rst
index 37f81bd4..fda8b2e5 100644
--- a/design-documents/index.rst
+++ b/design-documents/index.rst
@@ -16,3 +16,4 @@ and protocol.
004-wallet-withdrawal-flow
005-wallet-backup-sync
006-anastasis-ux
+ 007-payment