summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README18
-rw-r--r--conf.py11
-rw-r--r--core/api-bank-access.rst62
-rw-r--r--core/api-common.rst112
-rw-r--r--core/api-exchange.rst559
-rw-r--r--core/api-merchant.rst57
-rw-r--r--core/wireformats.rst2
-rw-r--r--design-documents/006-extensions.rst56
-rw-r--r--design-documents/010-exchange-helpers.rst6
-rw-r--r--design-documents/011-auditor-db-sync.rst8
-rw-r--r--design-documents/012-fee-schedule-metrics.rst2
-rw-r--r--design-documents/013-peer-to-peer-payments.rst35
-rw-r--r--design-documents/024-age-restriction.rst159
-rw-r--r--design-documents/026-refund-fees.rst61
-rw-r--r--design-documents/027-sandboxing-taler.rst165
-rw-r--r--design-documents/028-proof-of-escrow.rst128
-rw-r--r--design-documents/_svgs/escrow-flow.svg1
-rw-r--r--design-documents/index.rst3
-rw-r--r--frags/list-of-dependencies.rst4
-rw-r--r--libeufin/api-sandbox.rst6
-rw-r--r--libeufin/ebics.rst5
-rw-r--r--libeufin/index.rst1
-rw-r--r--libeufin/int-deployment-gv.rst71
-rw-r--r--libeufin/nexus-tutorial.rst288
-rw-r--r--manpages/TDM.el50
-rw-r--r--manpages/libeufin-cli.1.rst1006
-rw-r--r--manpages/libeufin-nexus.1.rst150
-rw-r--r--manpages/libeufin-sandbox.1.rst218
-rw-r--r--manpages/sync-config.1.rst2
-rw-r--r--manpages/taler-config.1.rst2
-rw-r--r--manpages/taler-exchange-offline.1.rst26
-rw-r--r--manpages/taler-exchange-secmod-cs.1.rst76
-rw-r--r--manpages/taler-fakebank-run.1.rst2
-rw-r--r--manpages/taler.conf.5.rst59
-rw-r--r--taler-auditor-manual.rst28
-rw-r--r--taler-developer-manual.rst4
-rw-r--r--taler-exchange-manual.rst19
-rw-r--r--taler-exchange-setup-guide.rst34
-rw-r--r--taler-mcig.rst10
-rw-r--r--taler-merchant-manual.rst46
-rw-r--r--taler-nfc-guide.rst10
-rw-r--r--taler-wallet-cli-manual.rst2
42 files changed, 3186 insertions, 378 deletions
diff --git a/README b/README
index dda29a2..206d305 100644
--- a/README
+++ b/README
@@ -14,4 +14,20 @@ Then, do "make html" for HTML, "make texinfo" for Texinfo, etc.
The output is in subdir ‘_build’.
-TODO: Add instructions on how to build/export/integrate ‘prebuilt’ docs.
+Branch ‘prebuilt’ is special. Its contents (or a subset) are used as
+submodules in other Git repos (e.g., Exchange, Merchant, Sync).
+
+One approach that works well (so far) for ttn is to do
+(presuming that the current directory is named ‘docs’):
+
+ $ cd ..
+ $ git clone -b prebuilt --reference docs \
+ git+ssh://git@git.taler.net/docs.git \
+ docs-prebuilt
+
+This creates Git repo docs-prebuilt as a peer to the current repo.
+
+This way, you can build in this directory (i.e., "make man" or whatever)
+and then copy to ../docs-prebuilt/man/* what files need to be updated.
+In that repo, you can commit changes and push to git.taler.net as normal,
+all without having to do "git checkout" in either repo.
diff --git a/conf.py b/conf.py
index 60f3396..fe18061 100644
--- a/conf.py
+++ b/conf.py
@@ -282,7 +282,7 @@ man_pages = [
("manpages/sync-httpd.1", "sync-httpd",
"provide the Sync HTTP interface", "GNU Taler contributors", 1),
("manpages/sync.conf.5", "sync.conf",
- "Sync configuration file", "GNU Taler contributors", 1),
+ "Sync configuration file", "GNU Taler contributors", 5),
("manpages/taler-auditor-exchange.1", "taler-auditor-exchange",
"add or remove exchange from auditor’s list", "GNU Taler contributors",
1),
@@ -338,6 +338,9 @@ man_pages = [
("manpages/taler-exchange-secmod-eddsa.1", "taler-exchange-secmod-eddsa",
"handle private EDDSA key operations for a Taler exchange",
"GNU Taler contributors", 1),
+ ("manpages/taler-exchange-secmod-cs.1", "taler-exchange-secmod-cs",
+ "handle private CS key operations for a Taler exchange",
+ "GNU Taler contributors", 1),
("manpages/taler-exchange-secmod-rsa.1", "taler-exchange-secmod-rsa",
"handle private RSA key operations for a Taler exchange",
"GNU Taler contributors", 1),
@@ -353,6 +356,12 @@ man_pages = [
("manpages/taler-helper-auditor-wire.1", "taler-helper-auditor-wire",
"audit exchange database for consistency with the bank's wire transfers",
"GNU Taler contributors", 1),
+ ("manpages/libeufin-sandbox.1", "libeufin-sandbox",
+ "simulate core banking system with EBICS access to bank accounts",
+ "GNU Taler contributors", 1),
+ ("manpages/libeufin-nexus.1", "libeufin-nexus",
+ "sevice to interface to various bank access APIs",
+ "GNU Taler contributors", 1),
]
# If true, show URL addresses after external links.
diff --git a/core/api-bank-access.rst b/core/api-bank-access.rst
index 343b319..0d1450a 100644
--- a/core/api-bank-access.rst
+++ b/core/api-bank-access.rst
@@ -30,6 +30,29 @@ to enabling wallets to withdraw with a better user experience ("tight integratio
Accounts and Withdrawals
------------------------
+.. http:get:: ${BANK_API_BASE_URL}/public-accounts
+
+ Show those accounts whose histories are publicly visible. For example,
+ accounts from donation receivers. As such, this request is unauthenticated.
+
+ **Response**
+
+ **Details**
+
+ .. ts:def:: PublicAccountsResponse
+
+ interface PublicAccountsResponse {
+ publicAccounts: PublicAccount[]
+ }
+
+ interface PublicAccount {
+ iban: string;
+ balance: string;
+ // The account name _and_ the username of the
+ // Sandbox customer that owns such a bank account.
+ accountLabel: string;
+ }
+
The following endpoints require HTTP "Basic" authentication with the account
name and account password, at least in the GNU Taler demo bank implementation.
@@ -146,13 +169,13 @@ Transactions
.. http:GET:: ${BANK_API_BASE_URL}/accounts/${account_name}/transactions
- Retrieve all the fresh transactions where the bank account with the
- label ``account_name`` was debited or credited. A transactions is 'fresh'
- if it was never included in a "history" type response.
+ Retrieve a subset of transactions related to $account_name. Without
+ query parameters, it returns the last 5 transactions.
**Request**
- FIXME: this needs query parameters to filter the results.
+ :query page: page number (defaults to 1, meaning the page with the latest transactions.)
+ :query size: how many transactions per page, defaults to 5.
**Response**
@@ -174,29 +197,22 @@ Transactions
interface BankAccountTransactionInfo {
creditorIban: string;
- creditorBic: string;
+ creditorBic: string; // Optional
creditorName: string;
-
- // Temporary. Payto address to let the wallet tests that
- // use x-taler-bank still function. This information
- // should flow through the TWG in the exchange's incoming
- // history.
- creditorXTalerBank: string;
debtorIban: string;
debtorBic: string;
debtorName: string;
- // Same as creditor's.
- debtorXTalerBank: string;
-
amount: number;
currency: string;
subject: string;
- date: string; // YYYY-MM-DD
- uid: string; // transaction (unique) ID
+ // Transaction unique ID. Matches
+ // $transaction_id from the URI.
+ uid: string;
direction: "DBIT" | "CRDT";
+ date: string; // YYYY-MM-DD ending with 'Z'
}
@@ -209,13 +225,16 @@ Transactions
.. ts:def:: BankAccountTransactionCreate
interface CreateBankAccountTransactionCreate {
- // Note: the authority value ('iban' or 'x-taler-bank')
- // depends on the particular service that offers the Access API.
- // euFin offers only 'iban' and the PyBank only 'x-taler-bank'.
+
+ // Address in the Payto format of the wire transfer receiver.
+ // It needs at least the 'message' query string parameter.
paytoUri: string;
- amount: string; // with currency
- subject: string;
+ // Transaction amount (in the $currency:x.y format), optional.
+ // However, when not given, its value must occupy the 'amount'
+ // query string parameter of the 'payto' field. In case it
+ // is given in both places, the paytoUri's takes the precedence.
+ amount: string;
}
**Response**
@@ -230,7 +249,6 @@ Transactions
Registration (Testing)
----------------------
-
.. http:POST:: ${BANK_API_BASE_URL}/testing/register
Create a new bank account. This endpoint should be disabled for most deployments, but is useful
diff --git a/core/api-common.rst b/core/api-common.rst
index 6b0f792..b32a788 100644
--- a/core/api-common.rst
+++ b/core/api-common.rst
@@ -235,6 +235,27 @@ hashed data. See `base32`_.
type SHA512HashCode = HashCode;
+.. ts:def:: CSNonce
+
+ // 32-byte nonce value, must only be used once.
+ type CSNonce = string;
+
+.. ts:def:: RefreshMasterSeed
+
+ // 32-byte nonce value, must only be used once.
+ type RefreshMasterSeed = string;
+
+.. ts:def:: Cs25519Point
+
+ // 32-byte value representing a point on Curve25519.
+ type Cs25519Point = string;
+
+.. ts:def:: Cs25519Scalar
+
+ // 32-byte value representing a scalar multiplier
+ // for scalar operations on points on Curve25519.
+ type Cs25519Scalar = string;
+
Safe Integers
^^^^^^^^^^^^^
@@ -262,18 +283,19 @@ Timestamps are represented by the following structure:
.. ts:def:: Timestamp
interface Timestamp {
- // Milliseconds since epoch, or the special
+ // Seconds since epoch, or the special
// value "never" to represent an event that will
// never happen.
- t_ms: number | "never";
+ t_s: number | "never";
}
.. ts:def:: RelativeTime
interface Duration {
- // Duration in milliseconds or "forever"
- // to represent an infinite duration.
- d_ms: number | "forever";
+ // Duration in microseconds or "forever"
+ // to represent an infinite duration. Numeric
+ // values are capped at 2^53 - 1 inclusive.
+ d_us: number | "forever";
}
@@ -349,6 +371,20 @@ Keys
// converted to Crockford `Base32`.
type EddsaPrivateKey = string;
+.. ts:def:: Edx25519PublicKey
+
+ // Edx25519 public keys are points on Curve25519 and represented using the
+ // standard 256 bits Ed25519 compact format converted to Crockford
+ // `Base32`.
+ type Edx25519PublicKey = string;
+
+.. ts:def:: Edx25519PrivateKey
+
+ // Edx25519 private keys are always points on Curve25519
+ // and represented using the standard 256 bits Ed25519 compact format,
+ // converted to Crockford `Base32`.
+ type Edx25519PrivateKey = string;
+
.. ts:def:: EcdhePublicKey
// EdDSA and ECDHE public keys always point on Curve25519
@@ -356,6 +392,12 @@ Keys
// converted to Crockford `Base32`.
type EcdhePublicKey = string;
+.. ts:def:: CsRPublic
+
+ // Point on Curve25519 represented using the standard 256 bits Ed25519 compact format,
+ // converted to Crockford `Base32`.
+ type CsRPublic = string;
+
.. ts:def:: EcdhePrivateKey
// EdDSA and ECDHE public keys always point on Curve25519
@@ -403,6 +445,12 @@ Signatures
// binary-encoded objects with just the R and S values (base32_ binary-only).
type EddsaSignature = string;
+.. ts:def:: Edx25519Signature
+
+ // Edx25519 signatures are transmitted as 64-bytes `base32`
+ // binary-encoded objects with just the R and S values (base32_ binary-only).
+ type Edx25519Signature = string;
+
.. ts:def:: RsaSignature
// `base32` encoded RSA signature.
@@ -578,10 +626,11 @@ uses 512-bit hash codes (64 bytes).
struct GNUNET_HashCode hash;
};
+.. _PaytoHash:
.. sourcecode:: c
struct TALER_PaytoHash {
- struct GNUNET_HashCode hash;
+ struct GNUNET_ShortHashCode hash;
};
.. sourcecode:: c
@@ -830,7 +879,6 @@ within the
struct TALER_DenominationHash h_denom_pub;
struct TALER_AmountNBO amount_with_fee;
struct TALER_AmountNBO melt_fee;
- union TALER_CoinSpendPublicKeyP coin_pub;
};
.. _TALER_RefreshMeltConfirmationPS:
@@ -1061,7 +1109,6 @@ within the
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
struct TALER_PrivateContractHash h_contract_terms;
union TALER_CoinSpendPublicKeyP coin_pub;
- struct TALER_MerchantPublicKeyP merchant;
uint64_t rtransaction_id;
struct TALER_AmountNBO refund_amount;
struct TALER_AmountNBO refund_fee;
@@ -1088,9 +1135,9 @@ within the
struct TALER_RecoupRequestPS {
/**
* purpose.purpose = TALER_SIGNATURE_WALLET_COIN_RECOUP
+ * or TALER_SIGNATURE_WALLET_COIN_RECOUP_REFRESH
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- union TALER_CoinSpendPublicKeyP coin_pub;
struct TALER_DenominationHash h_denom_pub;
struct TALER_DenominationBlindingKeyP coin_blind;
};
@@ -1106,7 +1153,7 @@ within the
struct GNUNET_TIME_AbsoluteNBO timestamp;
struct TALER_AmountNBO recoup_amount;
union TALER_CoinSpendPublicKeyP coin_pub;
- struct TALER_CoinSpendPublicKeyP old_coin_pub;
+ union TALER_CoinSpendPublicKeyP old_coin_pub;
};
.. _TALER_RecoupConfirmationPS:
@@ -1180,8 +1227,6 @@ within the
};
-
-
.. _TALER_ReserveStatusRequestSignaturePS:
.. sourcecode:: c
@@ -1240,7 +1285,7 @@ within the
struct TALER_ReserveCloseRequestSignaturePS {
/**
- * purpose.purpose = TALER_SIGNATURE_RESERVE_CLOSE
+ * purpose.purpose = TALER_SIGNATURE_WALLET_RESERVE_CLOSE
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
};
@@ -1258,12 +1303,13 @@ within the
struct TALER_PurseRequestSignaturePS {
/**
- * purpose.purpose = TALER_SIGNATURE_PURSE_REQUEST
+ * purpose.purpose = TALER_SIGNATURE_WALLET_PURSE_CREATE
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
struct GNUNET_TIME_AbsoluteNBO purse_expiration;
struct TALER_AmountNBO merge_value_after_fees;
- struct TALER_PrivateContractHash h_contract_terms;
+ struct TALER_PrivateContractHashP h_contract_terms;
+ uint32_t min_age;
};
@@ -1276,9 +1322,7 @@ within the
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
struct TALER_AmountNBO coin_contribution;
- struct GNUNET_TIME_AbsoluteNBO purse_expiration;
- struct TALER_PursePublicKey purse_pub;
- struct TALER_PrivateContractHash h_contract_terms;
+ struct TALER_PursePublicKeyP purse_pub;
};
@@ -1292,9 +1336,9 @@ within the
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
struct TALER_AmountNBO total_purse_amount;
struct TALER_AmountNBO total_deposit_fees;
- struct TALER_PursePublicKey purse_pub;
+ struct TALER_PursePublicKeyP purse_pub;
struct GNUNET_TIME_AbsoluteNBO purse_expiration;
- struct TALER_PrivateContractHash h_contract_terms;
+ struct TALER_PrivateContractHashP h_contract_terms;
};
.. _TALER_PurseMergeSignaturePS:
@@ -1302,15 +1346,11 @@ within the
struct TALER_PurseMergeSignaturePS {
/**
- * purpose.purpose = TALER_SIGNATURE_PURSE_MERGE
+ * purpose.purpose = TALER_SIGNATURE_WALLET_PURSE_MERGE
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct TALER_ReservePublicKey reserve_pub;
struct GNUNET_TIME_AbsoluteNBO merge_timestamp;
- struct GNUNET_TIME_AbsoluteNBO purse_expiration;
- struct TALER_AmountNBO merge_value_after_fees;
- struct TALER_PrivateContractHash h_contract_terms;
- struct TALER_PaytoHash h_wire;
+ struct TALER_PaytoHashP h_wire;
};
@@ -1319,15 +1359,16 @@ within the
struct TALER_AccountMergeSignaturePS {
/**
- * purpose.purpose = TALER_SIGNATURE_ACCOUNT_MERGE
+ * purpose.purpose = TALER_SIGNATURE_WALLET_ACCOUNT_MERGE
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct TALER_PursePublicKey purse_pub;
+ struct TALER_ReservePublicKeyP reserve_pub;
+ struct TALER_PursePublicKeyP purse_pub;
+ struct TALER_AmountNBO merge_amount_after_fees;
struct GNUNET_TIME_AbsoluteNBO merge_timestamp;
struct GNUNET_TIME_AbsoluteNBO purse_expiration;
- struct TALER_AmountNBO merge_value_after_fees;
- struct TALER_PrivateContractHash h_contract_terms;
- struct TALER_PaytoHash h_wire;
+ struct TALER_PrivateContractHashP h_contract_terms;
+ uint32_t min_age;
};
@@ -1339,12 +1380,13 @@ within the
* purpose.purpose = TALER_SIGNATURE_PURSE_MERGE_SUCCESS
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct TALER_ReservePublicKey reserve_pub;
- struct TALER_PursePublicKey purse_pub;
+ struct TALER_ReservePublicKeyP reserve_pub;
+ struct TALER_PursePublicKeyP purse_pub;
struct TALER_AmountNBO merge_amount_after_fees;
struct GNUNET_TIME_AbsoluteNBO contract_time;
- struct TALER_PrivateContractHash h_contract_terms;
- struct TALER_PaytoHash h_wire;
+ struct TALER_PrivateContractHashP h_contract_terms;
+ struct TALER_PaytoHashP h_wire;
+ uint32_t min_age;
};
diff --git a/core/api-exchange.rst b/core/api-exchange.rst
index 2638604..b55fb6b 100644
--- a/core/api-exchange.rst
+++ b/core/api-exchange.rst
@@ -1,6 +1,6 @@
..
This file is part of GNU TALER.
- Copyright (C) 2014-2021 Taler Systems SA
+ Copyright (C) 2014-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software
@@ -143,10 +143,8 @@ possibly by using HTTPS.
// Denominations for which the exchange currently offers/requests recoup.
recoup: Recoup[];
- // Fees relevant for wallet-to-wallet (or peer-to-peer) payments.
- // If no fees are provided for a given time range, then the
- // exchange simply does not support purses/p2p-payments at that time.
- p2p_fees: P2PFees[];
+ // Array of globally applicable fees by time range.
+ global_fees: GlobalFees[];
// The date when the denomination keys were last updated.
list_issue_date: Timestamp;
@@ -176,13 +174,9 @@ possibly by using HTTPS.
eddsa_pub: EddsaPublicKey;
}
- .. ts:def:: P2PFees
+ .. ts:def:: GlobalFees
- .. note::
-
- This is a draft API that is not yet implemented.
-
- interface P2PFees {
+ interface GlobalFees {
// What date (inclusive) does these fees go into effect?
start_date: Timestamp;
@@ -196,9 +190,8 @@ possibly by using HTTPS.
kyc_fee: Amount;
// Account history fee, charged when a user wants to
- // obtain the full account history, and not just the
- // recent transactions in an account.
- account_history_fee: Amount;
+ // obtain a reserve/account history.
+ history_fee: Amount;
// Annual fee charged for having an open account at the
// exchange. Charged to the account. If the account
@@ -206,12 +199,16 @@ possibly by using HTTPS.
// is automatically deleted/closed. (Note that the exchange
// will keep the account history around for longer for
// regulatory reasons.)
- account_annual_fee: Amount;
+ account_fee: Amount;
+
+ // Purse fee, charged only if a purse is abandoned
+ // and was not covered by the account limit.
+ purse_fee: Amount;
// How long will the exchange preserve the account history?
// After an account was deleted/closed, the exchange will
// retain the account history for legal reasons until this time.
- legal_history_retention: RelativeTime;
+ history_expiration: RelativeTime;
// How long does the exchange promise to keep funds
// an account for which the KYC has never happened
@@ -220,10 +217,6 @@ possibly by using HTTPS.
// forfeit.
account_kyc_timeout: RelativeTime;
- // Purse fee, charged only if a purse is abandoned
- // and was not covered by the account limit.
- purse_fee: Amount;
-
// Non-negative number of concurrent purses that any
// account holder is allowed to create without having
// to pay the purse_fee.
@@ -235,7 +228,7 @@ possibly by using HTTPS.
// plus this value.
purse_timeout: RelativeTime;
- // Signature of `TALER_P2PFeesPS`.
+ // Signature of `TALER_GlobalFeesPS`.
master_sig: EddsaSignature;
}
@@ -303,7 +296,8 @@ possibly by using HTTPS.
// 32-bit age mask.
age_mask: Integer;
- // FIXME: tbd
+ // Public key of the denomination.
+ cs_public_key: Cs25519Point;
}
@@ -421,7 +415,7 @@ possibly by using HTTPS.
// incoming wire transfers.
accounts: WireAccount[];
- // Object mapping names of wire methods (i.e. "sepa" or "x-taler-bank")
+ // Object mapping names of wire methods (i.e. "iban" or "x-taler-bank")
// to wire fees.
fees: { method : AggregateTransferFee };
@@ -458,6 +452,9 @@ possibly by using HTTPS.
// Per transfer closing fee.
closing_fee: Amount;
+ // Per exchange-to-exchange transfer (wad) fee.
+ wad_fee: Amount;
+
// What date (inclusive) does this fee go into effect?
// The different fees must cover the full time period in which
// any of the denomination keys are valid without overlap.
@@ -482,9 +479,6 @@ possibly by using HTTPS.
// Public master key of the partner exchange.
partner_master_pub: EddsaPublicKey;
- // Wallet-to-wallet transfer wad fee charged.
- wad_fee: Amount;
-
// Exchange-to-exchange wad (wire) transfer frequency.
wad_frequency: RelativeTime;
@@ -866,8 +860,28 @@ Management operations authorized by master key
// Wire fee to charge during that time period for this wire method.
wire_fee: Amount;
+ // Wad fee to charge during that time period for this wire method.
+ wad_fee: Amount;
+
}
+.. http:post:: /management/global-fees
+
+ Provides global fee configuration for a timeframe.
+
+ **Request:**
+
+ The request must be a `GlobalFees` message.
+
+ **Response**
+
+ :http:statuscode:`204 No content`:
+ The configuration update has been processed successfully. The body is empty.
+ :http:statuscode:`403 Forbidden`:
+ The signature is invalid.
+ :http:statuscode:`409 Conflict`:
+ The exchange has previously received a conflicting configuration message.
+
.. http:post:: /management/wire
@@ -964,27 +978,6 @@ Management operations authorized by master key
}
-.. http:post:: /management/p2pfees
-
- Provides fee configuration for purses.
-
- .. note::
-
- This is a draft API that is not yet implemented.
-
- **Request:**
-
- The request must be a `P2PFees` message.
-
- **Response**
-
- :http:statuscode:`204 No content`:
- The configuration update has been processed successfully. The body is empty.
- :http:statuscode:`403 Forbidden`:
- The signature is invalid.
- :http:statuscode:`409 Conflict`:
- The exchange has previously received a conflicting configuration message.
-
.. http:post:: /management/partners
@@ -1104,19 +1097,37 @@ exchange.
advertise those terms of service.
+.. http:get:: /reserves/$RESERVE_PUB
+
+ Request information about a reserve.
+
+ **Request:**
+
+ :query timeout_ms=MILLISECONDS: *Optional.* If specified, the exchange will wait up to MILLISECONDS for incoming funds before returning a 404 if the reserve does not yet exist.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The exchange responds with a `ReserveSummary` object; the reserve was known to the exchange.
+ :http:statuscode:`404 Not found`:
+ The reserve key does not belong to a reserve known to the exchange.
+
+ **Details:**
+
+ .. ts:def:: ReserveSummary
+
+ interface ReserveSummary {
+ // Balance left in the reserve.
+ balance: Amount;
+ }
+
+
.. http:post:: /reserves/$RESERVE_PUB/status
Request information about a reserve or an account.
**Request:**
- :query history=BOOLEAN: *Optional.* If specified, the exchange
- will return the recent account history.
- This is still free of charge.
- :query full_history=BOOLEAN: *Optional.* If 'true' is specified,
- the exchange will return the full account history. This
- may incur a fee that will be charged to the account.
-
The request body must be a `ReserveStatusRequest` object.
**Response:**
@@ -1124,7 +1135,7 @@ exchange.
:http:statuscode:`200 OK`:
The exchange responds with a `ReserveStatus` object; the reserve was known to the exchange.
:http:statuscode:`401 Unauthorized`:
- The *Account-Request-Signature* is invalid.
+ The *TALER_SIGNATURE_RESERVE_STATUS_REQUEST* signature is invalid.
This response comes with a standard `ErrorDetail` response.
:http:statuscode:`403 Forbidden`:
The provided timestamp is not close to the current time.
@@ -1219,7 +1230,7 @@ exchange.
// Signature created with the reserve's private key.
// Must be of purpose ``TALER_SIGNATURE_ACCOUNT_SETUP_REQUEST`` over
- // a `TALER_AccountSetupRequestSignaturePS`.
+ // a ``TALER_AccountSetupRequestSignaturePS``.
reserve_sig: EddsaSignature;
}
@@ -1377,7 +1388,7 @@ exchange.
:http:statuscode:`200 OK`:
The exchange responds with a `ReserveStatus` object; the reserve was known to the exchange.
:http:statuscode:`401 Unauthorized`:
- The *Account-Request-Signature* is invalid.
+ The *TALER_SIGNATURE_RESERVE_HISTORY_REQUEST* is invalid.
This response comes with a standard `ErrorDetail` response.
:http:statuscode:`403 Forbidden`:
The provided timestamp is not close to the current time.
@@ -1405,6 +1416,75 @@ exchange.
}
+.. http:post:: /csr-withdraw
+
+ Obtain exchange-side input values in preparation for a
+ withdraw step for certain denomination cipher types,
+ specifically at this point for Clause-Schnorr blind
+ signatures.
+
+ **Request:** The request body must be a `WithdrawPrepareRequest` object.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The request was successful, and the response is a `WithdrawPrepareResponse`. Note that repeating exactly the same request
+ will again yield the same response (assuming none of the denomination is expired).
+ :http:statuscode:`404 Not found`:
+ The denomination key is not known to the exchange.
+ :http:statuscode:`410 Gone`:
+ The requested denomination key is not yet or no longer valid.
+ It either before the validity start, past the expiration or was revoked. The response is a
+ `DenominationExpiredMessage`. Clients must evaluate
+ the error code provided to understand which of the
+ cases this is and handle it accordingly.
+
+ **Details:**
+
+ .. ts:def:: WithdrawPrepareRequest
+
+ interface WithdrawPrepareRequest {
+
+ // Nonce to be used by the exchange to derive
+ // its private inputs from. Must not have ever
+ // been used before.
+ nonce: CSNonce;
+
+ // Hash of the public key of the denomination the
+ // request relates to.
+ denom_pub_hash: Hash;
+
+ }
+
+ .. ts:def:: WithdrawPrepareResponse
+
+ type WithdrawPrepareResponse
+ | ExchangeWithdrawValue;
+
+ .. ts:def:: ExchangeWithdrawValue
+
+ type ExchangeWithdrawValue =
+ | ExchangeRsaWithdrawValue
+ | ExchangeCsWithdrawValue;
+
+ .. ts:def:: ExchangeRsaWithdrawValue
+
+ interface ExchangeRsaWithdrawValue {
+ cipher: "RSA";
+ }
+
+ .. ts:def:: ExchangeCsWithdrawValue
+
+ interface ExchangeCsWithdrawValue {
+ cipher: "CS";
+
+ // CSR R0 value
+ r_pub_0: CsRPublic;
+
+ // CSR R1 value
+ r_pub_1: CsRPublic;
+ }
+
.. http:post:: /reserves/$RESERVE_PUB/withdraw
Withdraw a coin of the specified denomination. Note that the client should
@@ -1543,7 +1623,13 @@ exchange.
interface CSBlindedDenominationSignature {
type: "CS";
- // FIXME: tbd
+ // Signer chosen bit value, 0 or 1, used
+ // in Clause Blind Schnorr to make the
+ // ROS problem harder.
+ b: Integer;
+
+ // Blinded scalar calculated from c_b.
+ s: Cs25519Scalar;
}
@@ -1719,7 +1805,8 @@ denomination.
timestamp: Timestamp;
// Indicative time by which the exchange undertakes to transfer the funds to
- // the merchant, in case of successful payment.
+ // the merchant, in case of successful payment. A wire transfer deadline of 'never'
+ // is not allowed.
wire_transfer_deadline: Timestamp;
// EdDSA `public key of the merchant <merchant-pub>`, so that the client can identify the
@@ -1750,12 +1837,16 @@ denomination.
rsa_signature: RsaSignature;
}
- .. ts:def:: CSBDenominationSignature
+ .. ts:def:: CSDenominationSignature
- interface CSBDenominationSignature {
+ interface CSDenominationSignature {
type: "CS";
- // FIXME: tbd
+ // R value component of the signature.
+ cs_signature_r: Cs25519Point;
+
+ // s value component of the signature.
+ cs_signature_s: Cs25519Scalar:
}
@@ -2113,6 +2204,73 @@ using the ``/refresh/link`` request. While ``/refresh/link`` must be implemente
the exchange to achieve taxability, wallets do not really ever need that part of
the API during normal operation.
+
+.. http:post:: /csr-melt
+
+ Obtain exchange-side input values in preparation for a
+ melt step for certain denomination cipher types,
+ specifically at this point for Clause-Schnorr blind
+ signatures.
+
+ **Request:** The request body must be a `MeltPrepareRequest` object.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The request was successful, and the response is a `MeltPrepareResponse`. Note that repeating exactly the same request
+ will again yield the same response (assuming none of the denomination is expired).
+ :http:statuscode:`404 Not found`:
+ A denomination key is not known to the exchange.
+ :http:statuscode:`410 Gone`:
+ A requested denomination key is not yet or no longer valid.
+ It either before the validity start, past the expiration or was revoked. The response is a
+ `DenominationExpiredMessage`. Clients must evaluate
+ the error code provided to understand which of the
+ cases this is and handle it accordingly.
+
+ **Details:**
+
+ .. ts:def:: MeltPrepareRequest
+
+ interface WithdrawPrepareRequest {
+
+ // Master seed for the Clause-schnorr R-value
+ // creation.
+ // Must not have been used in any prior request.
+ rms: RefreshMasterSeed;
+
+ // Array of denominations and coin offsets for
+ // each of the fresh coins with a CS-cipher
+ // denomination.
+ nks: MeltPrepareDenomNonce[];
+
+ }
+
+ .. ts:def:: MeltPrepareDenomNonce
+
+ interface MeltPrepareDenomNonce {
+
+ // Offset of this coin in the list of
+ // fresh coins. May not match the array offset
+ // as the fresh coins may include non-CS
+ // denominations as well.
+ coin_offset: Integer;
+
+ // Hash of the public key of the denomination the
+ // request relates to. Must be a CS denomination type.
+ denom_pub_hash: Hash;
+ }
+
+
+ .. ts:def:: MeltPrepareResponse
+
+ interface MeltPrepareResponse {
+ // Responses for each request, in the same
+ // order that was used in the request.
+ ewvs: ExchangeWithdrawValue[];
+ }
+
+
.. _refresh:
.. http:post:: /coins/$COIN_PUB/melt
@@ -2173,6 +2331,13 @@ the API during normal operation.
// See also ``TALER_refresh_get_commitment()``.
rc: TALER_RefreshCommitmentP;
+ // Master seed for the Clause-schnorr R-value
+ // creation. Must match the /csr-melt request.
+ // Must not have been used in any prior melt request.
+ // Must be present if one of the fresh coin's
+ // denominations is of type Clause-Schnorr.
+ rms?: RefreshMasterSeed;
+
}
For details about the HKDF used to derive the new coin private keys and
@@ -2223,18 +2388,6 @@ the API during normal operation.
// Detailed error code.
code: Integer;
- // Public key of a melted coin that had insufficient funds.
- coin_pub: EddsaPublicKey;
-
- // Original total value of the coin.
- original_value: Amount;
-
- // Remaining value of the coin.
- residual_value: Amount;
-
- // Amount of the coin's value that was to be melted.
- requested_value: Amount;
-
// The transaction list of the respective coin that failed to have sufficient funds left.
// Note that only the transaction history for one bogus coin is given,
// even if multiple coins would have failed the check.
@@ -2342,9 +2495,7 @@ the API during normal operation.
**Response:**
:http:statuscode:`200 OK`:
- All commitments were revealed successfully. The exchange returns an array,
- typically consisting of only one element, in which each each element contains
- information about a melting session that the coin was used in.
+ All commitments were revealed successfully. The exchange returns an array (typically consisting of only one element), in which each each element of the array contains a `LinkResponse` entry with information about a melting session that the coin was used in.
:http:statuscode:`404 Not found`:
The exchange has no linkage data for the given public key, as the coin has not
yet been involved in a refresh operation.
@@ -2375,6 +2526,14 @@ the API during normal operation.
// Blinded coin.
coin_ev : CoinEnvelope;
+ // Values contributed by the exchange during the
+ // withdraw operation (see /csr-melt).
+ ewv: ExchangeWithdrawValue;
+
+ // Offset of this coin in the refresh operation.
+ // Input needed to derive the private key.
+ coin_idx: Integer;
+
// Signature made by the old coin over the refresh request.
// Signs over a `TALER_CoinLinkSignaturePS`.
link_sig: EddsaSignature;
@@ -2404,11 +2563,10 @@ in using this API.
exchange. The exchange MUST return a 307 or 308 redirection to the correct
base URL if this is the case.
- Depending whether ``$COIN_PUB`` is a withdrawn coin or a refreshed coin,
- the remaining amount on the coin will be credited either on the reserve or
- the old coin that ``$COIN_PUB`` was withdrawn/refreshed from.
+ The remaining amount on the coin will be credited to the reserve
+ that ``$COIN_PUB`` was withdrawn from.
- Note that the original withdrawal/refresh fees will **not** be recouped.
+ Note that the original withdrawal fees will **not** be recouped.
**Request:** The request body must be a `RecoupRequest` object.
@@ -2416,7 +2574,7 @@ in using this API.
**Response:**
:http:statuscode:`200 OK`:
- The request was successful, and the response is a `RecoupConfirmation`.
+ The request was successful, and the response is a `RecoupWithdrawalConfirmation`.
Note that repeating exactly the same request
will again yield the same response, so if the network goes down during the
transaction or before the client can commit the coin signature to disk, the
@@ -2433,8 +2591,7 @@ in using this API.
residual value, or because the same public key of the coin has been
previously used with a different denomination. Which case it is
can be decided by looking at the error code
- (``TALER_EC_EXCHANGE_RECOUP_COIN_BALANCE_ZERO`` or
- ``TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY``).
+ (usually ``TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS``).
The response is a `DepositDoubleSpendError`.
:http:statuscode:`410 Gone`:
The requested denomination key is not yet or no longer valid.
@@ -2448,49 +2605,109 @@ in using this API.
.. ts:def:: RecoupRequest
interface RecoupRequest {
- // Hash of denomination public key (RSA), specifying the type of coin the client
+ // Hash of denomination public key, specifying the type of coin the client
// would like the exchange to pay back.
denom_pub_hash: HashCode;
// Signature over the `coin public key <eddsa-coin-pub>` by the denomination.
denom_sig: DenominationSignature;
- // Coin's blinding factor.
- coin_blind_key_secret: DenominationBlindingKeySecret;
+ // Exchange-contributed values during the refresh
+ // operation (see /csr-withdraw).
+ ewv: ExchangeWithdrawValue;
// Signature of `TALER_RecoupRequestPS` created with
// the `coin's private key <coin-priv>`.
coin_sig: EddsaSignature;
- // Was the coin refreshed (and thus the recoup should go to the old coin)?
- // While this information is technically redundant, it helps the exchange
- // to respond faster.
- // *Optional* (for backwards compatibility); if absent, ``false`` is assumed.
- refreshed?: boolean;
- }
-
+ // Coin's blinding factor.
+ coin_blind_key_secret: DenominationBlindingKeySecret;
- .. ts:def:: RecoupConfirmation
+ }
- type RecoupConfirmation = | RecoupRefreshConfirmation
- | RecoupWithdrawalConfirmation;
.. ts:def:: RecoupWithdrawalConfirmation
interface RecoupWithdrawalConfirmation {
- // Tag to distinguish the `RecoupConfirmation` response type.
- refreshed: false;
-
// Public key of the reserve that will receive the recoup.
reserve_pub: EddsaPublicKey;
}
+
+.. http:post:: /coins/$COIN_PUB/recoup-refresh
+
+ Demand that a coin be refunded via wire transfer to the original owner.
+
+ The base URL for ``/coins/``-requests may differ from the main base URL of the
+ exchange. The exchange MUST return a 307 or 308 redirection to the correct
+ base URL if this is the case.
+
+ The remaining amount on the coin will be credited to
+ the old coin that ``$COIN_PUB`` was refreshed from.
+
+ Note that the original refresh fees will **not** be recouped.
+
+
+ **Request:** The request body must be a `RecoupRefreshRequest` object.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The request was successful, and the response is a `RecoupRefreshConfirmation`.
+ Note that repeating exactly the same request
+ will again yield the same response, so if the network goes down during the
+ transaction or before the client can commit the coin signature to disk, the
+ coin is not lost.
+ :http:statuscode:`401 Unauthorized`:
+ The coin's signature is invalid.
+ :http:statuscode:`404 Not found`:
+ The denomination key is unknown, or the blinded
+ coin is not known to have been withdrawn.
+ If the denomination key is unknown, the response will be
+ a `DenominationUnknownMessage`.
+ :http:statuscode:`409 Conflict`:
+ The operation is not allowed as the coin has insufficient
+ residual value, or because the same public key of the coin has been
+ previously used with a different denomination. Which case it is
+ can be decided by looking at the error code
+ (usually ``TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_BALANCE``).
+ The response is a `DepositDoubleSpendError`.
+ :http:statuscode:`410 Gone`:
+ The requested denomination key is not yet or no longer valid.
+ It either before the validity start, past the expiration or was not yet revoked. The response is a
+ `DenominationExpiredMessage`. Clients must evaluate
+ the error code provided to understand which of the
+ cases this is and handle it accordingly.
+
+ **Details:**
+
+ .. ts:def:: RecoupRefreshRequest
+
+ interface RecoupRefreshRequest {
+ // Hash of denomination public key, specifying the type of coin the client
+ // would like the exchange to pay back.
+ denom_pub_hash: HashCode;
+
+ // Signature over the `coin public key <eddsa-coin-pub>` by the denomination.
+ denom_sig: DenominationSignature;
+
+ // Exchange-contributed values during the refresh
+ // operation (see /csr-melt).
+ ewv: ExchangeWithdrawValue;
+
+ // Signature of `TALER_RecoupRefreshRequestPS` created with
+ // the `coin's private key <coin-priv>`.
+ coin_sig: EddsaSignature;
+
+ // Coin's blinding factor.
+ coin_blind_key_secret: DenominationBlindingKeySecret;
+
+ }
+
+
.. ts:def:: RecoupRefreshConfirmation
interface RecoupRefreshConfirmation {
- // Tag to distinguish the `RecoupConfirmation` response type.
- refreshed: true;
-
// Public key of the old coin that will receive the recoup.
old_coin_pub: EddsaPublicKey;
}
@@ -2783,6 +3000,7 @@ Wallet-to-wallet transfers
Obtain information about a purse. The request header must
contain a *Purse-Request-Signature*. Endpoint used by
the party that did not create the purse.
+ TODO: maybe use POST to /purses/$PURSE_PUB/status instead?
**Request:**
@@ -2790,11 +3008,11 @@ Wallet-to-wallet transfers
:query merge_timeout_ms=NUMBER: *Optional.* If specified,
the exchange
- will wait up to ``timeout_ms`` milliseconds for completion
+ will wait up to ``NUMBER`` milliseconds for completion
of a merge operation before sending the HTTP response.
:query deposit_timeout_ms=NUMBER: *Optional.* If specified,
the exchange
- will wait up to ``timeout_ms`` milliseconds for completion
+ will wait up to ``NUMBER`` milliseconds for completion
of a deposit operation before sending the HTTP response.
:query contract=BOOLEAN: *Optional.* If 'false' is specified,
the exchange will not return the encrypted contract, saving
@@ -2853,6 +3071,9 @@ Wallet-to-wallet transfers
// EdDSA public key exchange used for 'exchange_sig'.
exchange_pub: EddsaPublicKey;
+ // EdDSA public key used to approve merges of this purse.
+ merge_pub: EddsaPublicKey;
+
// AES-GCM Encrypted contract terms using encryption
// key derived from DH of 'contract_pub' and the 'purse_pub'.
// Optional, may be omitted if not desired by the client.
@@ -2926,12 +3147,15 @@ Wallet-to-wallet transfers
// EdDSA signature of the purse over a
// `TALER_PurseRequestSignaturePS`
- // of purpose ``TALER_SIGNATURE_PURSE_REQUEST``
+ // of purpose ``TALER_SIGNATURE_WALLET_PURSE_CREATE``
// confirming the key
// invariants associated with the purse.
// (amount, h_contract_terms, expiration).
purse_sig: EddsaSignature;
+ // EdDSA public key used to approve merges of this purse.
+ merge_pub: EddsaPublicKey;
+
// Total amount to be paid into the purse.
// Clients may make several requests, i.e. if a
// first request failed with a double-spending error.
@@ -2942,9 +3166,9 @@ Wallet-to-wallet transfers
// SHA-512 hash of the contact of the purse.
h_contract_terms: HashCode;
- // Client-side timestamp of when the payment was made.
- payment_timestamp: Timestamp;
-
+ // Minimum age of deposits made into the purse
+ minimum_age: Integer;
+
// Indicative time by which the purse should expire
// if it has not been merged into an account. At this
// point, all of the deposits made will be auto-refunded.
@@ -2996,7 +3220,7 @@ Wallet-to-wallet transfers
ub_sig: DenominationSignature;
// Signature over `TALER_PurseDepositSignaturePS`
- // of purpose ``TALER_SIGNATURE_PURSE_DEPOSIT``
+ // of purpose ``TALER_SIGNATURE_WALLET_PURSE_DEPOSIT``
// made by the customer with the
// `coin's private key <coin-priv>`.
coin_sig: EddsaSignature;
@@ -3074,7 +3298,7 @@ Wallet-to-wallet transfers
// EdDSA signature of the purse over
// `TALER_PurseMergeSignaturePS` of
- // purpose ``TALER_SIGNATURE_PURSE_MERGE``
+ // purpose ``TALER_SIGNATURE_WALLET_PURSE_MERGE``
// confirming that the
// above details hold for this purse.
purse_sig: EddsaSignature;
@@ -3164,12 +3388,6 @@ Wallet-to-wallet transfers
The request body must be a `MergeRequest` object.
- :query timeout_ms=NUMBER: *Optional.* If specified, the exchange will
- wait up to ``timeout_ms`` milliseconds to receive payment before
- reporting on the completion of merge operation. Basically
- forstalls returning a 202 response for up to timeout milliseconds
- to possibly return a 200 response instead.
-
**Response:**
:http:statuscode:`200 OK`:
@@ -3214,29 +3432,11 @@ Wallet-to-wallet transfers
// EdDSA signature of the purse private key affirming the merge
// over a `TALER_PurseMergeSignaturePS`.
// Must be of purpose ``TALER_SIGNATURE_PURSE_MERGE``.
- purse_sig: EddsaSignature;
-
- // Minimum amount that must be credited to the reserve, that is
- // the total value of the purse minus the deposit fees.
- // If the deposit fees are lower, the contribution to the
- // reserve can be higher!
- merge_value_after_fees: Amount;
-
- // SHA-512 hash of the contact of the purse.
- h_contract_terms: HashCode;
+ merge_sig: EddsaSignature;
// Client-side timestamp of when the merge request was made.
merge_timestamp: Timestamp;
- // Indicative time by which the purse should expire
- // if it has not been paid.
- purse_expiration: Timestamp;
-
- // Optional encrypted contract, in case the seller is
- // proposing the contract and thus establishing the
- // purse with the payment.
- contract?: EncryptedContract;
-
}
.. ts:def:: MergeSuccess
@@ -3246,13 +3446,10 @@ Wallet-to-wallet transfers
// Amount merged (excluding deposit fees).
merge_amount: Amount;
- // SHA-512 hash of the contact of the purse.
- h_contract_terms: HashCode;
-
// Time at which the merge came into effect.
// Maximum of the "payment_timestamp" and the
// "merge_timestamp".
- contract_time: Timestamp;
+ exchange_timestamp: Timestamp;
// EdDSA signature of the exchange affirming the merge of
// purpose ``TALER_SIGNATURE_PURSE_MERGE_SUCCESS``
@@ -3268,6 +3465,76 @@ Wallet-to-wallet transfers
.. ts:def:: MergeAccepted
interface MergeAccepted {
+
+ // Current balance in the purse.
+ balance: Amount;
+
+ }
+
+
+
+.. http:POST:: /reserves/$RESERVE_PUB/purse
+
+ Create purse for an account.
+ Endpoint to be used by the seller.
+
+ **Request:**
+
+ The request body must be a `ReservePurseRequest` object.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The operation succeeded, the exchange confirms that the
+ purse was allocated.
+ The response will include a `MergePending` object.
+ :http:statuscode:`401 Unauthorized`:
+ Account signature is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`402 Payment Required`:
+ The account needs to contain more funding to create more purses.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not found`:
+ The refund operation failed as we could not find the purse.
+ This response comes with a standard `ErrorDetail` response.
+
+ **Details:**
+
+ .. ts:def:: ReservePurseRequest
+
+ interface ReservePurseRequest {
+
+ // EdDSA signature of the account/reserve affirming the merge
+ // over a `TALER_XXX`.
+ // Must be of purpose ``TALER_SIGNATURE_XXX``
+ reserve_sig: EddsaSignature;
+
+ // Minimum amount that must be credited to the reserve, that is
+ // the total value of the purse minus the deposit fees.
+ // If the deposit fees are lower, the contribution to the
+ // reserve can be higher!
+ merge_value_after_fees: Amount;
+
+ // SHA-512 hash of the contact of the purse.
+ h_contract_terms: HashCode;
+
+ // Client-side timestamp of when the merge request was made.
+ merge_timestamp: Timestamp;
+
+ // Indicative time by which the purse should expire
+ // if it has not been paid.
+ purse_expiration: Timestamp;
+
+ // Optional encrypted contract, in case the seller is
+ // proposing the contract and thus establishing the
+ // purse with the payment.
+ contract?: EncryptedContract;
+
+ }
+
+ .. ts:def:: MergePending
+
+ interface MergePending {
// The number of remaining purses that can still be opened
// under the given account.
@@ -3275,7 +3542,9 @@ Wallet-to-wallet transfers
}
-
+
+-- TODO: API to deposit into existing purse
+
.. _exchange_wads:
@@ -3480,7 +3749,7 @@ KYC status updates
// EdDSA signature of the exchange affirming the account
// is KYC'ed, must be of purpose
// ``TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS``
- // and over `TALER_AccountSetupStatusSignaturePS`.
+ // and over ``TALER_AccountSetupStatusSignaturePS``.
exchange_sig: EddsaSignature;
// public key used to create the signature.
@@ -3498,7 +3767,7 @@ KYC status updates
}
-.. http:GET:: /kyc-proof/$PAYMENT_TARGET_UUID
+.. http:GET:: /kyc-proof/$H_PAYTO
Update KYC status of a particular payment target. Provides
the token to the exchange that allows it to verify that the
@@ -3507,10 +3776,10 @@ KYC status updates
**Request:**
- :query code=CODE: OAuth 2.0 code argument.
+ :query code=CODE: OAuth 2.0 code argument.
:query state=CODE: OAuth 2.0 state argument.
- ..note::
+ .. note::
Depending on the OAuth variant used, additional
query parameters may need to be passed here.
diff --git a/core/api-merchant.rst b/core/api-merchant.rst
index 19073b3..d8611c2 100644
--- a/core/api-merchant.rst
+++ b/core/api-merchant.rst
@@ -381,6 +381,9 @@ Querying payment status
// Amount that was refunded in total.
refund_amount: Amount;
+
+ // Amount that already taken by the wallet.
+ refund_taken: Amount;
}
.. ts:def:: StatusGotoResponse
@@ -894,6 +897,15 @@ Setting up instances
// Merchant name corresponding to this instance.
name: string;
+ // Merchant email for customer contact.
+ email?: string;
+
+ // Merchant public website.
+ website?: string;
+
+ // Merchant logo.
+ logo?: ImageDataUrl;
+
// Authentication settings for this instance
auth: InstanceAuthConfigurationMessage;
@@ -998,6 +1010,15 @@ Setting up instances
// Merchant name corresponding to this instance.
name: string;
+ // Merchant email for customer contact.
+ email?: string;
+
+ // Merchant public website.
+ website?: string;
+
+ // Merchant logo.
+ logo?: ImageDataUrl;
+
// The merchant's physical address (to be put into contracts).
address: Location;
@@ -1063,6 +1084,12 @@ Inspecting instances
// Merchant name corresponding to this instance.
name: string;
+ // Merchant public website.
+ website?: string;
+
+ // Merchant logo.
+ logo?: ImageDataUrl;
+
// Merchant instance this response is about ($INSTANCE).
id: string;
@@ -1103,6 +1130,15 @@ Inspecting instances
// Merchant name corresponding to this instance.
name: string;
+ // Merchant email for customer contact.
+ email?: string;
+
+ // Merchant public website.
+ website?: string;
+
+ // Merchant logo.
+ logo?: ImageDataUrl;
+
// Public key of the merchant/instance, in Crockford Base32 encoding.
merchant_pub: EddsaPublicKey;
@@ -1363,6 +1399,9 @@ Adding products to the inventory
// Identifies when we expect the next restocking to happen.
next_restock?: Timestamp;
+ // Minimum age buyer must have (in years). Default is 0.
+ minimum_age?: Integer;
+
}
@@ -1435,6 +1474,9 @@ Adding products to the inventory
// Identifies when we expect the next restocking to happen.
next_restock?: Timestamp;
+ // Minimum age buyer must have (in years). Default is 0.
+ minimum_age?: Integer;
+
}
Inspecting inventory
@@ -1526,6 +1568,9 @@ Inspecting inventory
// Identifies when we expect the next restocking to happen.
next_restock?: Timestamp;
+ // Minimum age buyer must have (in years).
+ minimum_age: Integer;
+
}
@@ -1985,6 +2030,9 @@ Inspecting orders
// Reason given for the refund.
reason: string;
+ // Set to true if a refund is still available for the wallet for this payment.
+ pending: boolean;
+
// When was the refund approved.
timestamp: Timestamp;
@@ -3124,6 +3172,15 @@ It has the following structure:
name: string;
// Label for a location with the business address of the merchant.
+ email?: string;
+
+ // Label for a location with the business address of the merchant.
+ website?: string;
+
+ // An optional base64-encoded product image.
+ logo?: ImageDataUrl;
+
+ // Label for a location with the business address of the merchant.
address?: Location;
// Label for a location that denotes the jurisdiction for disputes.
diff --git a/core/wireformats.rst b/core/wireformats.rst
index d4ffe5f..591f1ce 100644
--- a/core/wireformats.rst
+++ b/core/wireformats.rst
@@ -56,7 +56,7 @@ follow the ``payto://`` specification for SEPA:
.. code-block:: none
- payto://sepa/IBAN
+ payto://iban/IBAN
.. [#sepa] SEPA - Single Euro Payments Area:
http://www.ecb.europa.eu/paym/sepa/html/index.en.html
diff --git a/design-documents/006-extensions.rst b/design-documents/006-extensions.rst
index 7692bb6..42a0e57 100644
--- a/design-documents/006-extensions.rst
+++ b/design-documents/006-extensions.rst
@@ -55,7 +55,8 @@ The necessary changes to ``ExchangeKeysResponse`` are highlighted here:
//...
// Optional field with a dictionary of (name, object) pairs defining the
- // supported extensions. The name MUST be non-empty and unique.
+ // supported and enabled extensions.
+ // The name MUST be non-empty and unique.
extensions?: { name: Extension };
// Signature by the exchange master key of the SHA-256 hash of the
@@ -115,30 +116,39 @@ feature. **However**, it MUST have
// https://docs.taler.net/core/api-common.html#protocol-version-ranges
version: LibtoolVersion;
- // Additional fields defined by the feature itself
- ...
-
+ // Optional configuration object, defined by the feature itself
+ config?: object;
}
Configuration
-------------
-Extensions are *disabled* per default and must *explicetly* be enabled via the
-tool ``taler-exchange-offline``.
+Extensions are *disabled* per default and must *explicetly* be enabled in the
+the TALER configuration manually. The configurations of all enabled extensions
+are signed with the master key and uploaded to the exchange with the tool
+``taler-exchange-offline``.
+
+Each extension has its own section in the configuration, starting with the
+prefix ``exchange-extension-``, like ``[exchange-extension-age_restriction]``.
+The field ``ENABLED = YES|NO`` is used to enable or disable the corresponding
+extension. If the extension has its own configuration parameters, they MAY be
+optional, in which case the ``taler-exchange-offline`` tool MUST fill them with
+safe default values.
-The ``taler-exchange-offline-tool`` MUST offer the subcommand ``extensions``
-for enabling/disabling and setting up particular extensions. For this purpose,
-the following sub-subcommands MUST be available:
+The ``taler-exchange-offline`` tool MUST offer the subcommand ``extensions``
+for showing and signing extensions. For this purpose, the following
+sub-subcommands MUST be available:
-* ``list``: List all available extensions, their versions and criticality
-* ``enable <name>``: Enable the extension with the given name.
-* ``disable <name>``: disable the extension with the given name.
+* ``extensions show``: List all available extensions, their versions,
+ criticality and whether they are enabled.
+* ``extensions sign``: Sign the configuration of all enabled extensions with
+ the master key and prepare a JSON-object for the ``upload`` command.
-When extensions are offered by an exchange the ``extensions`` object MUST be
-signed by the exchange's master signing key. Whenever extensions are enabled
-or disabled, the offline tool MUST sign the SHA256 hash of the normalized
-JSON-string of the ``extensions`` object, if it is not empty.
+When extensions are offered and enabled by an exchange, the ``extensions``
+object MUST be signed by the exchange's master signing key. Whenever
+extensions are enabled or disabled, the offline tool MUST sign the SHA256 hash
+of the normalized JSON-string of the ``extensions`` object, if it is not empty.
In order to do so, the ``taler-exchange-offline`` tool MUST
@@ -156,13 +166,21 @@ In order to do so, the ``taler-exchange-offline`` tool MUST
Similarly, the exchange MUST reject a signed configuration with extensions it
does not know or understand.
-
Examples
--------
-**TODO**:
+A configuration for age-restriction in the taler configuration would look like
+this:
+
+.. code:: none
+
+ [exchange-extension-age_restriction]
+ ENABLED = true
+ # default:
+ AGE_GROUPS = "8:10:12:14:16:18:21"
+
-* Add examples for age-restriction and p2p.
+* TODO: Add examples for p2p.
Merchant
diff --git a/design-documents/010-exchange-helpers.rst b/design-documents/010-exchange-helpers.rst
index e67fca4..a12b4a2 100644
--- a/design-documents/010-exchange-helpers.rst
+++ b/design-documents/010-exchange-helpers.rst
@@ -13,7 +13,7 @@ Motivation
We want to provide an additional layer of protection for the private online
signing keys used by the exchange. The exchange is network-facing, includes an
-HTTP server, Postgres interaction, JSON parser and quite a bit of other logic
+HTTP server, PostgreSQL interaction, JSON parser and quite a bit of other logic
which may all be theoretically vulnerable to remote exploitation. Thus, it
would be good from a security perspective to protect the private online
signing keys via an additional layer of protection.
@@ -89,7 +89,7 @@ Exchange design considerations:
exchange. This simplifies the exchange, and we already needed the
exchange operator to start four processes to operate an exchange.
So this number simply increases to six (not even counting the
- Postgres database and a reverse HTTP proxy for TLS termination).
+ PostgreSQL database and a reverse HTTP proxy for TLS termination).
* Each exchange thread will create its own connection to the helpers, and will
block while waiting on the helper to create a signature. This keeps the
exchange logic simple and similar to the existing in-line signing calls.
@@ -108,7 +108,7 @@ New exchange endpoints:
sign based on that file, and then upload the resulting signature back to
the exchange. For this, master signatures will be POSTed to
the exchange to the ``/keys`` endpoint.
- The exchange will keep those signatures in the Postgres database.
+ The exchange will keep those signatures in the PostgreSQL database.
* A new endpoint (``/auditors``) will also allow adding/removing auditors
(POST, DELETE) using requests signed with the offline master private key.
Once an auditor has been added, the respective auditor signatures on exchange
diff --git a/design-documents/011-auditor-db-sync.rst b/design-documents/011-auditor-db-sync.rst
index f8229b6..d49503d 100644
--- a/design-documents/011-auditor-db-sync.rst
+++ b/design-documents/011-auditor-db-sync.rst
@@ -89,9 +89,9 @@ Proposed Solution
* The auditor's "ingress" database should be well isolated from
the rest of the auditor's system and database
(different user accounts). The reason is that we should not
- assume that the Postgres replication code is battle-tested with
+ assume that the PostgreSQL replication code is battle-tested with
malicious parties in mind.
-* The canonical Postgres synchronization between exchange and the
+* The canonical PostgreSQL synchronization between exchange and the
auditor's "ingress" database must use transport security.
The above solution does not gracefully handle mutable tables on which
@@ -148,10 +148,10 @@ A good order for replicating the tables should be:
Alternatives
============
-* Copy the Postgres WAL, filter it for "illegal" operations
+* Copy the PostgreSQL WAL, filter it for "illegal" operations
and then apply it at the auditor end. Disadvantages: WAL
filtering is not a common operation (format documented?),
- this would be highly Postgres-specific, and would require
+ this would be highly PostgreSQL-specific, and would require
complex work to write the filter. Also unsure how one
could later recover gracefully from transient errors
(say where the exchange recified a bogus DELETE).
diff --git a/design-documents/012-fee-schedule-metrics.rst b/design-documents/012-fee-schedule-metrics.rst
index 01fd484..031783c 100644
--- a/design-documents/012-fee-schedule-metrics.rst
+++ b/design-documents/012-fee-schedule-metrics.rst
@@ -544,4 +544,4 @@ Other documents regarding fee specifications:
* Fee schedule and metrics from the users' point of view :doc:`008-fees`
-* Wire fee for different wiring methods (``sepa`` or ``x-taler-wire``) <https://docs.taler.net/taler-exchange-manual.html#wire-fee-structure>
+* Wire fee for different wiring methods (``iban`` or ``x-taler-wire``) <https://docs.taler.net/taler-exchange-manual.html#wire-fee-structure>
diff --git a/design-documents/013-peer-to-peer-payments.rst b/design-documents/013-peer-to-peer-payments.rst
index c44ab34..da4b4bb 100644
--- a/design-documents/013-peer-to-peer-payments.rst
+++ b/design-documents/013-peer-to-peer-payments.rst
@@ -376,6 +376,8 @@ In this protocol variant, the payer is initiating the process.
3. The payer shares the purse's private key and the base URL
of the exchange where the purse was created with the payee.
This can be done using a ``taler://purse/$BASE_URL/$PURSE_PRIV`` URL.
+ The chapter on ``Refinements'' below clarifies why this
+ step is not quite OK and was modified when implementing the design.
4. The payee uses the new ``/purse/$PURSE_PUB`` endpoint to retrieve
the encrypted contract (if available) and purse balance, which includes all
(coin) deposits and **merges** involving the purse.
@@ -703,7 +705,6 @@ database.)
(merge_request_serial_id BIGSERIAL UNIQUE
,reserve_uuid BYTEA NOT NULL REFERENCES reserves (reserve_uuid) ON DELETE CASCADE
,partner_serial_id INT8 REFERENCES partners(partner_serial_id) ON DELETE CASCADE,
- ,reserve_url TEXT NOT NULL,
,reserve_pub BYTEA NOT NULL CHECK (LENGTH(reserve_pub)=32),
,purse_pub BYTEA NOT NULL CHECK (LENGTH(purse_pub)=32),
,reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64))
@@ -721,8 +722,6 @@ database.)
IS 'identifies the reserve';
COMMENT ON COLUMN mergers.partner_serial_id
IS 'identifies the partner exchange, NULL in case the target reserve lives at this exchange';
- COMMENT ON COLUMN mergers.reserve_url
- IS 'payto://-URL of the reserve, identifies the exchange and the reserve';
COMMENT ON COLUMN mergers.reserve_pub
IS 'public key of the target reserve';
COMMENT ON COLUMN mergers.purse_pub
@@ -821,7 +820,6 @@ database.)
CREATE TABLE IF NOT EXISTS purse_deposits
(purse_deposit_serial_id BIGSERIAL UNIQUE
,purse_pub BYTEA NOT NULL CHECK (LENGTH(purse_pub)=32),
- ,purse_expiration INT8 NOT NULL
,coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub) ON DELETE CASCADE
,amount_with_fee_val INT8 NOT NULL
,amount_with_fee_frac INT4 NOT NULL
@@ -832,8 +830,6 @@ database.)
IS 'Requests depositing coins into a purse';
COMMENT ON COLUMN purse_deposits.purse_pub
IS 'Public key of the purse';
- COMMENT ON COLUMN purse_deposits.purse_expiration
- IS 'When the purse is set to expire';
COMMENT ON COLUMN purse_deposits.coin_pub
IS 'Public key of the coin being deposited';
COMMENT ON COLUMN purse_deposits.amount_with_fee_val
@@ -1071,6 +1067,33 @@ Aside from implementation complexity, the solution has the following drawbacks:
as the wallet software can trivially ensure that a backup was made of the
account private key before initiating the KYC process.
+
+Refinements
+===========
+
+In the original design, a payer making a payment offer sends the purse private
+key to the payee, so that the payee can sign the merge request with it. This
+creates a security issue, as theoretically the payee could sign a different
+contract with the purse private key, and conspire with the exchange to replace
+the original contract. In this case, the payer would be making a payment to
+the "wrong" contract, and have no proof of the exchange an payee conspiring
+against it.
+
+A simple fix seems possible: instead of having simply one public-private key
+pair for a purse, we have a PayerContractKey and a PurseMergeKey pair. The payer
+would pay into a purse identified by the PayerContractKey and associate a
+PurseMergeKey with the purse. The payer can then safely share the
+PayeeMergeKey with the payee, as it is ONLY useful for the merge and not to
+sign the contract. Payments would be made into a purse identified by the
+PurseContractKey.
+
+When payments flow in the other direction, the split of the keys seems
+unnecessary (as only a public key is transmitted anyway. However, schema-wise,
+signing the contract with the PurseContractKey and the merge with the
+PurseMergeKey would still work. Only the public PurseContractKey would need
+to be sent to the payer.
+
+
Q / A
=====
diff --git a/design-documents/024-age-restriction.rst b/design-documents/024-age-restriction.rst
index 884ab27..b97d833 100644
--- a/design-documents/024-age-restriction.rst
+++ b/design-documents/024-age-restriction.rst
@@ -72,7 +72,7 @@ The main ideas are simple:
zeroth age group is :math:`\{0,\ldots,a_1-1\}`.
#. An **unrestricted** *age commitment* is defined as a vector of length M of
- pairs of EdDSA public and private keys on Curve25519. In other words: one
+ pairs of Edx25519_ public and private keys on Curve25519. In other words: one
key pair for each age group after the zeroth:
:math:`\bigl\langle (p_1, s_1), \ldots, (p_M, s_M) \bigr\rangle`
@@ -107,7 +107,6 @@ TODO: Summarize the design based on the five functions ``Commit()``,
``Attest()``, ``Verify()``, ``Derive()``, ``Compare()``, once the paper from
Özgür and Christian is published.
-
Changes in the Exchange API
^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -143,8 +142,13 @@ registering the extension ``age_restriction`` with a value type
// `LibtoolVersion`.
version: "1";
- // Age restriction specific fields
-
+ // Age restriction specific configuration
+ config: ConfigAgeRestriction;
+ }
+
+.. ts:def:: ConfigAgeRestriction
+
+ interface ConfigAgeRestriction {
// The age groups. This field is mandatory and binding in the sense
// that its value is taken into consideration when signing the
// denominations in `ExchangeKeysResponse`.``age_restricted_denoms``.
@@ -354,14 +358,33 @@ the amount of age groups defined in the field ``.age_groups`` of the
// The size of the vector is defined by the Exchange implicetly as the
// amount of age groups defined in the field ``.age_groups`` of the
// ``ExtensionAgeRestriction``.
- old_age_commitment?: EddsaPublicKey[];
+ old_age_commitment?: Edx25519PublicKey[];
...
}
-TODO: describe how the exchange derives the κ-1 other age-restriction vectors
-and compares them to the one in ``.old_age_commitment``.
+
+The exchange can now check if the provided public keys ``.old_age_commitment``
+have the same SHA256 hash value when hashed in sequence as the
+``age_commitment_hash`` of the original coin from the call to melt.
+
+The existing `cut&choose protocol during the reveal phase
+</core/api-exchange.html#post--refreshes-$RCH-reveal>`__ is extended to perform
+the following additional computation and checks:
+
+Using the κ-1 transfer secrets :math:`\tau_i` from the reveal request, the
+exchange derives κ-1 age commitments from the ``old_age_commitment`` by calling
+``Edx25519_derive_public()`` on each `Edx25519PublicKey`, with :math:`\tau_i`
+as the seed, and then calculates the corresponding κ-1 hash values :math:`h_i`
+of those age commitments.
+
+It then calculates the κ-1 blinded hashes
+:math:`m_i = r^{e_i}\text{FDH}_N(C^{(i)}_p, h_i)` (using the notation from Florian's
+thesis) of the disclosed coins and together with the :math:`m_\gamma` of the
+undisclosed coin, calculates the hash
+:math:`h'_m = H(m_1,\cdots,m_\gamma,\cdots,m_\kappa)` which is then used in the
+final verification step of the cut&choose protocol.
Deposit
@@ -413,7 +436,7 @@ minimum age in response to order claim by the wallet, that is, a POST to
``[/instances/$INSTANCE]/orders/$ORDER_ID/claim``.
The object ``ContractTerms`` is extended by an optional field
-``required_minimum_age`` that can be any integer greater than 0. In reality
+``minimum_age`` that can be any integer greater than 0. In reality
this value will not be smaller than, say, 8, and not larger than, say, 21.
.. ts:def:: ContractTerms
@@ -424,12 +447,12 @@ this value will not be smaller than, say, 8, and not larger than, say, 21.
// If the order requires a minimum age greater than 0, this field is set
// to the integer value of that age. In reality this value will not be
// smaller than, say, 8, and not larger than, say, 21.
- required_minimum_age?: Integer;
+ minimum_age?: Integer;
...
}
-By sending the contract term with the field ``required_minimum_age`` set to an
+By sending the contract term with the field ``minimum_age`` set to an
non-zero integer value, the merchant implicetly signals that it understands the
extension ``age_restriction`` for age restriction from the exchange.
@@ -438,7 +461,7 @@ Making the payment
------------------
If the ``ContractTerms`` had a non-zero value in field
-``required_minimum_age``, the wallet has to provide evidence of that minimum
+``minimum_age``, the wallet has to provide evidence of that minimum
age by
#. *either* using coins which are of denominations that had *no* age support
@@ -449,7 +472,7 @@ age by
* and then ―for each such coin― it has the right private key of the
restricted age commitment to the age group into which the required minimum
- age falls (i.e. a non-empty entry at the right index in vector of EdDSA
+ age falls (i.e. a non-empty entry at the right index in vector of Edx25519
keys, see above).
* and signs the required minimum age with each coin's private key
@@ -470,12 +493,12 @@ The object ``CoinPaySig`` used within a ``PayRequest`` during a POST to
// are at least committed to the corresponding age group, this is the
// signature of the minimum age as a string, using the private key to the
// corresponding age group.
- minimum_age_sig?: EddsaSignature;
+ minimum_age_sig?: Edx25519Signature;
// If a minimum age was required by the order, this is age commitment bound
- // to the coin, i.e. the complete vector of EdDSA public keys, one for each
+ // to the coin, i.e. the complete vector of Edx25519_ public keys, one for each
// age group (as defined by the exchange).
- age_commitment?: EddsaPublicKey[];
+ age_commitment?: Edx25519PublicKey[];
}
@@ -543,7 +566,6 @@ Discussion / Q&A
We had some very engaged discussions on the GNU Taler `mailing list <taler@gnu.org>`__:
* `Money with capabilities <https://lists.gnu.org/archive/html/taler/2021-08/msg00005.html>`_
-
* `On age-restriction (was: online games in China) <https://lists.gnu.org/archive/html/taler/2021-09/msg00006.html>`__
@@ -552,3 +574,108 @@ We had some very engaged discussions on the GNU Taler `mailing list <taler@gnu.o
The upcoming paper on anonymous age-restriction for GNU Taler from Özgür Kesim
and Christian Grothoff will be cited here, once it is published.
+
+.. _Edx25519:
+
+Edx25519
+========
+
+Edx25519 is a variant of EdDSA on curve25519 which allows for repeated
+derivation of private and public keys, independently. It is implemented in
+`GNUNET with commit ce38d1f6c9bd7857a1c3bc2094a0ee9752b86c32.
+<https://git.gnunet.org/gnunet.git/commit/?id=ce38d1f6c9bd7857a1c3bc2094a0ee9752b86c32>`__
+
+The private keys in Edx25519 initially correspond to the data after expansion
+and clamping in EdDSA. However, this correspondence is lost after deriving
+further keys from existing ones. The public keys and signature verification
+are compatible with EdDSA.
+
+The scheme is as follows:
+
+::
+
+ /* Private keys in Edx25519 are pairs (a, b) of 32 byte each.
+ * Initially they correspond to the result of the expansion
+ * and clamping in EdDSA.
+ */
+
+ Edx25519_generate_private(seed) {
+ /* EdDSA expand and clamp */
+ dh := SHA-512(seed)
+ a := dh[0..31]
+ b := dh[32..64]
+ a[0] &= 0b11111000
+ a[31] &= 0b01111111
+ a[31] |= 0b01000000
+
+ return (a, b)
+ }
+
+ Edx25519_public_from_private(private) {
+ /* Public keys are the same as in EdDSA */
+ (a, _) := private
+ return [a] * G
+ }
+
+ Edx25519_blinding_factor(P, seed) {
+ /* This is a helper function used in the derivation of
+ * private/public keys from existing ones. */
+ h1 := HKDF_32(P, seed)
+
+ /* Ensure that h == h % L */
+ h := h1 % L
+
+ /* Optionally: Make sure that we don't create weak keys. */
+ P' := [h] * P
+ if !( (h!=1) && (h!=0) && (P'!=E) ) {
+ return Edx25519_blinding_factor(P, seed+1)
+ }
+
+ return h
+ }
+
+ Edx25519_derive_private(private, seed) {
+ /* This is based on the definition in
+ * GNUNET_CRYPTO_eddsa_private_key_derive. But it accepts
+ * and returns a private pair (a, b) and allows for iteration.
+ */
+ (a, b) := private
+ P := Edx25519_public_key_from_private(private)
+ h := Edx25519_blinding_factor(P, seed)
+
+ /* Carefully calculate the new value for a */
+ a1 := a / 8;
+ a2 := (h * a1) % L
+ a' := (a2 * 8) % L
+
+ /* Update b as well, binding it to h.
+ This is an additional step compared to GNS. */
+ b' := SHA256(b ∥ h)
+
+ return (a', b')
+ }
+
+ Edx25519_derive_public(P, seed) {
+ h := Edx25519_blinding_factor(P, seed)
+ return [h]*P
+ }
+
+ Edx25519_sign(private, message) {
+ /* As in Ed25519, except for the origin of b */
+ (d, b) := private
+ P := Edx25519_public_from_private(private)
+ r := SHA-512(b ∥ message)
+ R := [r] * G
+ s := r + SHA-512(R ∥ P ∥ message) * d % L
+
+ return (R,s)
+ }
+
+ Edx25519_verify(P, message, signature) {
+ /* Identical to Ed25519 */
+ (R, s) := signature
+ return [s] * G == R + [SHA-512(R ∥ P ∥ message)] * P
+ }
+
+::
+
diff --git a/design-documents/026-refund-fees.rst b/design-documents/026-refund-fees.rst
new file mode 100644
index 0000000..f65da4a
--- /dev/null
+++ b/design-documents/026-refund-fees.rst
@@ -0,0 +1,61 @@
+Refunds and Fees
+################
+
+Summary
+=======
+
+This document discusses what should happen with deposit fees when a
+deposit is refunded.
+
+
+Motivation
+==========
+
+When a user receives a refund, we have to decide what happens to the deposit
+fee that was originally paid on the associated deposit. Originally, we said
+that the deposit fee is waived when any refund happens. However, if the
+refund fee is zero and the deposit fee is non-zero, this results in a
+problematic scenario where merchants issue miniscule refunds that primarily
+enable customers to effectively obtain the deposit fee.
+
+
+Requirements
+============
+
+ * If the refund and refresh fees are zero, it should be possible for
+ consumers to get 100% of their digital cash back on refunds.
+ * This should not result in a problematic situation where merchants
+ conspire with consumers and issue miniscule refunds to allow consumers
+ to work around deposit fees.
+
+Proposed Solution
+=================
+
+ * Only waive the deposit fee for full refunds where for the
+ specific coin (!) the refunded amount is the total value of the
+ refunded deposit.
+
+Alternatives
+============
+
+ * Only waive the deposit fee for full refunds where for the
+ specific coin the refunded amount is the total value of the
+ denomination of the coin. This may slightly simplify the
+ logic, but has the problem that it does not enable 100%
+ refunds if the original payment already required a refresh
+ because the coin's value exceeded the paid amount.
+ * Waive the deposit fee on any (including partial) refund.
+ This creates a bad incentive structure if combined refresh
+ and refund fees are below deposit fees.
+
+Drawbacks
+=========
+
+ * We need to update and test an already complex fee calculation
+ logic.
+
+
+Discussion / Q&A
+================
+
+(This should be filled in with results from discussions on mailing lists / personal communication.)
diff --git a/design-documents/027-sandboxing-taler.rst b/design-documents/027-sandboxing-taler.rst
new file mode 100644
index 0000000..c1e5293
--- /dev/null
+++ b/design-documents/027-sandboxing-taler.rst
@@ -0,0 +1,165 @@
+Design Doc 027: Sandboxing all the Taler services.
+##################################################
+
+.. note::
+
+ This design document is currently a draft, it
+ does not reflect any implementation decisions yet.
+
+Summary
+=======
+
+This document presents a method of deploying all the Taler
+services via one Docker container.
+
+Motivation
+==========
+
+It is very difficult to build GNU Taler from scratch. It is even more difficult
+to install, configure and launch it correctly.
+
+The purpose of the sandbox is to have a demonstration system that can be both
+build and launched with ideally a single command.
+
+Requirements
+============
+
+- No external services should be required, the only dependencies should be:
+
+ - podman/docker
+ - optionally: configuration files to further customize the setup
+
+- All services that are used should be installed from repositories
+ and not built from scratch (i.e. debian repos or PyPI)
+
+- There should be some "admin page" for the whole sandbox that:
+
+ - Show an overview of all deployed services, a link to their documentation
+ and the endpoints they expose
+ - Show very simple statistics (e.g. number of transactions / withdrawals)
+ - Allows generating and downloading the auditor report
+
+- Developers should be able to launch the sandbox on their own machine
+
+ - Possibly using nightly repos instead of the official stable repos
+
+- We should be able to deploy it on $NAME.sandbox.taler.net
+
+Design
+======
+
+The container is based on Debian Sid, and it installs all
+the services from their Debian packages. During the build
+process, it creates all the 'static' configuration. This
+one includes all the .conf-files, the database setup and the
+keying.
+
+Subsequently at the launch step, the system will create all
+the remaining RESTful resources. Such RESTful resources include
+the merchant instances and all the euFin accounts, both at Sandbox
+and at Nexus.
+
+The sandbox will serve one HTTP base URL and make any service
+reachable at $baseUrl/$service. For example, the exchange base
+URL will be "$baseUrl/exchange".
+
+The sandbox allows to configure:
+
+- which host it binds to, typically localhost+port.
+- which host is being reverse proxied to the sandbox. This
+ helps to generate valid URIs of services.
+
+All the other values will be hard-coded in the preparation.
+
+The database is aunched *in* the same container along the
+other services.
+
+Open questions
+==============
+
+- How to collect the static configuration values?
+
+ - => Via a configuration file that you pass to the container via
+ a mounted directory (=> `-v $MYCONFIG:/sandboxconfig`)
+ - If we don't pass any config, the container should have
+ sane defaults
+ - This is effectively a "meta configuration", because it will
+ be used to generate the actual configuration files
+ and do RESTful configuration at launch time.
+
+- How to persist, at build time, the information
+ needed later at launch time to create the RESTful
+ resources?
+
+ - => The configuration should be done at launch-time of the container.
+
+- Should we at this iteration hard-code passwords too?
+ With generated passwords, (1) it won't be possible to
+ manually log-in to services, (2) it won't be possible
+ to write the exchange password for Nexus in the conf.
+ Clearly, that's a problem when the sandbox is served
+ to the outside.
+
+- How is data persisted? (i.e. where do we store stuff)
+
+ - By allowing to mount some data directory on the host of the container
+ (This stores the DB files, config files, key files, etc.)
+ - ... even for data like the postgresql database
+ - future/optional: we *might* allow connection to an external postgresql database as well
+
+- How are services supervised?
+
+ - SystemD? gnunet-arm? supervisord? something else?
+
+ - SystemD does not work well inside containers
+
+ - alternative: one container per service, use (docker/podman)-compose
+
+ - Either one docker file per service, *or* one base container that
+ can be launched as different services via command line arg
+
+ - Advantage: It's easy to see the whole architecture from the compose yaml file
+ - Advantage: It would be easy to later deploy this on kubernetes etc.
+
+ - list of containers:
+
+ - DB container (postgres)
+ - Exchange container (contains all exchange services, for now)
+ - Split this up further?
+ - Merchant container
+
+- Do we have multi-tenancy for the sandbox? (I.e. do we allow multiple
+ currencies/exchanges/merchants/auditors per sandbox)
+
+ - Might be simpler if we disallow this
+
+- How do we handle TLS
+
+ - Do we always do HTTPs in the sandbox container?
+ - We need to think about external and internal requests
+ to the sandbox
+
+- How do we handle (external vs internal) URLs
+
+ - If we use http://localhost:$PORT for everything, we can't expose
+ the services externally
+ - Example 1: Sandbox should run on sb1.sandbox.taler.net.
+
+ - What will be the base URL for the exchange in the merchant config?
+ - If it's https://sb1.sandbox.taler.net/exchange, we need some /etc/hosts entry
+ inside the container
+ - Once you want to expose the sandbox internally, you need a proper TLS cert (i.e. letsencrypt)
+ - Inside the container, you can get away with self-signed certificates
+ - Other solution: Just require the external nginx (e.g. at gv) to reverse proxy
+ sb1.sandbox.taler.net back to the container. This means that all communication
+ between services inside the sandbox container goes through gv
+
+ - Not great, but probably fine for first iteration
+ - Disadvantages: To test the container in the non-localhost mode, you need the external proxy running
+
+- Where do we take packages from?
+
+ - By default, from the stable taler-systems.com repos and PyPI
+ - Alternatively, via the nightly gv debian repo
+ - Since we install packages at container build time, this setting (stable vs nightly)
+ results in different container base images
diff --git a/design-documents/028-proof-of-escrow.rst b/design-documents/028-proof-of-escrow.rst
new file mode 100644
index 0000000..113d274
--- /dev/null
+++ b/design-documents/028-proof-of-escrow.rst
@@ -0,0 +1,128 @@
+DD 028: Proof of escrow in the exchange
+#######################################
+
+.. note::
+
+ This design document is currently a draft, it
+ does not reflect any implementation decisions yet.
+
+
+Summary
+=======
+
+We propose here an extension to the exchange: An escrow service that can be
+used by other, separate trading services f.e. for online auctions.
+
+
+Motivation
+==========
+
+Certain types of trade, such as auctions or trades with long phases of
+negotiation, require a proof of escrow of money as a guarantee in order to
+participate or perform the trade.
+
+We want to extend GNU Taler to support trades such as anonymous sealed-bid
+auctions. While the auction service will be a separate (from the exchange)
+entity, behaving in parts like a normal merchant in the GNU Taler sense, the
+exchange itself can provide an escrow services.
+
+Background and Requirements
+===========================
+
+An escrow service is a intermediary between two parties and must trusted by
+both. In the GNU Taler payment system, this role is per definition played by
+the exchange for buyers and sellers during purchases. The auditor controls the
+exchange and is also a mediator between buyers and selles.
+
+The role of the exchange can be therefore extended to the specific needs of
+escrow. In contrast to purchase/deposit, for escrow, particular coins are
+locked, but not spent. This prohibits their spending for a specific timespan
+and until a valid order of release is provided.
+
+However, in the context of auctions, we want the parties to be able to verify
+the fairness of the participants. For example, a seller of goods during an
+auction shall only be able to relase the money for the winning bidder and not
+for the others. On the other hand, both, sellers and bidders should be able
+provide evidence to the exchange and auditor if the other party wasn't honest,
+f.e. if the winning bidder hasn't released the money.
+
+
+
+Proposed Solution
+=================
+
+We propose a the following endpoints
+
+
+- ``POST /escrows/$ESCROW_ID/register``: Register an escrow account under the
+ provided EdDSA public key ``$ESCROW_ID``. The required parameters are:
+
+ - a starttime
+ - an endttime
+ - an interval ``[m, M]`` of minimum and maximum amounts, where ``M`` can also be ``∞``.
+
+- ``GET /escrows/$ESCROW_ID``: Return the terms of the escrow and the current
+ list of depositor IDs.
+
+- ``POST /escrows/$ESCROW_ID/deposit/$DEPOSIT_ID``: Deposit a specific amount
+ with a particular list of coins. The required parameters are:
+
+ - the amount ``a`` to be deposited (must lie in ``[m, M]``)
+ - the list of coins to be used for the deposit (the sum of the values must be
+ at least ``a``)
+ - signatures from each coin over the SHA512 hash of the amount ``a``, the
+ ``$DEPOSIT_ID`` and the ``$ESCROW_ID``.
+
+ The ``$DEPOSIT_ID`` is the SHA512 hash over all the coins.
+
+
+- ``POST /escrows/$ESCROW_ID/claim/$DEPOSIT_ID``: The owner of the private key for
+ ``$ESCROW_ID`` can claim the deposited coins. It has to provide
+
+ - the particular amount ``a'`` to be claimed
+ - the list of coins to be claimed from the deposit
+ - signatures over the SHA512 hash of the amount ``a'``, ``$ESCROW_ID`` and
+ the ``$DEPOSIT_ID``, signed by each coin
+
+The following diagram gives an overview of the flow:
+
+.. image:: _svgs/escrow-flow.svg
+
+
+When the ``endtime`` of an escrow has arrived on the exchange, an amount ``a``
+of a deposit of amount ``b ≥ a`` can be claimed by the originator of the escrow
+account. Only *one* succesfull claim can be made for a particular escrow
+account. After a claim has been made, the remaining coins in the remaining
+deposits are released by the exchange. If no claim is made within a specific
+time inverval after ``endtime``, all coins of *all* deposits are released.
+
+The ``GET /escrows/$ESCROWS_ID`` allows to depositors and auditors to confirm
+their deposit. It also allows depositors to compare the list with their
+mentioning at other services, such as the list of bidders in an online auction.
+
+TODOs: Specify
+
+- data structures
+- signatures
+- return values
+- errors
+- terms of contracts
+- default time intervals
+
+Alternatives
+============
+
+TODO
+
+Drawbacks
+=========
+
+TODO
+
+
+Discussion / Q&A
+================
+
+TODO
+
+(This should be filled in with results from discussions on mailing lists / personal communication.)
diff --git a/design-documents/_svgs/escrow-flow.svg b/design-documents/_svgs/escrow-flow.svg
new file mode 100644
index 0000000..cd0b2c9
--- /dev/null
+++ b/design-documents/_svgs/escrow-flow.svg
@@ -0,0 +1 @@
+<svg aria-labelledby="chart-title-graph-div chart-desc-graph-div" role="img" viewBox="-111 -10 1273 1070" style="max-width: 1273px;" height="1070" xmlns="http://www.w3.org/2000/svg" width="100%" id="graph-div"><title id="chart-title-graph-div"></title><desc id="chart-desc-graph-div"></desc><style>#graph-div {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#graph-div .error-icon{fill:#552222;}#graph-div .error-text{fill:#552222;stroke:#552222;}#graph-div .edge-thickness-normal{stroke-width:2px;}#graph-div .edge-thickness-thick{stroke-width:3.5px;}#graph-div .edge-pattern-solid{stroke-dasharray:0;}#graph-div .edge-pattern-dashed{stroke-dasharray:3;}#graph-div .edge-pattern-dotted{stroke-dasharray:2;}#graph-div .marker{fill:#333333;333;}#graph-div .marker.cross{333;}#graph-div svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#graph-div .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#graph-div text.actor&gt;tspan{fill:black;stroke:none;}#graph-div .actor-line{stroke:grey;}#graph-div .messageLine0{stroke-width:1.5;stroke-dasharray:none;;}#graph-div .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;;}#graph-div #arrowhead path{fill:#333;;}#graph-div .sequenceNumber{fill:white;}#graph-div #sequencenumber{fill:#333;}#graph-div #crosshead path{fill:#333;;}#graph-div .messageText{fill:#333;;}#graph-div .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#graph-div .labelText,#graph-div .labelText&gt;tspan{fill:black;stroke:none;}#graph-div .loopText,#graph-div .loopText&gt;tspan{fill:black;stroke:none;}#graph-div .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#graph-div .note{stroke:#aaaa33;fill:#fff5ad;}#graph-div .noteText,#graph-div .noteText&gt;tspan{fill:black;stroke:none;}#graph-div .activation0{fill:#f4f4f4;stroke:#666;}#graph-div .activation1{fill:#f4f4f4;stroke:#666;}#graph-div .activation2{fill:#f4f4f4;stroke:#666;}#graph-div .actorPopupMenu{position:absolute;}#graph-div .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#graph-div .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#graph-div .actor-man circle,#graph-div line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#graph-div :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g></g><defs><symbol height="24" width="24" id="computer"><path d="M2 2v13h20v-13h-20zm18 11h-16v-9h16v9zm-10.228 6l.466-1h3.524l.467 1h-4.457zm14.228 3h-24l2-6h2.104l-1.33 4h18.45l-1.297-4h2.073l2 6zm-5-10h-14v-7h14v7z" transform="scale(.5)"></path></symbol></defs><defs><symbol clip-rule="evenodd" fill-rule="evenodd" id="database"><path d="M12.258.001l.256.004.255.005.253.008.251.01.249.012.247.015.246.016.242.019.241.02.239.023.236.024.233.027.231.028.229.031.225.032.223.034.22.036.217.038.214.04.211.041.208.043.205.045.201.046.198.048.194.05.191.051.187.053.183.054.18.056.175.057.172.059.168.06.163.061.16.063.155.064.15.066.074.033.073.033.071.034.07.034.069.035.068.035.067.035.066.035.064.036.064.036.062.036.06.036.06.037.058.037.058.037.055.038.055.038.053.038.052.038.051.039.05.039.048.039.047.039.045.04.044.04.043.04.041.04.04.041.039.041.037.041.036.041.034.041.033.042.032.042.03.042.029.042.027.042.026.043.024.043.023.043.021.043.02.043.018.044.017.043.015.044.013.044.012.044.011.045.009.044.007.045.006.045.004.045.002.045.001.045v17l-.001.045-.002.045-.004.045-.006.045-.007.045-.009.044-.011.045-.012.044-.013.044-.015.044-.017.043-.018.044-.02.043-.021.043-.023.043-.024.043-.026.043-.027.042-.029.042-.03.042-.032.042-.033.042-.034.041-.036.041-.037.041-.039.041-.04.041-.041.04-.043.04-.044.04-.045.04-.047.039-.048.039-.05.039-.051.039-.052.038-.053.038-.055.038-.055.038-.058.037-.058.037-.06.037-.06.036-.062.036-.064.036-.064.036-.066.035-.067.035-.068.035-.069.035-.07.034-.071.034-.073.033-.074.033-.15.066-.155.064-.16.063-.163.061-.168.06-.172.059-.175.057-.18.056-.183.054-.187.053-.191.051-.194.05-.198.048-.201.046-.205.045-.208.043-.211.041-.214.04-.217.038-.22.036-.223.034-.225.032-.229.031-.231.028-.233.027-.236.024-.239.023-.241.02-.242.019-.246.016-.247.015-.249.012-.251.01-.253.008-.255.005-.256.004-.258.001-.258-.001-.256-.004-.255-.005-.253-.008-.251-.01-.249-.012-.247-.015-.245-.016-.243-.019-.241-.02-.238-.023-.236-.024-.234-.027-.231-.028-.228-.031-.226-.032-.223-.034-.22-.036-.217-.038-.214-.04-.211-.041-.208-.043-.204-.045-.201-.046-.198-.048-.195-.05-.19-.051-.187-.053-.184-.054-.179-.056-.176-.057-.172-.059-.167-.06-.164-.061-.159-.063-.155-.064-.151-.066-.074-.033-.072-.033-.072-.034-.07-.034-.069-.035-.068-.035-.067-.035-.066-.035-.064-.036-.063-.036-.062-.036-.061-.036-.06-.037-.058-.037-.057-.037-.056-.038-.055-.038-.053-.038-.052-.038-.051-.039-.049-.039-.049-.039-.046-.039-.046-.04-.044-.04-.043-.04-.041-.04-.04-.041-.039-.041-.037-.041-.036-.041-.034-.041-.033-.042-.032-.042-.03-.042-.029-.042-.027-.042-.026-.043-.024-.043-.023-.043-.021-.043-.02-.043-.018-.044-.017-.043-.015-.044-.013-.044-.012-.044-.011-.045-.009-.044-.007-.045-.006-.045-.004-.045-.002-.045-.001-.045v-17l.001-.045.002-.045.004-.045.006-.045.007-.045.009-.044.011-.045.012-.044.013-.044.015-.044.017-.043.018-.044.02-.043.021-.043.023-.043.024-.043.026-.043.027-.042.029-.042.03-.042.032-.042.033-.042.034-.041.036-.041.037-.041.039-.041.04-.041.041-.04.043-.04.044-.04.046-.04.046-.039.049-.039.049-.039.051-.039.052-.038.053-.038.055-.038.056-.038.057-.037.058-.037.06-.037.061-.036.062-.036.063-.036.064-.036.066-.035.067-.035.068-.035.069-.035.07-.034.072-.034.072-.033.074-.033.151-.066.155-.064.159-.063.164-.061.167-.06.172-.059.176-.057.179-.056.184-.054.187-.053.19-.051.195-.05.198-.048.201-.046.204-.045.208-.043.211-.041.214-.04.217-.038.22-.036.223-.034.226-.032.228-.031.231-.028.234-.027.236-.024.238-.023.241-.02.243-.019.245-.016.247-.015.249-.012.251-.01.253-.008.255-.005.256-.004.258-.001.258.001zm-9.258 20.499v.01l.001.021.003.021.004.022.005.021.006.022.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.023.018.024.019.024.021.024.022.025.023.024.024.025.052.049.056.05.061.051.066.051.07.051.075.051.079.052.084.052.088.052.092.052.097.052.102.051.105.052.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.048.144.049.147.047.152.047.155.047.16.045.163.045.167.043.171.043.176.041.178.041.183.039.187.039.19.037.194.035.197.035.202.033.204.031.209.03.212.029.216.027.219.025.222.024.226.021.23.02.233.018.236.016.24.015.243.012.246.01.249.008.253.005.256.004.259.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.021.224-.024.22-.026.216-.027.212-.028.21-.031.205-.031.202-.034.198-.034.194-.036.191-.037.187-.039.183-.04.179-.04.175-.042.172-.043.168-.044.163-.045.16-.046.155-.046.152-.047.148-.048.143-.049.139-.049.136-.05.131-.05.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.053.083-.051.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.05.023-.024.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.023.01-.022.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.127l-.077.055-.08.053-.083.054-.085.053-.087.052-.09.052-.093.051-.095.05-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.045-.118.044-.12.043-.122.042-.124.042-.126.041-.128.04-.13.04-.132.038-.134.038-.135.037-.138.037-.139.035-.142.035-.143.034-.144.033-.147.032-.148.031-.15.03-.151.03-.153.029-.154.027-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.01-.179.008-.179.008-.181.006-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.006-.179-.008-.179-.008-.178-.01-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.027-.153-.029-.151-.03-.15-.03-.148-.031-.146-.032-.145-.033-.143-.034-.141-.035-.14-.035-.137-.037-.136-.037-.134-.038-.132-.038-.13-.04-.128-.04-.126-.041-.124-.042-.122-.042-.12-.044-.117-.043-.116-.045-.113-.045-.112-.046-.109-.047-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.05-.093-.052-.09-.051-.087-.052-.085-.053-.083-.054-.08-.054-.077-.054v4.127zm0-5.654v.011l.001.021.003.021.004.021.005.022.006.022.007.022.009.022.01.022.011.023.012.023.013.023.015.024.016.023.017.024.018.024.019.024.021.024.022.024.023.025.024.024.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.052.11.051.114.051.119.052.123.05.127.051.131.05.135.049.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.044.171.042.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.022.23.02.233.018.236.016.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.012.241-.015.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.048.139-.05.136-.049.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.051.051-.049.023-.025.023-.024.021-.025.02-.024.019-.024.018-.024.017-.024.015-.023.014-.023.013-.024.012-.022.01-.023.01-.023.008-.022.006-.022.006-.022.004-.021.004-.022.001-.021.001-.021v-4.139l-.077.054-.08.054-.083.054-.085.052-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.044-.118.044-.12.044-.122.042-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.035-.143.033-.144.033-.147.033-.148.031-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.009-.179.009-.179.007-.181.007-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.007-.179-.007-.179-.009-.178-.009-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.031-.146-.033-.145-.033-.143-.033-.141-.035-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.04-.126-.041-.124-.042-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.051-.093-.051-.09-.051-.087-.053-.085-.052-.083-.054-.08-.054-.077-.054v4.139zm0-5.666v.011l.001.02.003.022.004.021.005.022.006.021.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.024.018.023.019.024.021.025.022.024.023.024.024.025.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.051.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.043.171.043.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.021.23.02.233.018.236.017.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.013.241-.014.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.049.139-.049.136-.049.131-.051.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.049.023-.025.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.022.01-.023.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.153l-.077.054-.08.054-.083.053-.085.053-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.048-.105.048-.106.048-.109.046-.111.046-.114.046-.115.044-.118.044-.12.043-.122.043-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.034-.143.034-.144.033-.147.032-.148.032-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.024-.161.024-.162.023-.163.023-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.01-.178.01-.179.009-.179.007-.181.006-.182.006-.182.004-.184.003-.184.001-.185.001-.185-.001-.184-.001-.184-.003-.182-.004-.182-.006-.181-.006-.179-.007-.179-.009-.178-.01-.176-.01-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.023-.162-.023-.161-.024-.159-.024-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.032-.146-.032-.145-.033-.143-.034-.141-.034-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.041-.126-.041-.124-.041-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.048-.105-.048-.102-.048-.1-.05-.097-.049-.095-.051-.093-.051-.09-.052-.087-.052-.085-.053-.083-.053-.08-.054-.077-.054v4.153zm8.74-8.179l-.257.004-.254.005-.25.008-.247.011-.244.012-.241.014-.237.016-.233.018-.231.021-.226.022-.224.023-.22.026-.216.027-.212.028-.21.031-.205.032-.202.033-.198.034-.194.036-.191.038-.187.038-.183.04-.179.041-.175.042-.172.043-.168.043-.163.045-.16.046-.155.046-.152.048-.148.048-.143.048-.139.049-.136.05-.131.05-.126.051-.123.051-.118.051-.114.052-.11.052-.106.052-.101.052-.096.052-.092.052-.088.052-.083.052-.079.052-.074.051-.07.052-.065.051-.06.05-.056.05-.051.05-.023.025-.023.024-.021.024-.02.025-.019.024-.018.024-.017.023-.015.024-.014.023-.013.023-.012.023-.01.023-.01.022-.008.022-.006.023-.006.021-.004.022-.004.021-.001.021-.001.021.001.021.001.021.004.021.004.022.006.021.006.023.008.022.01.022.01.023.012.023.013.023.014.023.015.024.017.023.018.024.019.024.02.025.021.024.023.024.023.025.051.05.056.05.06.05.065.051.07.052.074.051.079.052.083.052.088.052.092.052.096.052.101.052.106.052.11.052.114.052.118.051.123.051.126.051.131.05.136.05.139.049.143.048.148.048.152.048.155.046.16.046.163.045.168.043.172.043.175.042.179.041.183.04.187.038.191.038.194.036.198.034.202.033.205.032.21.031.212.028.216.027.22.026.224.023.226.022.231.021.233.018.237.016.241.014.244.012.247.011.25.008.254.005.257.004.26.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.022.224-.023.22-.026.216-.027.212-.028.21-.031.205-.032.202-.033.198-.034.194-.036.191-.038.187-.038.183-.04.179-.041.175-.042.172-.043.168-.043.163-.045.16-.046.155-.046.152-.048.148-.048.143-.048.139-.049.136-.05.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.05.051-.05.023-.025.023-.024.021-.024.02-.025.019-.024.018-.024.017-.023.015-.024.014-.023.013-.023.012-.023.01-.023.01-.022.008-.022.006-.023.006-.021.004-.022.004-.021.001-.021.001-.021-.001-.021-.001-.021-.004-.021-.004-.022-.006-.021-.006-.023-.008-.022-.01-.022-.01-.023-.012-.023-.013-.023-.014-.023-.015-.024-.017-.023-.018-.024-.019-.024-.02-.025-.021-.024-.023-.024-.023-.025-.051-.05-.056-.05-.06-.05-.065-.051-.07-.052-.074-.051-.079-.052-.083-.052-.088-.052-.092-.052-.096-.052-.101-.052-.106-.052-.11-.052-.114-.052-.118-.051-.123-.051-.126-.051-.131-.05-.136-.05-.139-.049-.143-.048-.148-.048-.152-.048-.155-.046-.16-.046-.163-.045-.168-.043-.172-.043-.175-.042-.179-.041-.183-.04-.187-.038-.191-.038-.194-.036-.198-.034-.202-.033-.205-.032-.21-.031-.212-.028-.216-.027-.22-.026-.224-.023-.226-.022-.231-.021-.233-.018-.237-.016-.241-.014-.244-.012-.247-.011-.25-.008-.254-.005-.257-.004-.26-.001-.26.001z" transform="scale(.5)"></path></symbol></defs><defs><symbol height="24" width="24" id="clock"><path d="M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm5.848 12.459c.202.038.202.333.001.372-1.907.361-6.045 1.111-6.547 1.111-.719 0-1.301-.582-1.301-1.301 0-.512.77-5.447 1.125-7.445.034-.192.312-.181.343.014l.985 6.238 5.394 1.011z" transform="scale(.5)"></path></symbol></defs><g><line stroke="#999" stroke-width="0.5px" class="200" y2="1004" x2="75" y1="5" x1="75" id="actor6934"></line><g id="root-6934"><rect class="actor" ry="3" rx="3" height="65" width="150" stroke="#666" fill="#eaeaea" y="0" x="0"></rect><text style="text-anchor: middle; font-size: 14px; font-weight: 400; font-family: &quot;Open Sans&quot;, sans-serif;" class="actor" alignment-baseline="central" dominant-baseline="central" y="32.5" x="75"><tspan dy="0" x="75">Seller</tspan></text></g></g><g><line stroke="#999" stroke-width="0.5px" class="200" y2="1004" x2="575" y1="5" x1="575" id="actor6935"></line><g id="root-6935"><rect class="actor" ry="3" rx="3" height="65" width="150" stroke="#666" fill="#eaeaea" y="0" x="500"></rect><text style="text-anchor: middle; font-size: 14px; font-weight: 400; font-family: &quot;Open Sans&quot;, sans-serif;" class="actor" alignment-baseline="central" dominant-baseline="central" y="32.5" x="575"><tspan dy="0" x="575">Exchange</tspan></text></g></g><g><line stroke="#999" stroke-width="0.5px" class="200" y2="1004" x2="949" y1="5" x1="949" id="actor6936"></line><g id="root-6936"><rect class="actor" ry="3" rx="3" height="65" width="150" stroke="#666" fill="#eaeaea" y="0" x="874"></rect><text style="text-anchor: middle; font-size: 14px; font-weight: 400; font-family: &quot;Open Sans&quot;, sans-serif;" class="actor" alignment-baseline="central" dominant-baseline="central" y="32.5" x="949"><tspan dy="0" x="949">Buyer</tspan></text></g></g><defs><marker orient="auto" markerHeight="12" markerWidth="12" markerUnits="userSpaceOnUse" refY="5" refX="9" id="arrowhead"><path d="M 0 0 L 10 5 L 0 10 z"></path></marker></defs><defs><marker refY="4" refX="16" orient="auto" markerHeight="8" markerWidth="15" id="crosshead"><path style="stroke-dasharray: 0, 0;" d="M 9,2 V 6 L16,4 Z" stroke-width="1px" stroke="#000000" fill="black"></path><path style="stroke-dasharray: 0, 0;" d="M 0,1 L 6,7 M 6,1 L 0,7" stroke-width="1px" stroke="#000000" fill="none"></path></marker></defs><defs><marker orient="auto" markerHeight="28" markerWidth="20" refY="7" refX="18" id="filled-head"><path d="M 18,7 L9,13 L14,7 L9,1 Z"></path></marker></defs><defs><marker orient="auto" markerHeight="40" markerWidth="60" refY="15" refX="15" id="sequencenumber"><circle r="6" cy="15" cx="15"></circle></marker></defs><g><rect class="note" ry="0" rx="0" height="52" width="272" stroke="#666" fill="#EDF2AE" y="75" x="-61"></rect><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="80" x="75"><tspan x="75">The seller creates an escrow account </tspan></text><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="96" x="75"><tspan x="75"> with specific terms and a public key EID</tspan></text></g><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 16px; font-weight: 400;" dy="1em" class="messageText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="142" x="325">register escrow (EID, [m, M], starttime, endtime)</text><line style="fill: none;" marker-end="url(#arrowhead)" stroke="none" stroke-width="2" class="messageLine0" y2="175" x2="575" y1="175" x1="75"></line><g><rect class="activation0" ry="0" rx="0" height="48" width="10" stroke="#666" fill="#EDF2AE" y="175" x="570"></rect></g><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 16px; font-weight: 400;" dy="1em" class="messageText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="190" x="323">(EID + sig_e(EID, [m, M], starttime, endtime))</text><line style="fill: none;" marker-end="url(#arrowhead)" stroke="none" stroke-width="2" class="messageLine0" y2="223" x2="75" y1="223" x1="570"></line><g><rect class="note" ry="0" rx="0" height="52" width="188" stroke="#666" fill="#EDF2AE" y="233" x="-19"></rect><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="238" x="75"><tspan x="75">Seller publishes the EID, </tspan></text><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="254" x="75"><tspan x="75"> for example for an auction</tspan></text></g><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 16px; font-weight: 400;" dy="1em" class="messageText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="300" x="512">publish auction (EID, [m, M], starttime, endtime, sig)</text><line style="stroke-dasharray: 3, 3; fill: none;" marker-end="url(#arrowhead)" stroke="none" stroke-width="2" class="messageLine1" y2="333" x2="949" y1="333" x1="75"></line><g><rect class="note" ry="0" rx="0" height="53" width="326" stroke="#666" fill="#EDF2AE" y="343" x="786"></rect><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="348" x="949"><tspan x="949">An interested bidder can receive the list of</tspan></text><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="364" x="949"><tspan x="949"> depositors (not amounts) for the escrow account</tspan></text></g><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 16px; font-weight: 400;" dy="1em" class="messageText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="411" x="762">list(EID)</text><line style="fill: none;" marker-end="url(#arrowhead)" stroke="none" stroke-width="2" class="messageLine0" y2="444" x2="575" y1="444" x1="949"></line><g><rect class="activation0" ry="0" rx="0" height="48" width="10" stroke="#666" fill="#EDF2AE" y="444" x="570"></rect></g><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 16px; font-weight: 400;" dy="1em" class="messageText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="459" x="765">list of depositors</text><line style="fill: none;" marker-end="url(#arrowhead)" stroke="none" stroke-width="2" class="messageLine0" y2="492" x2="949" y1="492" x1="580"></line><g><rect class="note" ry="0" rx="0" height="52" width="315" stroke="#666" fill="#EDF2AE" y="502" x="791.5"></rect><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="507" x="949"><tspan x="949">A intereseted bidder can deposit coins into the </tspan></text><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="523" x="949"><tspan x="949">escrow account and receives a proof of escrow</tspan></text></g><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 16px; font-weight: 400;" dy="1em" class="messageText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="569" x="762">deposit(EID, amount, coins[], DEPOSIT_ID)</text><line style="fill: none;" marker-end="url(#arrowhead)" stroke="none" stroke-width="2" class="messageLine0" y2="602" x2="575" y1="602" x1="949"></line><g><rect class="activation0" ry="0" rx="0" height="48" width="10" stroke="#666" fill="#EDF2AE" y="602" x="570"></rect></g><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 16px; font-weight: 400;" dy="1em" class="messageText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="617" x="765">proof (EID, DEPOSIT_ID, [m,M])</text><line style="fill: none;" marker-end="url(#arrowhead)" stroke="none" stroke-width="2" class="messageLine0" y2="650" x2="949" y1="650" x1="580"></line><g><rect class="note" ry="0" rx="0" height="52" width="233" stroke="#666" fill="#EDF2AE" y="660" x="832.5"></rect><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="665" x="949"><tspan x="949">The bidder can now use the proof</tspan></text><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="681" x="949"><tspan x="949"> to participate in the auction</tspan></text></g><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 16px; font-weight: 400;" dy="1em" class="messageText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="727" x="512">bid (EID, proof(EID, [m,M]))</text><line style="stroke-dasharray: 3, 3; fill: none;" marker-end="url(#arrowhead)" stroke="none" stroke-width="2" class="messageLine1" y2="760" x2="75" y1="760" x1="949"></line><g><rect class="note" ry="0" rx="0" height="52" width="299" stroke="#666" fill="#EDF2AE" y="770" x="799.5"></rect><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="775" x="949"><tspan x="949">The winning bidder provides a release token </tspan></text><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="791" x="949"><tspan x="949"> for the winning amount to the seller</tspan></text></g><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 16px; font-weight: 400;" dy="1em" class="messageText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="837" x="512">EID, DEPOSIT_ID, amount, coins[], sig_b(...)</text><line style="fill: none;" marker-end="url(#arrowhead)" stroke="none" stroke-width="2" class="messageLine0" y2="870" x2="75" y1="870" x1="949"></line><g><rect class="note" ry="0" rx="0" height="36" width="208" stroke="#666" fill="#EDF2AE" y="880" x="-29"></rect><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="885" x="75"><tspan x="75">The seller can claim the coins</tspan></text></g><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 16px; font-weight: 400;" dy="1em" class="messageText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="931" x="325">claim(EID, DEPOSIT_ID, amount, coins[], sig_b, sig_s(sig_b))</text><line style="fill: none;" marker-end="url(#arrowhead)" stroke="none" stroke-width="2" class="messageLine0" y2="964" x2="575" y1="964" x1="75"></line><g><rect class="actor" ry="3" rx="3" height="65" width="150" stroke="#666" fill="#eaeaea" y="984" x="0"></rect><text style="text-anchor: middle; font-size: 14px; font-weight: 400; font-family: &quot;Open Sans&quot;, sans-serif;" class="actor" alignment-baseline="central" dominant-baseline="central" y="1016.5" x="75"><tspan dy="0" x="75">Seller</tspan></text></g><g><rect class="actor" ry="3" rx="3" height="65" width="150" stroke="#666" fill="#eaeaea" y="984" x="500"></rect><text style="text-anchor: middle; font-size: 14px; font-weight: 400; font-family: &quot;Open Sans&quot;, sans-serif;" class="actor" alignment-baseline="central" dominant-baseline="central" y="1016.5" x="575"><tspan dy="0" x="575">Exchange</tspan></text></g><g><rect class="actor" ry="3" rx="3" height="65" width="150" stroke="#666" fill="#eaeaea" y="984" x="874"></rect><text style="text-anchor: middle; font-size: 14px; font-weight: 400; font-family: &quot;Open Sans&quot;, sans-serif;" class="actor" alignment-baseline="central" dominant-baseline="central" y="1016.5" x="949"><tspan dy="0" x="949">Buyer</tspan></text></g></svg>
diff --git a/design-documents/index.rst b/design-documents/index.rst
index 444e475..53889b2 100644
--- a/design-documents/index.rst
+++ b/design-documents/index.rst
@@ -34,4 +34,7 @@ and protocol.
023-taler-kyc
024-age-restriction
025-withdraw-from-wallet
+ 026-refund-fees
+ 027-sandboxing-taler.rst
+ 028-proof-of-escrow
999-template
diff --git a/frags/list-of-dependencies.rst b/frags/list-of-dependencies.rst
index ace68f3..082cc37 100644
--- a/frags/list-of-dependencies.rst
+++ b/frags/list-of-dependencies.rst
@@ -14,8 +14,8 @@
- libjansson >= 2.7
-- PostgreSQL >= 9.6, including libpq
+- PostgreSQL >= 13, including libpq
- GNU libmicrohttpd >= 0.9.71
-- GNUnet >= 0.15.2 (from `source tarball <http://ftpmirror.gnu.org/gnunet/>`__)
+- GNUnet >= 0.16 (from `source tarball <http://ftpmirror.gnu.org/gnunet/>`__)
diff --git a/libeufin/api-sandbox.rst b/libeufin/api-sandbox.rst
index 4ef47b4..f6ff682 100644
--- a/libeufin/api-sandbox.rst
+++ b/libeufin/api-sandbox.rst
@@ -233,6 +233,10 @@ Bank accounts.
Give information about a bank account.
+.. http:delete:: /demobanks/$demobankId/$accountLabel
+
+ Delete the bank account (and the customer entry) from the database.
+ Note, customer usernames and bank accounts have the same value.
Main EBICS service.
^^^^^^^^^^^^^^^^^^^
@@ -310,7 +314,7 @@ rights on all of them.
One of the main differences with the previous versions is the
removal of the "/admin" initial component. If the administrator
authenticates for one operation, then this one is of type ``admin``:
-no need for a dedicate and extra URI part.
+no need for a dedicated and extra URI path component.
For example, mocking transactions in the system was a typical
/admin-operation, but since transactions themselves are resources
diff --git a/libeufin/ebics.rst b/libeufin/ebics.rst
index 058804e..7c1fa2a 100644
--- a/libeufin/ebics.rst
+++ b/libeufin/ebics.rst
@@ -409,13 +409,14 @@ Formats
ISO 20022
---------
-ISO 20022 is XML-based and defines the message format for many finance-related activities.
+`ISO 20022 <https://www.iso20022.org/>`_
+is XML-based and defines the message format for many finance-related activities.
ISO 20022 messages are identified by a message identifier in the following format:
<business area> . <message identifier> . <variant> . <version>
-Some financial instututions (such as the Deutsche Kreditwirtschaft) may decided to use
+Some financial instututions (such as the Deutsche Kreditwirtschaft) have decided to use
a subset of elements/attributes in a message, this is what the ``<variant>`` part is for.
"Standard" ISO20022 have variant ``001``.
diff --git a/libeufin/index.rst b/libeufin/index.rst
index 0e18486..29cd7a0 100644
--- a/libeufin/index.rst
+++ b/libeufin/index.rst
@@ -18,3 +18,4 @@ LibEuFin is a project providing free software tooling for European FinTech.
frontend
nexus-tutorial
demo-deployment-gv
+ int-deployment-gv
diff --git a/libeufin/int-deployment-gv.rst b/libeufin/int-deployment-gv.rst
new file mode 100644
index 0000000..b3a1293
--- /dev/null
+++ b/libeufin/int-deployment-gv.rst
@@ -0,0 +1,71 @@
+.. target audience: operator, developer
+
+Deploying Taler with libEufin
+#############################
+
+.. contents:: Table of Contents
+
+This document shows how to compile and run all
+the Taler services (including libEuFin).
+
+Deployment on Gv
+----------------
+
+After having pulled the latest code of deployment.git:
+
+.. code-block:: console
+
+ $ python3 deployment/bin/WIP/taler-local bootstrap
+ $ python3 deployment/bin/WIP/taler-local build
+ $ python3 deployment/bin/WIP/taler-local prepare
+
+The last step offers also a way to specify the database
+name -- only the PostgreSQL at this time -- and the hostname
+of the reverse proxy. See ``--help`` for more information.
+
+At this point, the services can be launched, and will be
+served at ``$hostname/$service``. The following command
+will launch all the services and show what ``$service``
+can be:
+
+.. code-block:: console
+
+ $ python3 deployment/bin/WIP/taler-local launch
+
+.. note::
+
+ In this context, one reverse proxy gets launched
+ along all the Taler services and will dispatch any request
+ to ``$service`` to the respective Unix domain socket.
+
+Withdraw with Taler
+-------------------
+
+The following command withdraws a fixed amount of 5 units of currency
+to the CLI wallet:
+
+.. code-block:: console
+
+ $ python3 deployment/bin/WIP/taler-local withdraw
+
+The requests will be addressed to the default Sandbox, unless
+``--bank-host`` (and ``--bank-proto``) were given; see ``--help``
+for more information.
+
+.. note::
+
+ To test phone wallets, the option ``--with-qr-code``
+ can be specified. That will print a QR code on screen, and
+ wait for the user's input before confirming the payment to
+ the Exchange.
+
+Taler Internal deployment
+-------------------------
+
+One deployment is currently hosted at ``int.taler.net``.
+
+Withdraw:
+
+.. code-block:: console
+
+ $ python3 deployment/bin/WIP/taler-local withdraw --bank-host int.taler.net --bank-proto https
diff --git a/libeufin/nexus-tutorial.rst b/libeufin/nexus-tutorial.rst
index 5ce357b..1877e92 100644
--- a/libeufin/nexus-tutorial.rst
+++ b/libeufin/nexus-tutorial.rst
@@ -134,6 +134,9 @@ If you don't have access to a real bank account with an EBICS API, you can set
up the sandbox. The sandbox is a simplistic and incomplete implementation of a
core banking system with EBICS access to bank accounts.
+The sandbox uses HTTP Basic auth, with username ``admin``.
+Choose a password and set env var ``LIBEUFIN_SANDBOX_ADMIN_PASSWORD`` to it.
+
The sandbox relies on a database, which you must specify using a JDBC
connection URI with the ``LIBEUFIN_SANDBOX_DB_CONNECTION`` environment
variable, before invoking any commands.
@@ -141,6 +144,7 @@ If this variable is not set, ``libeufin-sandbox`` complains and exits:
.. code-block:: console
+ $ export LIBEUFIN_SANDBOX_ADMIN_PASSWORD=secret
$ libeufin-sandbox serve
DB connection string not found/valid in the env variable LIBEUFIN_SANDBOX_DB_CONNECTION.
The following two examples are valid connection strings:
@@ -149,95 +153,290 @@ If this variable is not set, ``libeufin-sandbox`` complains and exits:
Only *SQLite* and *PostgreSQL (via TCP)* are supported right now.
-For the following commands, the sandbox service must be running.
-The sandbox service is started with the following command:
+Before being usable, a Sandbox needs to be configured. This is done
+by creating the `default` demobank. A demobank is a set of configuration
+values associated to one name; in the example below, we'll create one
+named `default`, that is mandatory to have.
+
+.. note::
+
+ By design, many demobanks can be hosted by one running Sandbox,
+ although at the time of writing only the 'default' one is supported.
+
+A default demobank having the EUR currency is created with the following command:
.. code-block:: console
$ export LIBEUFIN_SANDBOX_DB_CONNECTION=jdbc:sqlite:/tmp/libeufintestdb
+ $ libeufin-sandbox config --currency EUR default
+
+In order to use Taler, a default exchange needs to be configured.
+
+.. code-block:: console
+
+ $ export LIBEUFIN_SANDBOX_DB_CONNECTION=jdbc:sqlite:/tmp/libeufintestdb
+ $ libeufin-sandbox default-exchange --demobank default $exchange_base_url $exchange_payto_address
+
+The sandbox service can now be started with the following command:
+
+.. code-block:: console
+
+ $ export LIBEUFIN_SANDBOX_ADMIN_PASSWORD=secret
+ $ export LIBEUFIN_SANDBOX_DB_CONNECTION=jdbc:sqlite:/tmp/libeufintestdb
$ libeufin-sandbox serve --port 5016
+The instructions below hook Nginx to the Sandbox:
+
+.. code-block:: console
+
+ redirect / to /demobanks/default;
+ rewrite ^/$ https://$host/demobanks/default;
+ location / {
+ proxy_set_header Host $host;
+ proxy_set_header X-Forwarded-Host $host;
+ proxy_set_header X-Forwarded-Proto "https";
+ proxy_set_header X-Forwarded-Prefix "/";
+ proxy_pass http://localhost:5016/;
+ }
+
To reset the state of the sandbox, delete the database.
For invocations of the LibEuFin command-line interface tool (``libeufin-cli``),
-the following environment variable must be set to the URL of the sandbox
-service:
+the following environment variables must be set to the authentication
+information, and the URL of the sandbox service:
.. code-block:: console
- $ export LIBEUFIN_SANDBOX_URL=http://localhost:5016/
+ $ export LIBEUFIN_SANDBOX_USERNAME=admin
+ $ export LIBEUFIN_SANDBOX_PASSWORD=secret
+ $ export LIBEUFIN_SANDBOX_URL=http://localhost:5016
+Note that the password is the same as for ``LIBEUFIN_SANDBOX_ADMIN_PASSWORD``.
Verify that the sandbox is running:
.. code-block:: console
$ libeufin-cli sandbox check
- {
- "name" : "libeufin-sandbox",
- "version" : "0.0.0-dev.0"
- }
+ Hello, this is the Sandbox
Now an EBICS host can be created:
.. code-block:: console
$ libeufin-cli sandbox ebicshost create --host-id testhost
+ $ libeufin-cli sandbox ebicshost list
+ {
+ "ebicsHosts" : [ "testhost" ]
+ }
Note that most ``libeufin-cli`` subcommands will ask for input interactively if
the respective value is not specified on the command line.
-Next, create an EBICS subscriber (identified by the partner ID and user ID) for the host:
+Next, register a user. For the ``libeufin-cli sandbox demobank register``
+command, the ``LIBEUFIN_SANDBOX_USERNAME`` and ``LIBEUFIN_SANDBOX_PASSWORD``
+are assumed to be ``jrluser`` and ``easy``, respectively.
+Also, the URL for all ``libeufin-cli sandbox demobank`` commands
+must include the name of a bank, as follows:
.. code-block:: console
- $ libeufin-cli sandbox ebicssubscriber create \
- --host-id testhost --partner-id partner01 --user-id user01
+ $ export LIBEUFIN_SANDBOX_USERNAME=jrluser
+ $ export LIBEUFIN_SANDBOX_PASSWORD=easy
+ $ libeufin-cli sandbox \
+ --sandbox-url http://localhost:5016/demobanks/default \
+ demobank register
+
+In this example, the bank name is ``default``. In these examples, we use the
+``--sandbox-url`` option for the ``demobank`` commands, so that we don't need
+to change the environment variable ``LIBEUFIN_SANDBOX_URL`` for the
+non-``demobank`` commands.
-Create a bank account for the subscriber and add a sample transaction:
+Check the balance of the user just created:
.. code-block:: console
- $ libeufin-cli sandbox ebicsbankaccount create \
- --currency EUR \
- --iban DE18500105172929531888 \
- --bic INGDDEFFXXX \
- --person-name "Jane Normal" \
- --account-name "testacct01" \
- --ebics-host-id testhost \
- --ebics-user-id user01 \
- --ebics-partner-id partner01
+ $ libeufin-cli sandbox \
+ --sandbox-url http://localhost:5016/demobanks/default \
+ demobank info --bank-account jrluser
+
+With a user registered, we can now create an EBICS subscriber (identified by
+the partner ID and user ID) for the host. This command requires admin
+priveleges, so ``LIBEUFIN_SANDBOX_USERNAME`` and ``LIBEUFIN_SANDBOX_PASSWORD``
+are reset back to ``admin`` and ``secret``, respectively.
-The account name ``testacct01`` is the unique identifier of the account within
+.. The plan is to replace the ‘sandbox ebicssubscriber list’ command
+ below with a ‘sandbox demobank show-ebicssubscriber’ command.
+ Need to implement it first!
+
+.. code-block:: console
+
+ $ export LIBEUFIN_SANDBOX_USERNAME=admin
+ $ export LIBEUFIN_SANDBOX_PASSWORD=secret
+ $ libeufin-cli sandbox \
+ --sandbox-url http://localhost:5016/demobanks/default \
+ demobank new-ebicssubscriber \
+ --host-id testhost \
+ --partner-id partner01 \
+ --user-id user02 \
+ --bank-account jrluser
+ $ libeufin-cli sandbox ebicssubscriber list
+ {
+ "subscribers" : [ {
+ "hostID" : "testhost",
+ "partnerID" : "partner01",
+ "userID" : "user02",
+ "systemID" : null,
+ "demobankAccountLabel" : "jrluser"
+ } ]
+ }
+
+The ``libeufin-cli sandbox demobank new-ebicssubscriber`` command
+also creates an associated bank account. You can see it with command:
+
+.. code-block:: console
+
+ $ libeufin-cli sandbox bankaccount list
+ [ {
+ "label" : "bank",
+ "name" : "Bank account owner's name",
+ "iban" : "DE895351",
+ "bic" : "SANDBOXX"
+ }, {
+ "label" : "jrluser",
+ "name" : "Bank account owner's name",
+ "iban" : "DE724881",
+ "bic" : "SANDBOXX"
+ } ]
+
+The account name ``jrluser`` is the unique identifier of the account within
the sandbox. The EBICS parameters identify the subscriber that should have
access to the bank account via EBICS.
-To populate the account with some test transactions, run the following command
-(note that we use the ``bankaccount`` subcommand, because there is no need to rely
-on EBICS):
+.. note::
+
+ Currently, the person (given human) name is not maintained by
+ the sandbox. It displays "Bank account owner's name" instead.
+
+The account already has one transaction, the "Sign-up bonus" from the bank.
+Note that in the following examples we transition to using the ``bankaccount``
+subcommand, because there is no need to rely on EBICS:
+
+.. code-block:: console
+
+ $ libeufin-cli sandbox bankaccount transactions jrluser
+ {
+ "payments" : [ {
+ "accountLabel" : "jrluser",
+ "creditorIban" : "DE724881",
+ "creditorBic" : "SANDBOXX",
+ "creditorName" : "Unknown",
+ "debtorIban" : "DE895351",
+ "debtorBic" : "SANDBOXX",
+ "debtorName" : "The Bank",
+ "amount" : "100",
+ "currency" : "EUR",
+ "subject" : "Sign-up bonus",
+ "date" : "Tue, 22 Feb 2022 00:04:15 GMT",
+ "creditDebitIndicator" : "credit",
+ "accountServicerReference" : "2NG75I0O",
+ "paymentInformationId" : null
+ } ]
+ }
+
+To populate the account with some more transactions, run the following command:
.. code-block:: console
- $ libeufin-cli sandbox bankaccount generate-transactions testacct01
+ $ libeufin-cli sandbox bankaccount generate-transactions jrluser
.. code-block:: console
- $ libeufin-cli sandbox bankaccount simulate-incoming-transaction testacct01 \
+ $ libeufin-cli sandbox bankaccount simulate-incoming-transaction jrluser \
--debtor-iban DE06500105174526623718 \
--debtor-bic INGDDEFFXXX \
--debtor-name "Joe Foo" \
--subject "Hello World" \
--amount 10.50
-Payments to a sandbox bank account can be listed as follows:
+Now the list of transactions has grown by several entries:
.. code-block:: console
- $ libeufin-cli sandbox bankaccount transactions testacct01
+ $ libeufin-cli sandbox bankaccount transactions jrluser
+ {
+ "payments" : [ {
+ "accountLabel" : "jrluser",
+ "creditorIban" : "DE724881",
+ "creditorBic" : "SANDBOXX",
+ "creditorName" : "Unknown",
+ "debtorIban" : "DE895351",
+ "debtorBic" : "SANDBOXX",
+ "debtorName" : "The Bank",
+ "amount" : "100",
+ "currency" : "EUR",
+ "subject" : "Sign-up bonus",
+ "date" : "Tue, 22 Feb 2022 00:04:15 GMT",
+ "creditDebitIndicator" : "credit",
+ "accountServicerReference" : "2NG75I0O",
+ "paymentInformationId" : null
+ }, {
+ "accountLabel" : "jrluser",
+ "creditorIban" : "DE724881",
+ "creditorBic" : "SANDBOXX",
+ "creditorName" : "Creditor Name",
+ "debtorIban" : "DE64500105178797276788",
+ "debtorBic" : "DEUTDEBB101",
+ "debtorName" : "Max Mustermann",
+ "amount" : "22",
+ "currency" : "EUR",
+ "subject" : "sample transaction GSF7S5LC",
+ "date" : "Tue, 22 Feb 2022 01:26:18 GMT",
+ "creditDebitIndicator" : "credit",
+ "accountServicerReference" : "GSF7S5LC",
+ "paymentInformationId" : null
+ }, {
+ "accountLabel" : "jrluser",
+ "creditorIban" : "DE64500105178797276788",
+ "creditorBic" : "DEUTDEBB101",
+ "creditorName" : "Max Mustermann",
+ "debtorIban" : "DE724881",
+ "debtorBic" : "SANDBOXX",
+ "debtorName" : "Debitor Name",
+ "amount" : "10",
+ "currency" : "EUR",
+ "subject" : "sample transaction 1WUP303Q",
+ "date" : "Tue, 22 Feb 2022 01:26:18 GMT",
+ "creditDebitIndicator" : "debit",
+ "accountServicerReference" : "1WUP303Q",
+ "paymentInformationId" : null
+ }, {
+ "accountLabel" : "jrluser",
+ "creditorIban" : "DE724881",
+ "creditorBic" : "SANDBOXX",
+ "creditorName" : "Creditor Name",
+ "debtorIban" : "DE06500105174526623718",
+ "debtorBic" : "INGDDEFFXXX",
+ "debtorName" : "Joe Foo",
+ "amount" : "10.50",
+ "currency" : "EUR",
+ "subject" : "Hello World",
+ "date" : "Tue, 22 Feb 2022 01:26:41 GMT",
+ "creditDebitIndicator" : "credit",
+ "accountServicerReference" : "sandbox-ALQP8TXKJWRVKMAH",
+ "paymentInformationId" : null
+ } ]
+ }
.. note::
The sandbox is intended as a testing tool and thus not stable.
+Disable registrations (experimental)
+------------------------------------
+
+Demobanks can disable/enable registrations for new users. The
+responsible option is ``--with-registrations``/``--without-registrations``.
+
For more information on the available commands, use the built-in ``--help`` flag.
The full functionality of the sandbox is available via
the :ref:`Sandbox API <sandbox-api>`.
@@ -255,7 +454,7 @@ Only *SQLite* (e.g. ``jdbc:sqlite:/tmp/libeufintestdb``) and *PostgreSQL (via TC
(e.g. ``jdbc:postgresql://localhost:$port/libeufintestdb?user=$username&password=$password``)
are supported right now.
-Use the following command to run the nexus service:
+Use the following command to run the Nexus service:
.. code-block:: console
@@ -264,8 +463,8 @@ Use the following command to run the nexus service:
This assumes that the PostgreSQL service with a database
called ``libeufindb`` listens on port 5433
-for requests from the nexus service.
-The nexus service itself listens on port 5017.
+for requests from the Nexus service.
+The Nexus service itself listens on port 5017.
Note that you must have the ``LIBEUFIN_NEXUS_DB_CONNECTION``
environment variable set for most uses of the libeufin-nexus
command.
@@ -290,14 +489,22 @@ to be defined in the environment: ``LIBEUFIN_NEXUS_URL``, ``LIBEUFIN_NEXUS_USERN
and ``LIBEUFIN_NEXUS_PASSWORD``. In this example, ``LIBEUFIN_NEXUS_USERNAME`` should be
set to ``foo``, and ``LIBEUFIN_NEXUS_PASSWORD`` to the value given for its password
in the previous step (with the ``libeufin-nexus superuser`` command). The
-``LIBEUFIN_NEXUS_URL`` could be given as ``http://localhost:5017/``.
+``LIBEUFIN_NEXUS_URL`` could be given as ``http://localhost:5017``.
-Next, we create a EBICS *bank connection* that nexus can use to communicate with the bank.
+Next, we create a EBICS *bank connection* that Nexus can use to communicate with the bank.
.. note::
For the sandbox setup in this guide, the ``EBICS_BASE_URL``
should be ``http://localhost:5016/ebicsweb``.
+ This is the value of environment variable
+ ``LIBEUFIN_SANDBOX_URL`` suffixed with ``/ebicsweb``,
+ since the sandbox will be providing EBICS services.
+
+ Similarly, ``EBICS_HOST_ID`` should be ``testhost``,
+ and ``EBICS_PARTNER_ID`` should be ``partner01``.
+ For ``EBICS_USER_ID`` we will use ``user02`` (for account ``jrluser``),
+ and for ``CONNECTION_NAME``, we will use ``conn01``.
.. code-block:: console
@@ -310,7 +517,10 @@ Next, we create a EBICS *bank connection* that nexus can use to communicate with
--ebics-user-id $EBICS_USER_ID \
$CONNECTION_NAME
-If this step executes correctly, Nexus will have created all the cryptographic
+If this step executes correctly
+(use ``libeufin-cli connections list-connections``
+and ``libeufin-cli connections show-connection`` to check),
+Nexus will have created all the cryptographic
material that is needed on the client side; in this EBICS example, it created
the signature and identification keys. It is therefore advisable to *make
a backup copy* of such keys.
@@ -394,7 +604,7 @@ list of transactions, and making a payment.
Request history of transactions
===============================
-The LibEuFin nexus keeps a local copy of the bank account's transaction
+The LibEuFin Nexus keeps a local copy of the bank account's transaction
history. Before querying transactions locally, it is necessary
to request transactions for the bank account via the bank connection.
@@ -456,11 +666,11 @@ in the next step, to **send the payment instructions to the bank**:
Automatic scheduling
====================
-With an EBICS bank connection, the LibEuFin nexus needs to regularly query for
+With an EBICS bank connection, the LibEuFin Nexus needs to regularly query for
new transactions and (re-)submit prepared payments.
It is possible to schedule these tasks via an external task scheduler such as
-cron(8). However, the nexus also has an internal task scheduling mechanism for
+cron(8). However, the Nexus also has an internal task scheduling mechanism for
accounts.
diff --git a/manpages/TDM.el b/manpages/TDM.el
index b4fabc7..a58fb1c 100644
--- a/manpages/TDM.el
+++ b/manpages/TDM.el
@@ -1,6 +1,6 @@
;;; TDM.el --- editing Taler docs.git/manpages/* -*- lexical-binding: t -*-
-;; Copyright (C) 2021 Taler Systems SA
+;; Copyright (C) 2021, 2022 Taler Systems SA
;;
;; This file is part of GNU TALER.
;;
@@ -22,7 +22,10 @@
;;; Commentary:
-;; This library currently provides one command: ‘TDM-convert-options’.
+;; This library currently provides two commands: ‘TDM-convert-options’
+;; and ‘TDM-recursive-help’.
+;;
+;; * ‘TDM-convert-options’
;; The intended workflow is simple:
;; - Create a new file from template.
;; - Do the <FOO> substitutions / deletions as necessary.
@@ -49,6 +52,15 @@
;; There are a couple TODO items, which point to situations that
;; have not yet arisen in practice, but that might theoretically
;; bother us in the future.
+;;
+;; * ‘TDM-recursive-help’
+;; This command is intended for libeufin programs, specifically
+;; libeufin-sandbox, libeufin-nexus, and libeufin-cli. However,
+;; it should work with any Java program that uses clikt, or any
+;; Python program that uses click, for its command-line handling.
+;;
+;; You can obtain the --help output (recursively) in a buffer
+;; and write it to a file for further analysis / processing.
;;; Code:
@@ -121,6 +133,40 @@ Prefix arg KEEP-ORIG means don't delete them."
(save-excursion
(delete-region p q)))))
+(defun TDM-recursive-help (command)
+ "Call COMMAND --help and recurse on its subcommands.
+Subcommands are identified by \"Commands:\" in column 0
+in the output.
+
+Collect the output in a new buffer *COMMAND --help*,
+with one page per --help output."
+ (interactive "sCommand: ")
+ (let ((out (get-buffer-create (format "*%s --help*" command))))
+ (with-current-buffer out
+ (erase-buffer))
+ (cl-labels
+ ;; visit command
+ ((v (c) (with-temp-buffer
+ (apply #'call-process (car c) nil t nil
+ (append (cdr c) (list "--help")))
+ (goto-char (point-min))
+ (when (re-search-forward "^Commands:\n" nil t)
+ (while (looking-at "[ ][ ]\\(\\S +\\)")
+ (let ((sub (match-string 1)))
+ (v (append c (list sub))))
+ (forward-line 1)
+ (while (looking-at "[ ][ ][ ]")
+ (forward-line 1))))
+ (let ((s (buffer-string)))
+ (message "c: %s" c)
+ (with-current-buffer out
+ (goto-char (point-min))
+ (insert "\f\n")
+ (insert "$ " (substring (format "%s" c) 1 -1) "\n")
+ (insert s "\n"))))))
+ (v (list command)))
+ (switch-to-buffer out)))
+
(provide 'TDM)
;;; TDM.el ends here
diff --git a/manpages/libeufin-cli.1.rst b/manpages/libeufin-cli.1.rst
new file mode 100644
index 0000000..e48fffd
--- /dev/null
+++ b/manpages/libeufin-cli.1.rst
@@ -0,0 +1,1006 @@
+libeufin-cli(1)
+###############
+
+.. only:: html
+
+ Name
+ ====
+
+ **libeufin-cli** - Interact with LibEuFin Sandbox and Nexus
+
+
+Synopsis
+========
+
+**libeufin-cli**
+[**-h** | **--help**]
+[**--version**]
+COMMAND [ARGS...]
+
+Commands: accounts, connections, facades, permissions, sandbox, users
+
+
+Description
+===========
+
+**libeufin-cli** is the user interface program to interact
+with **libeufin-sandbox** and **libeufin-nexus** when they are
+operating as HTTP servers, listening on localhost ports.
+Normally, you invoke them with their respective ``serve`` commands,
+and in a separate shell, use **libeufin-cli** to send requests
+and receive responses from them.
+
+The interaction model is as follows:
+
+- (Optionally) Start the sandbox.
+
+- Start the nexus.
+
+- Use **libeufin-cli** to interact with them.
+ You can manage users and permissions, bank accounts, "facades",
+ transactions, and connections between the various systems.
+
+For **libeufin-cli** to be able to communicate with **libeufin-sandbox**,
+the following environment variables need to be set:
+
+``LIBEUFIN_SANDBOX_USERNAME``
+ This should normally be ``admin``.
+
+``LIBEUFIN_SANDBOX_PASSWORD``
+ This is the same password chosen when the sandbox was started.
+
+``LIBEUFIN_SANDBOX_URL``
+ This is ``http://localhost:PORT``, where ``PORT`` is the
+ same port chosen when the sandbox was started.
+ This URL can also be specified with the ``--sandbox-url URL``
+ option to the ``sandbox`` command (see below).
+ If both are given, the ``--sandbox-url`` option takes precedence.
+
+For **libeufin-cli** to be able to communicate with **libeufin-nexus**,
+the following environment variables need to be set:
+
+``LIBEUFIN_NEXUS_USERNAME``
+ For some operations (such as ``users create``), this must be the
+ same username chosen by the ``libeufin-nexus superuser`` command.
+
+``LIBEUFIN_NEXUS_PASSWORD``
+ This is the password associated with the username.
+
+``LIBEUFIN_NEXUS_URL``
+ This is ``http://localhost:PORT``, where ``PORT`` is the
+ same port chosen when the nexus was started.
+
+Of the six commands, the ``sandbox`` command talks to the sandbox,
+while the other five commands talk to the nexus.
+The following sections describe each command and their subcommands in detail.
+
+
+sandbox
+-------
+
+The ``libeufin-cli sandbox`` command is for managing the sandbox process
+started by ``libeufin-sandbox serve``.
+It takes one option, ``--sandbox-url URL``, to be specified before
+the subcommands and their arguments.
+This URL can also be specified with the ``LIBEUFIN_SANDBOX_URL``
+environment variable (see above).
+If both are given, the ``--sandbox-url`` option takes precedence.
+
+The following subcommands are available: bankaccount, check, demobank,
+ebicsbankaccount, ebicshost, ebicssubscriber.
+
+The first command to use is ``check``,
+followed by ``ebicshost``, ``ebicssubscriber``,
+and ``ebicsbankaccount``, to configure the basic system.
+
+You can then use the ``bankaccount`` command to generate (simulated)
+transaction traffic.
+
+After that, the ``demobank`` command and its subcommands
+provide the same access to the API that Nexus itself uses.
+You normally do not need to use those commands directly.
+
+
+sandbox check
+-------------
+
+The ``check`` command attempts a simple aliveness check by
+contacting the sandbox and displaying its returned message.
+If all goes well, you should see something like:
+
+.. code-block:: console
+
+ $ libeufin-cli sandbox check
+ Hello, this is the Sandbox
+
+
+sandbox ebicshost
+-----------------
+
+The ``ebicshost`` command manages EBICS hosts.
+It has two subcommands: create and list.
+
+sandbox ebicshost create
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``ebicshost create`` command creates a EBICS host.
+It takes one option, ``--host-id ID``, where ``ID`` is used to
+identify that host for all future commands.
+
+sandbox ebicshost list
+^^^^^^^^^^^^^^^^^^^^^^
+
+The ``ebicshost list`` command lists the hosts in the system.
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-cli sandbox ebicshost create --host-id testhost
+ $ libeufin-cli sandbox ebicshost list
+ {
+ "ebicsHosts" : [ "testhost" ]
+ }
+
+Here, the ``ID`` is ``testhost``.
+
+
+sandbox ebicssubscriber
+-----------------------
+
+The ``ebicssubscriber`` command manages EBICS subscribers.
+It has two subcommands: create and list.
+
+sandbox ebicssubscriber create
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+NB: This command is deprecated and will be removed at some point.
+See ``sandbox demobank new-ebicssubscriber`` (below) for its replacement.
+
+The ``ebicssubscriber create`` command creates a EBICS subscriber.
+It takes three options, all of which are required:
+
+::
+
+ --host-id TEXT Ebics host ID
+ --partner-id TEXT Ebics partner ID
+ --user-id TEXT Ebics user ID
+
+The host ID should be the same one specified in ``ebicshost create``
+(see above).
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-cli sandbox ebicssubscriber create \
+ --host-id testhost \
+ --partner-id partner01 \
+ --user-id user01
+
+Note that ``testhost`` is the same as in the ``ebicshost create``
+example (see above).
+
+sandbox ebicssubscriber list
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``ebicssubscriber list`` command lists the EBICS subscribers
+in the system.
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-cli sandbox ebicssubscriber list
+ {
+ "subscribers" : [ {
+ "hostID" : "testhost",
+ "partnerID" : "partner01",
+ "userID" : "user01",
+ "systemID" : null,
+ "demobankAccountLabel" : "not associated yet"
+ } ]
+ }
+
+Note that the output reflects the subscriber created in
+the ``ebicssubscriber create`` example (see above).
+
+
+sandbox ebicsbankaccount
+------------------------
+
+The ``ebicsbankaccount`` command manages EBICS bank accounts.
+It has one subcommand: create.
+(To list accounts, see ``sandbox bankaccount`` below.)
+
+sandbox ebicsbankaccount
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``ebicsbankaccount create`` command takes several options, all required:
+
+::
+
+ --iban TEXT IBAN
+ --bic TEXT BIC
+ --person-name TEXT bank account owner name
+ --account-name TEXT label of this bank account
+ --ebics-user-id TEXT user ID of the Ebics subscriber
+ --ebics-host-id TEXT host ID of the Ebics subscriber
+ --ebics-partner-id TEXT partner ID of the Ebics subscriber
+
+At this time, although the ``--person-name`` option is required,
+the sandbox does not remember the option value.
+(When queried, it displays "Bank account owner's name" instead.
+See ``sandbox bankaccount`` below.)
+For the sandbox, the important value is the ``--account-name`` option.
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-cli sandbox ebicsbankaccount create \
+ --iban DE18500105172929531888 \
+ --bic INGDDEFFXXX \
+ --person-name "Jane Normal" \
+ --account-name testacct01 \
+ --ebics-host-id testhost \
+ --ebics-user-id user01 \
+ --ebics-partner-id partner01
+
+Note that ``testhost`` is the same as in the ``ebicshost create``
+example, and that ``user01`` and ``partner01`` are the same as in the
+``ebicssubscriber create`` example (see above).
+
+
+sandbox bankaccount
+-------------------
+
+The ``bankaccount`` command manages bank accounts.
+It has several subcommands: list, generate-transactions,
+simulate-incoming-transaction, transactions.
+
+sandbox bankaccount list
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``bankaccount list`` command lists the bank accounts in the system.
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-cli sandbox bankaccount list
+ [ {
+ "label" : "bank",
+ "name" : "Bank account owner's name",
+ "iban" : "DE370758",
+ "bic" : "SANDBOXX"
+ }, {
+ "label" : "testacct01",
+ "name" : "Bank account owner's name",
+ "iban" : "DE18500105172929531888",
+ "bic" : "INGDDEFFXXX"
+ } ]
+
+Note that ``testacct01``, ``DE18500105172929531888``, and ``INGDDEFFXXX``
+are the same as specified in the ``ebicsbankaccount create`` example
+(see above).
+
+sandbox bankaccount generate-transactions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The remaining ``bankaccount`` commands deal with transactions
+to and from the bank accounts.
+
+The ``bankaccount generate-transactions`` command generates
+test transactions.
+It takes one arg, the account label.
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-cli sandbox bankaccount generate-transactions testacct01
+
+Note that ``testacct01`` is the account label shown in the ``bankaccount
+list`` example (see above).
+
+sandbox bankaccount simulate-incoming-transaction
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``bankaccount simulate-incoming-transaction`` books an
+incoming payment in the sandbox.
+It takes one arg, the account label, and several options.
+
+::
+
+ --debtor-iban TEXT IBAN sending the payment
+ --debtor-bic TEXT BIC sending the payment
+ --debtor-name TEXT name of the person who is sending the payment
+ --amount TEXT amount, no currency
+ --subject TEXT payment subject
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-cli sandbox bankaccount simulate-incoming-transaction
+ testacct01 \
+ --debtor-iban DE06500105174526623718 \
+ --debtor-bic INGDDEFFXXX \
+ --debtor-name "Joe Foo" \
+ --subject "Hello World" \
+ --amount 10.50
+
+Note that ``testacct01`` is the same as in previous examples (see above),
+and that ``10.50`` is in ``X.Y`` format.
+
+sandbox bankaccount transactions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``bankaccount transactions`` command lists transactions.
+It takes one arg, the account label.
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-cli sandbox bankaccount transactions testacct01
+ {
+ "payments" : [ {
+ "accountLabel" : "testacct01",
+ "creditorIban" : "DE18500105172929531888",
+ "creditorBic" : "INGDDEFFXXX",
+ "creditorName" : "Creditor Name",
+ "debtorIban" : "DE64500105178797276788",
+ "debtorBic" : "DEUTDEBB101",
+ "debtorName" : "Max Mustermann",
+ "amount" : "5",
+ "currency" : "EUR",
+ "subject" : "sample transaction DILWBJHL",
+ "date" : "Wed, 26 Jan 2022 09:03:44 GMT",
+ "creditDebitIndicator" : "credit",
+ "accountServicerReference" : "DILWBJHL",
+ "paymentInformationId" : null
+ }, {
+ "accountLabel" : "testacct01",
+ "creditorIban" : "DE64500105178797276788",
+ "creditorBic" : "DEUTDEBB101",
+ "creditorName" : "Max Mustermann",
+ "debtorIban" : "DE18500105172929531888",
+ "debtorBic" : "INGDDEFFXXX",
+ "debtorName" : "Debitor Name",
+ "amount" : "12",
+ "currency" : "EUR",
+ "subject" : "sample transaction N7JSY17B",
+ "date" : "Wed, 26 Jan 2022 09:03:44 GMT",
+ "creditDebitIndicator" : "debit",
+ "accountServicerReference" : "N7JSY17B",
+ "paymentInformationId" : null
+ }, {
+ "accountLabel" : "testacct01",
+ "creditorIban" : "DE18500105172929531888",
+ "creditorBic" : "INGDDEFFXXX",
+ "creditorName" : "Creditor Name",
+ "debtorIban" : "DE06500105174526623718",
+ "debtorBic" : "INGDDEFFXXX",
+ "debtorName" : "Joe Foo",
+ "amount" : "10.50",
+ "currency" : "EUR",
+ "subject" : "Hello World",
+ "date" : "Wed, 26 Jan 2022 09:04:31 GMT",
+ "creditDebitIndicator" : "credit",
+ "accountServicerReference" : "sandbox-6UI2J3636J9EESXO",
+ "paymentInformationId" : null
+ } ]
+ }
+
+Note that ``testacct01`` is the same as in previous examples (see above),
+and that the generated transactions from previous examples are listed,
+as well.
+
+
+sandbox demobank
+----------------
+
+The ``demobank`` command provides an interface to the Access API,
+which includes three commands: register, info, new-transaction.
+There is also a fourth ``demobank`` command, new-ebicssubscriber,
+that does not use the Access API.
+
+For all ``demobank`` commands, the sandbox URL *must* specify which
+*one* bank the command applies to in the base URL.
+Note that this URL cannot be used with other sandbox commands.
+In other words:
+
+``--sandbox-url http://localhost:5016/demobanks/default``
+ This base URL can be used for commands:
+
+ - sandbox demobank register
+ - sandbox demobank info
+ - sandbox demobank new-ebicssubscriber
+ - sandbox demobank new-transaction
+
+ It specifies the ``default`` demobank.
+
+``--sandbox-url http://localhost:5016``
+ This base URL can be used for all other sandbox commands.
+
+In the following examples, the base URL will be explicitly shown with
+the ``--sandbox-url`` option for the ``demobank`` commands.
+
+sandbox demobank register
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``demobank register`` command registers a new bank account.
+Note that the username will be both the username to login at
+the bank and the bank account label.
+It takes the username and password from the
+``LIBEUFIN_SANDBOX_USERNAME`` and ``LIBEUFIN_SANDBOX_PASSWORD``
+environment variables.
+The username *need not be* ``admin``.
+
+For example:
+
+.. code-block:: console
+
+ $ export LIBEUFIN_SANDBOX_USERNAME=jrluser
+ $ export LIBEUFIN_SANDBOX_PASSWORD=easy
+ $ libeufin-cli sandbox \
+ --sandbox-url http://localhost:5016/demobanks/default \
+ demobank register
+
+sandbox demobank info
+^^^^^^^^^^^^^^^^^^^^^
+
+The ``demobank info`` command returns basic information on a bank account.
+It takes option ``--bank-account NAME``.
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-cli sandbox \
+ --sandbox-url http://localhost:5016/demobanks/default \
+ demobank info --bank-account jrluser
+ {
+ "balance" : {
+ "amount" : "EUR:100",
+ "credit_debit_indicator" : "credit"
+ },
+ "paytoUri" : "payto://iban/SANDBOXX/DE948559?receiver-name=admin"
+ }
+
+Note that ``jrluser`` is the same username / bank account name
+as in the ``register`` example (see above).
+
+sandbox demobank new-ebicssubscriber
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``demobank new-ebicssubscriber`` command associates a new Ebics
+subscriber to an existing bank account.
+It takes several options, all required:
+
+::
+
+ --host-id TEXT Ebics host ID
+ --partner-id TEXT Ebics partner ID
+ --user-id TEXT Ebics user ID
+ --bank-account TEXT Label of the bank account to associate
+ with this Ebics subscriber
+
+For example:
+
+.. code-block: console
+
+ $ libeufin-cli sandbox \
+ --sandbox-url http://localhost:5016/demobanks/default \
+ demobank new-ebicssubscriber \
+ --host-id testhost \
+ --partner-id partner01 \
+ --user-id user02 \
+ --bank-account jrluser
+
+Note that ``testhost`` is the same as in the ``ebicshost create``
+example, and that ``partner01`` is the same as in the
+``ebicssubscriber create`` example (see above).
+The ``user02`` is new.
+The ``--bank-account jrluser`` is the same as in the
+``info`` example (see above).
+You can see the effect of the ``new-ebicssubscriber`` command
+with the ``sandbox ebicssubscriber list``
+and ``sandbox bankaccount list`` commands.
+
+sandbox demobank new-transaction
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``demobank new-transaction`` command initiates a new transaction.
+It takes several options, all required:
+
+::
+
+ --bank-account TEXT Label of the bank account to be
+ debited for the transaction
+ --payto-with-subject TEXT Payto address including the
+ subject as a query parameter
+ --amount CUR:X.Y Amount to transfer
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-cli sandbox \
+ --sandbox-url http://localhost:5016/demobanks/default \
+ demobank new-transaction \
+ --bank-account jrluser \
+ --payto-with-subject 'payto://FIXME/?message=1kg+coffee' \
+ --amount EUR:10.50
+ FIXME: Any output?
+
+Note that ``--bank-account jrluser`` is the same as in the
+``info`` and ``new-ebicssubscriber`` command examples (see above).
+
+
+connections
+-----------
+
+The ``connections`` set of commands handle connections between
+the bank(s) and Nexus.
+It has several subcommands:
+new-ebics-connection,
+list-connections,
+show-connection,
+delete-connection,
+export-backup,
+restore-backup,
+get-key-letter,
+connect,
+list-offered-bank-accounts,
+download-bank-accounts,
+import-bank-account.
+
+Generally, you will create a connection, save its critical key information
+to a safe location, then use the connection to find and import a bank
+account, for further use.
+
+Several commands take a ``CONNECTION_NAME`` argument.
+In the following examples, we use ``conn01`` for that.
+Also, for demonstration purposes, we use the sandbox EBICS services,
+so the ``EBICS_URL`` follows the previous examples in the ``sandbox``
+command, as the value of environment variable ``LIBEUFIN_SANDBOX_URL``
+suffixed with ``/ebicsweb``, i.e., ``http://localhost:5016/ebicsweb``.
+
+connections new-ebics-connection
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``connections new-ebics-connection`` command creates a new connection
+between an EBICS service and the Nexus.
+It takes one arg, the ``CONNECTION_NAME``, and four required options:
+
+::
+
+ --ebics-url TEXT EBICS URL
+ --host-id TEXT Host ID
+ --partner-id TEXT Partner ID
+ --ebics-user-id TEXT Ebics user ID
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-cli connections new-ebics-connection \
+ --ebics-url http://localhost:5016/ebicsweb \
+ --host-id testhost \
+ --partner-id partner01 \
+ --ebics-user-id user02 \
+ conn01
+
+Note that the ``testhost``, ``partner01``, and ``user02`` are the same as
+in the ``sandbox demobank new-ebicssubscriber`` command (see above).
+
+connections list-connections
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``connections list-connections`` command lists connections in Nexus.
+For example:
+
+.. code-block:: console
+
+ $ libeufin-cli connections list-connections
+ {
+ "bankConnections" : [ {
+ "name" : "conn01",
+ "type" : "ebics"
+ } ]
+ }
+
+The name of the connection is ``conn01`` as in the
+``connections new-ebics-connection`` example (see above).
+
+connections show-connection
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``connections show-connection`` command displays information
+about a specific connection.
+It takes one argument, the ``CONNECTION_NAME``.
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-cli connections show-connection conn01
+ {
+ "type" : "ebics",
+ "owner" : "foo",
+ "ready" : true,
+ "details" : {
+ "ebicsUrl" : "http://localhost:5016/ebicsweb",
+ "ebicsHostId" : "testhost",
+ "partnerId" : "partner01",
+ "userId" : "user02"
+ }
+ }
+
+The details are the same as in the ``connections new-ebics-connections``
+example (see above).
+
+connections delete-connection
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``connections delete-connection`` command deletes a bank connection.
+It takes one argument, the ``CONNECTION_NAME``.
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-cli connections delete-connection conn01
+
+connections export-backup
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``connections export-backup`` command writes key and signature
+information to a backup file (which you should take care to store
+in a secure location).
+It takes one argument, the ``CONNECTION_NAME`` and two required options:
+
+::
+
+ --passphrase TEXT Passphrase for locking the backup
+ --output-file TEXT Where to store the backup
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-cli connections export-backup \
+ --passphrase secret \
+ --output-file sig-and-key-info \
+ conn01
+ FIXME: Output?
+
+See: https://bugs.gnunet.org/view.php?id=7180
+
+connections restore-backup
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+WRITEME
+
+connections get-key-letter
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``connections get-key-letter`` command creates a PDF file
+that contains key information.
+It takes two arguments, ``CONNECTION_NAME`` and ``OUTPUT_FILE``.
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-cli connections get-key-letter conn01 key-letter.pdf
+
+This creates file ``key-letter.pdf`` in the current working directory.
+
+connections connect
+^^^^^^^^^^^^^^^^^^^
+
+WRITEME
+
+connections list-offered-bank-accounts
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+WRITEME
+
+connections download-bank-accounts
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+WRITEME
+
+connections import-bank-account
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+WRITEME
+
+
+users
+-----
+
+The ``libeufin-cli users`` command manages users authorized to
+operate Nexus.
+It has several subcommands: self, list, create, change-password.
+The ``create`` and ``change-password`` commands can only be issued
+by the superuser
+(as configured by the ``libeufin-nexus superuser`` command),
+while the ``self`` and ``list`` commands can be issued by any user.
+
+In the following ``users`` examples, we assume that previously
+the command ``libeufin-nexus superuser foo`` was issued, and
+that the current username and password are for that user
+(via environment variables ``LIBEUFIN_NEXUS_USERNAME`` and
+``LIBEUFIN_NEXUS_PASSWORD``, see above).
+
+users self
+^^^^^^^^^^
+
+The ``users self`` command displays information for the current user.
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-cli users self
+ {
+ "username" : "foo",
+ "superuser" : true
+ }
+
+users list
+^^^^^^^^^^
+
+The ``users list`` command displays information for all the
+users authorized to operate Nexus.
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-cli users list
+ {
+ "users" : [ {
+ "username" : "foo",
+ "superuser" : true
+ } ]
+ }
+
+In this example, there is only one user, the superuser ``foo``.
+
+users create
+^^^^^^^^^^^^
+
+The ``users create`` command creates a normal (non-superuser) user.
+It takes one argument, the ``USERNAME`` and one option,
+``--password TEXT``.
+If you omit the option, **libeufin-cli** will prompt you for the password.
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-cli users create --password easy jrluser
+ {
+ "message" : "New user 'jrluser' registered"
+ }
+ $ libeufin-cli users list
+ {
+ "users" : [ {
+ "username" : "foo",
+ "superuser" : true
+ }, {
+ "username" : "jrluser",
+ "superuser" : false
+ } ]
+ }
+
+In this example, we create the same user as for the sandbox examples
+(see above).
+Note that the system now includes two users.
+
+users change-password
+^^^^^^^^^^^^^^^^^^^^^
+
+The ``users change-password`` command changes the password for a user.
+It takes one argument, the ``USERNAME`` and one option,
+``--new-password TEXT``.
+If you omit the option, **libeufin-cli** will prompt you for the password.
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-cli users change-password --new-password hard jrluser
+ {
+ "message" : "Password successfully changed"
+ }
+
+
+permissions
+-----------
+
+The ``libeufin-cli permissions`` command manages permissions
+for operations on Nexus.
+It has three subcommands: list, grant, revoke.
+All three commands can only be issued by the superuser.
+
+permissions list
+^^^^^^^^^^^^^^^^
+
+The ``permissions list`` command lists the granted permissions.
+At the beginning of a session, there are none:
+
+.. code-block:: console
+
+ $ libeufin-cli permissions list
+ {
+ "permissions" : [ ]
+ }
+
+
+permissions grant
+^^^^^^^^^^^^^^^^^
+
+The ``permissions grant`` command adds a permission to the list
+of granted permissions.
+It takes five arguments: ``SUBJECT_TYPE``, ``SUBJECT_ID``,
+``RESOURCE_TYPE``, ``RESOURCE_ID``, ``PERMISSION_NAME``.
+
+FIXME: The subject type and id, resource type and id, are ...
+
+The ``PERMISSION_NAME`` is one of the following:
+
+- ``facade.talerwiregateway.history``
+- ``facade.talerwiregateway.transfer``
+- ``facade.anastasis.history``
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-cli permissions grant \
+ some-subject-type some-subject-id \
+ some-resource-type some-resource-id \
+ facade.anastasis.history
+ { }
+ $ libeufin-cli permissions list
+ {
+ "permissions" : [ {
+ "subjectType" : "some-subject-type",
+ "subjectId" : "some-subject-id",
+ "resourceType" : "some-resource-type",
+ "resourceId" : "some-resource-id",
+ "permissionName" : "facade.anastasis.history"
+ } ]
+ }
+
+permissions revoke
+^^^^^^^^^^^^^^^^^^
+
+The ``permissions revoke`` command does the opposite of the
+``permissions grant`` command.
+It takes the same arguments as the ``permissions grant`` command:
+``SUBJECT_TYPE``, ``SUBJECT_ID``, ``RESOURCE_TYPE``, ``RESOURCE_ID``,
+``PERMISSION_NAME``.
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-cli permissions revoke \
+ some-subject-type some-subject-id \
+ some-resource-type some-resource-id \
+ facade.anastasis.history
+ { }
+ $ libeufin-cli permissions list
+ {
+ "permissions" : [ ]
+ }
+
+This example undoes the effect of the previous (``permissions grant``) example.
+
+
+accounts
+--------
+
+WRITEME
+
+accounts transactions
+^^^^^^^^^^^^^^^^^^^^^
+
+WRITEME
+
+accounts task-status
+^^^^^^^^^^^^^^^^^^^^
+
+WRITEME
+
+accounts task-schedule
+^^^^^^^^^^^^^^^^^^^^^^
+
+WRITEME
+
+accounts task-delete
+^^^^^^^^^^^^^^^^^^^^
+
+WRITEME
+
+accounts submit-payment
+^^^^^^^^^^^^^^^^^^^^^^^
+
+WRITEME
+
+accounts show-payment
+^^^^^^^^^^^^^^^^^^^^^
+
+WRITEME
+
+accounts show
+^^^^^^^^^^^^^
+
+WRITEME
+
+accounts prepare-payment
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+WRITEME
+
+accounts list-tasks
+^^^^^^^^^^^^^^^^^^^
+
+WRITEME
+
+accounts list-payments
+^^^^^^^^^^^^^^^^^^^^^^
+
+WRITEME
+
+accounts fetch-transactions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+WRITEME
+
+accounts delete-payment
+^^^^^^^^^^^^^^^^^^^^^^^
+
+WRITEME
+
+
+facades
+-------
+
+WRITEME
+
+facades new-taler-wire-gateway-facade
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+WRITEME
+
+facades new-anastasis-facade
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+WRITEME
+
+facades list
+^^^^^^^^^^^^
+
+WRITEME
+
+
+See Also
+========
+
+.. TODO: libeufin-sandbox(1), libeufin-cli(1).
+
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/libeufin-nexus.1.rst b/manpages/libeufin-nexus.1.rst
new file mode 100644
index 0000000..d1a0698
--- /dev/null
+++ b/manpages/libeufin-nexus.1.rst
@@ -0,0 +1,150 @@
+libeufin-nexus(1)
+#################
+
+.. only:: html
+
+ Name
+ ====
+
+ **libeufin-nexus** - Sevice to interface to various bank access APIs
+
+
+Synopsis
+========
+
+**libeufin-nexus**
+[**-h** | **--help**]
+[**--version**]
+COMMAND [ARGS...]
+
+Commands: serve, superuser, parse-camt, reset-tables
+
+
+Description
+===========
+
+**libeufin-nexus** is a program that provides a service to interface to
+various bank access APIs, using JSON as the response format.
+It maintains state in its own private database.
+You interact with it through HTTP
+requests either over the network or via a Unix domain socket.
+Related program **libeufin-cli** is the preferred front end
+for that mode of operation.
+There is also a mode where **libeufin-nexus** accepts commands directly,
+useful for doing administrative tasks.
+
+Its options are as follows:
+
+**-h** \| **--help**
+ Print short help on options.
+
+**–version**
+ Print version information.
+
+The interaction model is as follows:
+
+- Configure the nexus with command ``superuser``.
+
+- Start the HTTP server with command ``serve``.
+ Let this run in a shell, writing logs to stderr.
+
+- Interact with **libeufin-nexus**.
+
+- When finished, interrupt the ``serve`` process and clean up with command
+ ``reset-tables``.
+
+The following sections describe each command in detail.
+
+
+superuser
+---------
+
+This command adds a superuser, or changes the password.
+It takes argument ``USERNAME``.
+Option ``--password TEXT`` specifies the password.
+If omitted, **libeufin-nexus** will query interactively for it.
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-nexus superuser joe
+
+This creates superuser ``joe`` and interactively queries for the password.
+
+
+parse-camt
+----------
+
+This command parses a camt file and displays the result to stdout.
+It takes argument ``FILENAME``, which names a file in CAMT format.
+Parsing may also display log information to stderr.
+The normal log level is ``DEBUG``.
+To change it, use ``--log-level LEVEL``, where ``LEVEL`` is one of:
+``ERROR``, ``WARN``, ``INFO``, ``DEBUG``, ``TRACE``.
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-nexus parse-camt camt53-gls-style-0.xml
+ {
+ "transactions" : [ {
+ "amount" : "EUR:2.35",
+ "creditDebitIndicator" : "DBIT",
+ ...
+ } ]
+ }
+
+
+serve
+-----
+
+This command starts the HTTP server, listening on port 5001.
+To use a different port, use option ``--port INT``.
+To listen, instead, on a Unix domain socket,
+use option ``--with-unix-socket PATH``.
+When both ``--port`` and ``--with-unix-socket`` are given,
+``--with-unix-socket`` takes precedence.
+
+The process runs in the foreground, writing its logs to standard error.
+The normal log level is ``DEBUG``.
+To change it, use ``--log-level LEVEL``, where ``LEVEL`` is one of:
+``ERROR``, ``WARN``, ``INFO``, ``DEBUG``, ``TRACE``.
+
+Before invoking ``serve``, the following environment variable needs to be set:
+
+``LIBEUFIN_NEXUS_DB_CONNECTION``
+ This specifies the database **libeufin-nexus** uses to maintain state.
+ Currently, both Sqlite and PostgreSQL are supported.
+ (Only one needs to be specified.)
+ Examples:
+
+ - ``jdbc:sqlite:/tmp/libeufin-nexus.db``
+ - ``jdbc:postgresql://localhost:5432/libeufindb?user=Foo&password=secret``
+
+Normally, the ``serve`` command runs until interrupted.
+When run in a shell, you can use ``Control-C`` for that.
+
+
+reset-tables
+------------
+
+This command drops all the tables in the internal database.
+(The next time the tables are needed, **libeufin-nexus** creates them
+again, automatically.)
+
+It should only be used when the nexus is quiescent.
+
+
+See Also
+========
+
+.. TODO: libeufin-sandbox(1), libeufin-cli(1).
+
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/libeufin-sandbox.1.rst b/manpages/libeufin-sandbox.1.rst
new file mode 100644
index 0000000..fc1c7f3
--- /dev/null
+++ b/manpages/libeufin-sandbox.1.rst
@@ -0,0 +1,218 @@
+libeufin-sandbox(1)
+###################
+
+.. only:: html
+
+ Name
+ ====
+
+ **libeufin-sandbox** - Simulate a banking system core
+ with EBICS access to bank accounts
+
+
+Synopsis
+========
+
+**libeufin-sandbox**
+[**-h** | **--help**]
+[**--version**]
+COMMAND [ARGS...]
+
+Commands: serve, reset-tables, config, make-transaction, camt053tick
+default-exchange
+
+
+Description
+===========
+
+**libeufin-sandbox** is a program to simulate a banking system core
+with EBICS access to bank accounts.
+It maintains state in its own private database.
+You interact with it through HTTP
+requests either over the network or via a Unix domain socket.
+Related program **libeufin-cli** is the preferred front end
+for that mode of operation.
+There is also a mode where **libeufin-sandbox** accepts commands directly,
+useful for configuring one or more "demobank" (simulated bank) instances.
+
+Its options are as follows:
+
+**-h** \| **--help**
+ Print short help on options.
+
+**–version**
+ Print version information.
+
+The interaction model is as follows:
+
+.. @MS Is the order of the first two steps correct?
+ Or are some of the commands to be used AFTER ‘serve’ starts?
+ Or is it a mix? (I believe it is a mix, but am not sure.)
+
+- Configure the sandbox with commands ``config``, ``default-exchange``,
+ ``make-transaction``, and ``camt053tick``.
+
+- Start the HTTP server with command ``serve``.
+ Let this run in a shell, writing logs to stderr.
+
+- Point program **libeufin-nexus** at the sandbox.
+
+- Interact with **libeufin-nexus**.
+
+- When finished, interrupt the ``serve`` process and clean up with command
+ ``reset-tables``.
+
+The following sections describe each command in detail.
+
+
+config
+------
+
+This command takes argument ``NAME`` and creates a demobank with that name.
+
+Option ``--currency CUR`` (default: ``EUR``) specifes another currency.
+Option ``--bank-debt-limit N`` (default: 1000000) specifies that
+the bank debt limit should be N (units of currency).
+Similarly, option ``--users-debt-limit N`` (default: 1000) specifies
+that the users debt limit should be N (units of currency).
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-sandbox config default
+
+This creates the demobank ``default`` with currency ``EUR``,
+bank debt limit 1000000, users debt limit 1000,
+and allows registrations.
+
+
+default-exchange
+----------------
+
+This command sets the exchange that a demobank will suggest to wallets.
+(Wallets are of course free to disregard the suggestion and choose
+another exchange.)
+It requires two arguments, ``EXCHANGE-BASEURL`` and ``EXCHANGE-PAYTO``.
+The option ``--demobank NAME`` (default: ``default``) specifies
+which demobank this setting affects.
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-sandbox default-exchange \
+ --demobank bank01 \
+ https://exchange.example.com/ \
+ payto://iban/CH9300762011623852957
+
+This sets the default exchange for demobank ``bank01``.
+It is an error if the demobank does not exist.
+
+
+make-transaction
+----------------
+
+This is a "legacy" command, useful in a previous iteration of LibEuFin
+and for internal testing.
+It creates and records a wire transfer transaction in the database.
+
+It takes two arguments and several required options.
+The arguments are ``AMOUNT``, in ``CUR:X.Y`` format;
+and ``SUBJECT``, a short textual description of the transaction.
+The options are: ``--credit-account LABEL`` and ``--debit-account LABEL``,
+where each LABEL names a bank account for receiving and issuing,
+respectively, the wire transfer.
+The option ``--demobank NAME`` (default: ``default``) specifies
+in which demobank the wire transfer occurs.
+
+.. note::
+
+ If you have not yet called ``config``, this command creates
+ a demobank named ``default`` on its first use. The currency,
+ and bank debt limit have the same defaults as for the ``config``
+ command. The users debt limit, however, defaults to 10000.
+
+FIXME: How to achieve the same result with **libeufin-cli**?
+
+
+camt053tick
+-----------
+
+This command advances the internal time step that the demobank
+uses to group transactions for reporting.
+(Successive transactions will be inserted in a new Camt.053 report.)
+
+For example:
+
+.. code-block:: console
+
+ $ libeufin-sandbox camt053tick
+
+FIXME: How to achieve the same result with **libeufin-cli**?
+
+
+serve
+-----
+
+This command starts the HTTP server, listening on port 5000.
+To use a different port, use option ``--port INT``.
+To listen, instead, on a Unix domain socket,
+use option ``--with-unix-socket PATH``.
+When both ``--port`` and ``--with-unix-socket`` are given,
+``--with-unix-socket`` takes precedence.
+
+.. note::
+
+ If you have not yet called ``config``, this command creates
+ a demobank named ``default`` on its first use. The currency,
+ and bank debt limit have the same defaults as for the ``config``
+ command. The users debt limit, however, defaults to 10000.
+
+The process runs in the foreground, writing its logs to standard error.
+The normal log level is ``DEBUG``.
+To change it, use ``--log-level LEVEL``, where ``LEVEL`` is one of:
+``ERROR``, ``WARN``, ``INFO``, ``DEBUG``, ``TRACE``.
+
+Before invoking ``serve``, the following environment variables need to be set:
+
+``LIBEUFIN_SANDBOX_ADMIN_PASSWORD``
+ The password required for later use by **libeufin-cli**.
+ For testing purposes, you can use option ``--no-auth`` to disable
+ this requirement.
+ (In that case, this environment variable need not be set.)
+
+``LIBEUFIN_SANDBOX_DB_CONNECTION``
+ This specifies the database **libeufin-sandbox** uses to maintain state.
+ Currently, both Sqlite and PostgreSQL are supported.
+ (Only one needs to be specified.)
+ Examples:
+
+ - ``jdbc:sqlite:/tmp/libeufin-sandbox.db``
+ - ``jdbc:postgresql://localhost:5432/libeufindb?user=Foo&password=secret``
+
+Normally, the ``serve`` command runs until interrupted.
+When run in a shell, you can use ``Control-C`` for that.
+
+
+reset-tables
+------------
+
+This command drops all the tables in the internal database.
+(The next time the tables are needed, **libeufin-sandbox** creates them
+again, automatically.)
+
+It should only be used when the sandbox is quiescent.
+
+
+See Also
+========
+
+.. TODO: libeufin-nexus(1), libeufin-cli(1).
+
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/sync-config.1.rst b/manpages/sync-config.1.rst
index 14c61a0..c7dd9ea 100644
--- a/manpages/sync-config.1.rst
+++ b/manpages/sync-config.1.rst
@@ -35,7 +35,7 @@ Description
**-b** *BACKEND* \| **--supported-backend=**\ \ *BACKEND*
Tests whether the specified *BACKEND* is supported by the current installation.
The backend must match the name of a plugin, i.e. "namestore_postgres" for
- the Postgres database backend of the "NAMESTORE" service. If *BACKEND* is
+ the PostgreSQL database backend of the "NAMESTORE" service. If *BACKEND* is
supported, sync-config will return a status code of 0 (success), otherwise
77 (unsupported). When this option is specified, no other options may be
specified. Specifying this option together with other options will cause
diff --git a/manpages/taler-config.1.rst b/manpages/taler-config.1.rst
index 103c95e..14a8959 100644
--- a/manpages/taler-config.1.rst
+++ b/manpages/taler-config.1.rst
@@ -35,7 +35,7 @@ Description
**-b** *BACKEND* \| **--supported-backend=**\ \ *BACKEND*
Tests whether the specified *BACKEND* is supported by the current installation.
The backend must match the name of a plugin, i.e. "namestore_postgres" for
- the Postgres database backend of the "NAMESTORE" service. If *BACKEND* is
+ the PostgreSQL database backend of the "NAMESTORE" service. If *BACKEND* is
supported, taler-config will return a status code of 0 (success), otherwise
77 (unsupported). When this option is specified, no other options may be
specified. Specifying this option together with other options will cause
diff --git a/manpages/taler-exchange-offline.1.rst b/manpages/taler-exchange-offline.1.rst
index 18d5399..265324e 100644
--- a/manpages/taler-exchange-offline.1.rst
+++ b/manpages/taler-exchange-offline.1.rst
@@ -255,13 +255,13 @@ format suitable for the ``upload`` subcommand.
wire-fee
--------
-This subcommand informs an exchange about the desired wire fee (and closing fee)
-structure for particular wire method and a calendar year (!). The tool does not
+This subcommand informs an exchange about the desired wire fee structure (that is, wire, closing and wad fees)
+for particular wire method and a calendar year (!). The tool does not
permit changing wire fees during a calendar year. Also, once the wire fee has been
set for a calendar year, it cannot be changed.
The subcommand takes the year, wire-method (see RFC 8905, examples include
-``x-taler-bank`` or ``iban``), wire fee and closing fee as arguments.
+``x-taler-bank`` or ``iban``), wire fee, closing fee and wad fee as arguments.
Instead of a year, the string ``now`` can be given for the current year
(this is mostly useful for test cases). The wire-method should follow the
GANA registry as given in RFC 8905. The fees must be given in the usual
@@ -273,6 +273,26 @@ It outputs the signature affirming the wire fees, in a format suitable for the
``upload`` subcommand.
+global-fee
+----------
+
+This subcommand informs an exchange about the desired global fee structure and
+related global configuration options for a calendar year (!). The tool does
+not permit changing global fees during a calendar year. Also, once the global
+fee structure has been set for a calendar year, it cannot be changed.
+
+The subcommand takes the year, history fee, kyc fee, account fee, purse fee,
+purse timeout, kyc timeout, history expiration and the (free) purse (per)
+account limit as arguments. Instead of a year, the string ``now`` can be
+given for the current year (this is mostly useful for test cases). The fees
+must be given in the usual Taler format of ``CURRENCY:NUMBER.FRACTION``.
+
+The subcommand takes no inputs from ``stdin`` or other subcommands.
+
+It outputs the signature affirming the global fees, in a format suitable for
+the ``upload`` subcommand.
+
+
enable-partner
--------------
diff --git a/manpages/taler-exchange-secmod-cs.1.rst b/manpages/taler-exchange-secmod-cs.1.rst
new file mode 100644
index 0000000..b75ce31
--- /dev/null
+++ b/manpages/taler-exchange-secmod-cs.1.rst
@@ -0,0 +1,76 @@
+taler-exchange-secmod-cs(1)
+###########################
+
+.. only:: html
+
+ Name
+ ====
+
+ **taler-exchange-secmod-cs** - handle private Clause-Schnorr key operations for a Taler exchange
+
+
+Synopsis
+========
+
+**taler-exchange-secmod-cs**
+[**-c** *FILENAME* | **--config=**\ \ *FILENAME*]
+[**-h** | **--help**]
+[**-L** *LOGLEVEL* | **--loglevel=**\ ‌\ *LOGLEVEL*]
+[**-l** *FILENAME* | **--logfile=**\ ‌\ *FILENAME*]
+[**-p** *N* | ,**--parallelism=**\ \ *N*]
+[**-T** *USEC* | **--timetravel=**\ \ *USEC*]
+[**-t** *TIMESTAMP* | **--time=**\ \ *TIMESTAMP*]
+[**-v** | **--version**]
+
+
+Description
+===========
+
+**taler-exchange-secmod-cs** is a command-line tool to
+handle private Clause-Schnorr key operations for a Taler exchange.
+
+FIXME: More details.
+
+Its options are as follows:
+
+**-c** *FILENAME* \| **--config=**\ ‌\ *FILENAME*
+ Use the configuration and other resources for the merchant to operate
+ from *FILENAME*.
+
+**-h** \| **--help**
+ Print short help on options.
+
+**-L** *LOGLEVEL* \| **--loglevel=**\ ‌\ *LOGLEVEL*
+ Specifies the log level to use. Accepted values are: ``DEBUG``, ``INFO``,
+ ``WARNING``, ``ERROR``.
+
+**-l** *FILENAME* \| **--logfile=**\ ‌\ *FILENAME*
+ Send logging output to *FILENAME*.
+
+**p** *N* \| **--parallelism=**\ \ *N*
+ Run with *N* worker threads.
+
+**-T** *USEC* \| **--timetravel=**\ \ *USEC*
+ Modify the system time by *USEC* microseconds.
+ *USEC* may be prefixed with ``+`` or ``-`` (e.g. ``-T +300``).
+ This option is intended for debugging/testing only.
+
+**-t** *TIMESTAMP* \| **--time=**\ \ *TIMESTAMP*
+ Pretend it is *TIMESTAMP* for the update.
+ *TIMESTAMP* is a human-readable string (e.g., ``YYYY-MM-DD HH:MM:SS``).
+
+**-v** \| **--version**
+ Print version information.
+
+
+See Also
+========
+
+taler-exchange-httpd(1).
+
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/taler-fakebank-run.1.rst b/manpages/taler-fakebank-run.1.rst
index eb60834..590b4b6 100644
--- a/manpages/taler-fakebank-run.1.rst
+++ b/manpages/taler-fakebank-run.1.rst
@@ -24,6 +24,8 @@ Description
**taler-fakebank-run** is a command-line tool to run a Taler "bank" API (HTTP REST service). The program is useful to provide the bank functionality for benchmarking or testing when LibEuFin is unavailable or otherwise unsuitable.
+It should be noted that the fakebank will keep a configured number of transactions in memory. If the number of transactions exceeds the configured memory limit, the fakebank will simply discard and overwrite the old entries. At that point, any requests involving such overwritten transactions will fail. Users of the fakebank are responsible for ensuring that the transaction history kept in memory is long enough for the purpose the bank is used for. The default limit is 128k entries.
+
Its options are as follows:
**-C** \| **--connection-close**
diff --git a/manpages/taler.conf.5.rst b/manpages/taler.conf.5.rst
index a671ffd..76b1c6b 100644
--- a/manpages/taler.conf.5.rst
+++ b/manpages/taler.conf.5.rst
@@ -1,4 +1,4 @@
-taler.conf(5)
+it putaler.conf(5)
#############
.. only:: html
@@ -175,7 +175,10 @@ EXCHANGE KYC OAUTH2 OPTIONS
The following options must be in the section "[exchange-kyc-oauth2]".
-KYC_OAUTH2_URL
+KYC_OAUTH2_AUTH_URL
+ URL of the OAuth2 endpoint to be used for KYC checks. Requires KYC_ENABLED to be "OAUTH2". Example: "http://localhost:8888/oauth/v2/login" (or "/token")
+
+KYC_OAUTH2_LOGIN_URL
URL of the OAuth2 endpoint to be used for KYC checks. Requires KYC_ENABLED to be "OAUTH2". Example: "http://localhost:8888/oauth/v2/login"
KYC_INFO_URL
@@ -247,6 +250,34 @@ Note that the **taler-exchange-secmod-rsa** also evaluates the ``[coin_*]``
configuration sections described below.
+EXCHANGE CS CRYPTO HELPER OPTIONS
+---------------------------------
+
+The following options must be in the section "[taler-exchange-secmod-cs]".
+
+LOOKAHEAD_SIGN
+ How long do we generate denomination and signing keys ahead of time?
+
+OVERLAP_DURATION
+ How much should validity periods for coins overlap?
+ Should be long enough to avoid problems with
+ wallets picking one key and then due to network latency
+ another key being valid. The ``DURATION_WITHDRAW`` period
+ must be longer than this value.
+
+SM_PRIV_KEY
+ Where should the security module store its long-term private key?
+
+KEY_DIR
+ Where should the security module store the private keys it manages?
+
+UNIXPATH
+ On which path should the security module listen for signing requests?
+
+Note that the **taler-exchange-secmod-cs** also evaluates the ``[coin_*]``
+configuration sections described below.
+
+
EXCHANGE EDDSA CRYPTO HELPER OPTIONS
------------------------------------
@@ -288,6 +319,10 @@ IDLE_RESERVE_EXPIRATION_TIME
LEGAL_RESERVE_EXPIRATION_TIME
After what time do we forget about (drained) reserves during garbage collection?
+AGGREGATOR_SHIFT
+ Delay between a deposit being eligible for aggregation and
+ the aggregator actually triggering.
+
EXCHANGE POSTGRES BACKEND DATABASE OPTIONS
------------------------------------------
@@ -390,8 +425,14 @@ FEE_REFUND
What fee is charged for refunds? When a coin is refunded, the deposit
fee is returned. Instead, the refund fee is charged to the customer.
+CIPHER
+ What cryptosystem should be used? Must be set to either "CS" or "RSA".
+ The respective crypto-helper will then generate the keys for this
+ denomination.
+
RSA_KEYSIZE
- What is the RSA keysize modulos (in bits)?
+ What is the RSA keysize modulos (in bits)? Only used if "CIPHER=RSA".
+
MERCHANT OPTIONS
----------------
@@ -505,6 +546,18 @@ CONFIG
"taler" database. Testcases use “talercheck”.
+Bank Options
+------------
+
+The following options must be in section "[bank]" for the taler-fakebank-run(1) command. They are not used by the exchange or LibEuFin!
+
+HTTP_PORT
+ On which TCP port should the (fake)bank offer its REST API.
+RAM_LIMIT
+ This gives the number of transactions to keep in memory. Older transactions will be overwritten and history requests for overwritten transactions will fail.
+
+
+
SEE ALSO
========
diff --git a/taler-auditor-manual.rst b/taler-auditor-manual.rst
index cf3952f..e7aecb8 100644
--- a/taler-auditor-manual.rst
+++ b/taler-auditor-manual.rst
@@ -65,7 +65,7 @@ all, the goal is to detect nerfarious activity of the exchange operator,
which cannot be effectively done on a machine controlled by the exchange
operator.
-For this, every auditor needs to operate a Postgres database. The data
+For this, every auditor needs to operate a PostgreSQL database. The data
collected will include sensitive information about Taler users, including
withdrawals made by consumers and income received by merchants. As a result,
the auditor is expected to provide high confidentiality for the database. In
@@ -118,7 +118,7 @@ third parties to verify one's own work.
The Taler software stack for an auditor consists of the following
components:
-- DBMS: Postgres
+- DBMS: PostgreSQL
The auditor requires a DBMS to store a local copy of the transaction history for
the Taler exchange, as well as for its own internal bookkeeping and checkpointing.
@@ -128,7 +128,7 @@ components:
concern that must be addressed manually. The software only verifies the content
of a well-formed exchange database (well-formed with respect to SQL).
For now, the GNU Taler reference implementation
- only supports Postgres, but the code could be easily extended to
+ only supports PostgreSQL, but the code could be easily extended to
support another DBMS.
- The auditor Web service
@@ -268,7 +268,7 @@ Additionally, there are two canonical system users of relevance (which your
distribution would typically create for you):
* www-data --- runs the HTTPS frontend (usually nginx or Apache)
- * postgres --- runs the Postgres database
+ * postgres --- runs the PostgreSQL database
Databases and users
@@ -585,7 +585,7 @@ as illustrated in the following figure:
.. image:: replication.png
-First, the exchange should use standard Postgres replication features to
+First, the exchange should use standard PostgreSQL replication features to
enable the auditor to obtain a full copy of the exchange's database.
Second, the auditor should make a "trusted" local copy, ensuring that it
never replicates malicious changes using ``taler-auditor-sync``. Both
@@ -595,7 +595,7 @@ We note that as a result of these steps, the auditor will have three
databases: its own production primary database (as configured in
``auditordb-postgres``), its on production copy of the exchange's database
(``exchangedb-postgress``), and a third, untrusted "ingres" copy of the
-exchange database. The untrusted database should run as a separate Postgres
+exchange database. The untrusted database should run as a separate PostgreSQL
instance and is only accessed via ``taler-auditor-sync`` and the replication
mechanism driven by the exchange operator.
@@ -607,7 +607,7 @@ Ingres operation should be done using the ``auditor-ingres`` user --- or
depending on the setup parts of the operation may be done by the ``postgres``
user directly.
-The full copy can be obtained in various ways with Postgres. It is
+The full copy can be obtained in various ways with PostgreSQL. It is
possible to use log shipping with streaming replication as described
in https://www.postgresql.org/docs/13/warm-standby.html, or to use
logical replication, as described in
@@ -616,7 +616,7 @@ that asynchronous replication should suffice.
The resulting auditor database should be treated as read-only on the auditor
side. The ``taler-exchange-dbinit`` tool can be used to setup the schema, or
-the schema can be replicated using Postgres's standard mechanisms. The same
+the schema can be replicated using PostgreSQL's standard mechanisms. The same
applies for schema upgrades: if logical replication is used (which does not
replicate schema changes), ``taler-exchange-dbinit`` can be used to migrate
the schema(s) in both the ingres and production copies of the exchange's
@@ -640,7 +640,7 @@ Wireguard.
It is also necessary to edit ``main.cf`` of the exchange and on the auditor
side to enable logical replication. If an exchange has multiple auditors, it
should setup multiple ``egress`` accounts. The exchange must ensure that
-the following lines are in the ``main.cf`` Postgres configuration (the port
+the following lines are in the ``main.cf`` PostgreSQL configuration (the port
may differ) to enable replication over the network:
.. code-block::
@@ -650,7 +650,7 @@ may differ) to enable replication over the network:
wal_level= logical
Equally, the auditor must configure logical replication in the ``main.cf``
-Postgres configuration:
+PostgreSQL configuration:
.. code-block::
@@ -677,7 +677,7 @@ system must subscribe:
$ echo "CREATE PUBLICATION $NAME FOR ALL TABLES;" | psql taler-exchange
-For details, we refer to the Postgres manual.
+For details, we refer to the PostgreSQL manual.
.. note::
@@ -686,9 +686,9 @@ For details, we refer to the Postgres manual.
``DROP`` operations on the tables. Hence, the auditor cannot rely upon the
exchange's primary copy to respect schema constraints, especially as we
have to presume that the exchange could act maliciously. Furthermore, it
- is unclear to what degree Postgres database replication mechanisms are
+ is unclear to what degree PostgreSQL database replication mechanisms are
robust against a malicious master database. Thus, the auditor should
- isolate its primary copy of the exchange database, including the Postgres
+ isolate its primary copy of the exchange database, including the PostgreSQL
process, from its actual operational data.
@@ -708,7 +708,7 @@ While ``taler-auditor-sync`` could in theory be run directly against the
exchange's production system, this is likely a bad idea due to the high
latency from the network between auditor and exchange operator. Thus, we
recommend first making an "untrusted" ingress copy of the exchange's
-production database using standard Postgres tooling, and then using
+production database using standard PostgreSQL tooling, and then using
``taler-auditor-sync`` to create a second "safe" copy. The "safe" copy used
by the production system should also run under a different UID.
diff --git a/taler-developer-manual.rst b/taler-developer-manual.rst
index 91bec2b..b7f2ac4 100644
--- a/taler-developer-manual.rst
+++ b/taler-developer-manual.rst
@@ -504,7 +504,7 @@ prepared.
Database schema versioning
--------------------------
-The Postgres databases of the exchange and the auditor are versioned.
+The PostgreSQL databases of the exchange and the auditor are versioned.
See the 0000.sql file in the respective directory for documentation.
Every set of changes to the database schema must be stored in a new
@@ -1690,7 +1690,7 @@ for the Taler exchange or Taler merchants.
Print version information.
**-w** *WIREFORMAT* \| **--wire** *WIREFORMAT*
- Specifies which wire format to use (i.e. “test” or “sepa”)
+ Specifies which wire format to use (i.e. “x-talerbank” or “iban”)
**--bank-uri**
Alternative to specify wire configuration to use for the exchange and
diff --git a/taler-exchange-manual.rst b/taler-exchange-manual.rst
index 59eb1ba..a45577a 100644
--- a/taler-exchange-manual.rst
+++ b/taler-exchange-manual.rst
@@ -63,7 +63,7 @@ etc.). This manual will not cover these aspects of operating a
payment service provider.
We will assume that you can operate a (high-availability,
-high-assurance) Postgres database. Furthermore, we expect some moderate
+high-assurance) PostgreSQL database. Furthermore, we expect some moderate
familiarity with the compilation and installation of free software
packages. You need to understand the cryptographic concepts of private
and public keys and must be able to protect private keys stored in files
@@ -181,9 +181,9 @@ components:
The exchange requires a DBMS to stores the transaction history for
the Taler exchange and aggregator, and a (typically separate) DBMS
for the Taler auditor. For now, the GNU Taler reference implementation
- only supports Postgres, but the code could be easily extended to
+ only supports PostgreSQL, but the code could be easily extended to
support another DBMS.
- .. index:: Postgres
+ .. index:: PostgreSQL
- Auditor
The auditor verifies that the transactions performed by the exchange
@@ -711,13 +711,13 @@ Wire fee structure
.. index:: wire fee
.. index:: fee
-For each wire method (“sepa” or “x-taler-wire”) the
+For each wire method (“iban” or “x-taler-bank”) the
exchange must know about applicable wire fees. This is also done
using the ``taler-exchange-offline`` tool:
.. code-block:: console
- $ taler-exchange-offline wire-fee iban 2040 EUR:0.05 EUR:0.10
+ $ taler-exchange-offline wire-fee iban 2040 EUR:0.05 EUR:0.10 EUR:0.15
The above sets the wire fees for wire transfers involving ``iban`` accounts
(in Euros) in the year 2040 to 5 cents (wire fee) and 10 cents (closing fee).
@@ -787,7 +787,7 @@ they should use the same configuration file.
For the most secure deployment, we recommend using separate users for each of
these processes to minimize information disclosures should any of them be
-compromised. The helpers do not need access to the Postgres database (and
+compromised. The helpers do not need access to the PostgreSQL database (and
thus also should not have it).
The processes that require access to the bank account need to have a
@@ -1048,8 +1048,9 @@ You can run a first simple benchmark using:
$ HTTPD_PID=$!
$ taler-exchange-offline -c benchmark.conf \
download sign \
- enable-account FIXME-DETAILS-MISING-HERE \
- wire-fee FIXME-DETAILS-MISING-HERE \
+ enable-account payto://iban/CH9300762011623852957 \
+ wire-fee iban EUR:0 EUR:0 EUR:0 \
+ global-fee EUR:0 EUR:0 EUR:0 EUR:0 4w 4w 6y 4 \
upload
$ kill -TERM $HTTPD_PID
$ taler-exchange-benchmark -c benchmark.conf -p 4 -r 1 -n 10
@@ -1066,4 +1067,4 @@ repetitions (i.e. if the operation failed the first time), total execution
time (operating system and user space) and other details.
Naturally, additional instrumentation (including using features of the
-Postgres database itself) may help discover performance issues.
+PostgreSQL database itself) may help discover performance issues.
diff --git a/taler-exchange-setup-guide.rst b/taler-exchange-setup-guide.rst
index 049c5ff..67fdebf 100644
--- a/taler-exchange-setup-guide.rst
+++ b/taler-exchange-setup-guide.rst
@@ -107,12 +107,12 @@ Finally, the required packages can be installed:
[root@exchange-online]# apt-get install -y nginx postgresql
[root@exchange-online]# apt-get install -y taler-exchange taler-exchange-offline
- [root@exchange-online]# apt-get install -y taler-wallet-cli
+ [root@exchange-online]# apt-get install -y taler-merchant taler-wallet-cli
By default, all installed services will be disabled. You need to enable
and start them later.
-While ``taler-merchant`` and ``taler-wallet`` are not required to operate an
+While ``taler-merchant`` and ``taler-wallet-cli`` are not required to operate an
exchange, they are useful for testing. When asked about using dbconfig to configure
the merchant's database, select ``yes``.
@@ -155,7 +155,7 @@ can use the ``taler-config`` helper:
Services, users, groups and file system hierarchy
=================================================
-The *taler-exchange-httpd* package will create several system users
+The *taler-exchange* package will create several system users
to compartmentalize different parts of the system:
* ``taler-exchange-httpd``: runs the HTTP daemon with the core business logic.
@@ -164,13 +164,13 @@ to compartmentalize different parts of the system:
* ``taler-exchange-closer``: closes idle reserves by triggering wire transfers that refund the originator.
* ``taler-exchange-aggregator``: aggregates deposits into larger wire transfer requests.
* ``taler-exchange-wire``: performs wire transfers with the bank (via LibEuFin/Nexus).
-* ``postgres``: runs the Postgres database (from *postgres* package).
+* ``postgres``: runs the PostgreSQL database (from *postgresql* package).
* ``www-data``: runs the frontend HTTPS service with the TLS keys (from *nginx* package).
.. note::
- The *taler-merchant-httpd* package additionally creates a taler-merchant-httpd user
- to runs the HTTP daemon with the merchant business logic.
+ The *taler-merchant* package additionally creates a ``taler-merchant-httpd`` user
+ to run the HTTP daemon with the merchant business logic.
The exchange setup uses the following system groups:
@@ -240,7 +240,7 @@ must be specified in ``/etc/taler/taler.conf``.
.. warning::
When editing ``/etc/taler/taler.conf``, take care to not accidentally remove
- the @inline-matching@ directive to include the configuration files in ``conf.d``.
+ the ``@inline-matching@`` directive to include the configuration files in ``conf.d``.
Next, the electronic cash denominations that the exchange offers must be
specified. The ``taler-wallet-cli`` has a helper command that generates a
@@ -248,7 +248,10 @@ reasonable denomination structure.
.. code-block:: shell-session
- taler-wallet-cli deployment gen-coin-config --min-amount EUR:0.01 --max-amount EUR:100 > /etc/taler/conf.d/exchange-coins.conf
+ [root@exchange-online]# taler-wallet-cli deployment gen-coin-config \
+ --min-amount EUR:0.01 \
+ --max-amount EUR:100 \
+ > /etc/taler/conf.d/exchange-coins.conf
You can manually review and edit the generated configuration file. The main
change that is possibly required is updating the various fees.
@@ -284,10 +287,6 @@ machine or a different one.
The main component of LibEuFin is called the Nexus. It implements a Web
service that provides a JSON abstraction layer to access bank accounts.
-The Nexus currently uses an sqlite3 database as storage by default.
-We currently recommend to stick with this default. In future
-versions, there will be a migration path to a PostgreSQL database.
-
The HTTP port and database connection string can be edited in the configuration:
.. code-block:: ini
@@ -648,7 +647,7 @@ exchange processes should not have access to this information.
enable_debit = yes
# Account identifier in the form of an RFC-8905 payto:// URI.
- # For SEPA, looks like payto://sepa/$IBAN?receiver-name=$NAME
+ # For SEPA, looks like payto://iban/$IBAN?receiver-name=$NAME
# Make sure to URL-encode spaces in $NAME!
payto_uri =
@@ -871,12 +870,15 @@ steps involving the offline signing machine must be completed:
[root@exchange-offline]# taler-exchange-offline \
sign < sig-request.json > sig-response.json
[root@exchange-offline]# taler-exchange-offline \
- enable-account payto://sepa/$IBAN?receiver-name=$NAME > acct-response.json
+ enable-account payto://iban/$IBAN?receiver-name=$NAME > acct-response.json
+ [root@exchange-offline]# taler-exchange-offline \
+ wire-fee now iban EUR:0 EUR:0 EUR:0 > fee-response.json
[root@exchange-offline]# taler-exchange-offline \
- wire-fee 2021 sepa EUR:0 EUR:0 > fee-response.json
+ global-fee now EUR:0 EUR:0 EUR:0 EUR:0 4w 4w 6y 4 > global-response.json
[root@exchange-online]# taler-exchange-offline upload < sig-response.json
[root@exchange-online]# taler-exchange-offline upload < acct-response.json
[root@exchange-online]# taler-exchange-offline upload < fee-response.json
+ [root@exchange-online]# taler-exchange-offline upload < global-response.json
@@ -940,7 +942,7 @@ provides this functionality for testing.)
.. code-block:: shell-session
$ taler-wallet-cli deposit create EUR:5 \
- payto://sepa/$IBAN?receiver-name=Name
+ payto://iban/$IBAN?receiver-name=Name
$ taler-wallet-cli run-pending
diff --git a/taler-mcig.rst b/taler-mcig.rst
index c69d838..97de36e 100644
--- a/taler-mcig.rst
+++ b/taler-mcig.rst
@@ -315,7 +315,7 @@ The fictitious store, Pretty Pianos, has only two products:
- pianos (physical good);
- *Beethoven Sonatas* (sheet music PDF files, digital good).
-M: :http:post:`/instances/default/private/products`
+M: POST ``/instances/default/private/products``
.. code-block:: javascript
@@ -338,7 +338,7 @@ field's list value.
This means the ``image`` value is *marked as forgettable*.
This will come into play later (see below).
-M: :http:post:`/instances/default/private/products`
+M: POST ``/instances/default/private/products``
.. code-block:: javascript
@@ -384,7 +384,7 @@ they need never pay again for it.
When the customer clicks on the product's "buy" button,
you first POST to ``/private/orders`` to create an order:
-M: :http:post:`/instances/default/private/orders`
+M: POST ``/instances/default/private/orders``
.. code-block:: javascript
@@ -425,7 +425,7 @@ Notes:
Now that there is an order in the system, the wallet *claims* the order.
-W: :http:post:`/orders/G93420934823/claim`
+W: POST ``/orders/G93420934823/claim``
.. code-block:: javascript
@@ -508,7 +508,7 @@ for the offer to time out).
The customer accepts the contract:
-W: :http:post:`/orders/G93420934823/pay`
+W: POST ``/orders/G93420934823/pay``
.. code-block:: javascript
diff --git a/taler-merchant-manual.rst b/taler-merchant-manual.rst
index 0701f6e..f568ef1 100644
--- a/taler-merchant-manual.rst
+++ b/taler-merchant-manual.rst
@@ -66,7 +66,7 @@ special currency “KUDOS” and includes its own special bank.
.. index:: back-office
.. index:: backend
.. index:: DBMS
-.. index:: Postgres
+.. index:: PostgreSQL
The Taler software stack for a merchant consists of four main
components:
@@ -90,8 +90,8 @@ components:
describes how to install and configure this backend.
- A *DBMS* which stores the transaction history for the Taler backend.
For now, the GNU Taler reference implementation only supports
- Postgres, but the code could be easily extended to support another
- DBMS. Please review the Postgres documentation for details on
+ PostgreSQL, but the code could be easily extended to support another
+ DBMS. Please review the PostgreSQL documentation for details on
how to configure the database.
The following image illustrates the various interactions of these key
@@ -381,13 +381,21 @@ Installing Taler on Debian GNU/Linux from source
.. index:: Wheezy
.. index:: Jessie
.. index:: Stretch
+.. index:: Buster
+.. index:: Bullseye
.. index:: Debian
Debian Wheezy is too old and lacks most of the packages required.
-Debian Jessie is better, but still lacks PostgreSQL 9.6.
+Debian Jessie, Stretch, and Buster are better, but still lack PostgreSQL 12.
-On Debian Stretch, only GNU libmicrohttpd needs to be compiled from
-source. To install dependencies on Debian stretch, run the following
+.. note::
+
+ When compiling PostgreSQL 12, make sure to
+ do ``make world`` to build the ``contrib/`` modules, and
+ ``cd contrib && make install`` to install them, as well.
+
+On Debian Stretch and Buster, only GNU libmicrohttpd needs to be compiled from
+source. To install dependencies on Debian Stretch, run the following
commands:
.. code-block:: console
@@ -404,8 +412,8 @@ commands:
libjansson-dev \
libpq-dev \
postgresql-9.6
- # wget https://ftp.gnu.org/gnu/libmicrohttpd/libmicrohttpd-latest.tar.gz
- # wget https://ftp.gnu.org/gnu/libmicrohttpd/libmicrohttpd-latest.tar.gz.sig
+ # wget https://ftpmirror.gnu.org/libmicrohttpd/libmicrohttpd-latest.tar.gz
+ # wget https://ftpmirror.gnu.org/libmicrohttpd/libmicrohttpd-latest.tar.gz.sig
# gpg -v libmicrohttpd-latest.tar.gz # Should show signed by 939E6BE1E29FC3CC
# tar xf libmicrohttpd-latest.tar.gz
# cd libmicrohttpd-0*
@@ -467,7 +475,7 @@ Backend options
---------------
.. index:: DBMS
-.. index:: Postgres
+.. index:: PostgreSQL
.. index:: UNIX domain socket
.. index:: TCP
.. index:: port
@@ -588,7 +596,7 @@ For the ``postgres`` backend, you need to provide:
This option specifies a postgres access path using the format
``postgres:///$DBNAME``, where ``$DBNAME`` is the name of the
-Postgres database you want to use. Suppose ``$USER`` is the name of
+PostgreSQL database you want to use. Suppose ``$USER`` is the name of
the user who will run the backend process. Then, you need to first
run:
@@ -596,7 +604,7 @@ run:
$ sudo -u postgres createuser -d $USER
-as the Postgres database administrator (usually ``postgres``) to
+as the PostgreSQL database administrator (usually ``postgres``) to
grant ``$USER`` the ability to create new databases. Next, you should
as ``$USER`` run:
@@ -625,7 +633,7 @@ You can improve your security posture if you now REVOKE the rights to CREATE,
DROP or ALTER tables from ``$USER``. However, if you do so, please be aware
that you may have to temporarily GRANT those rights again when you update the
merchant backend. For details on how to REVOKE or GRANT these rights, consult
-the Postgres documentation.
+the PostgreSQL documentation.
Commands, like ``taler-merchant-dbinit``, that support the ``-l LOGFILE``
command-line option, send logging output to standard error by default.
@@ -774,7 +782,7 @@ The following is an example for a complete backend configuration:
CURRENCY = KUDOS
Given the above configuration, the backend will use a database named
-``donations`` within Postgres.
+``donations`` within PostgreSQL.
The backend will deposit the coins it receives to the exchange at
https://exchange.demo.taler.net/, which has the master key
@@ -822,7 +830,7 @@ If everything worked as expected, the command
.. code-block:: console
- $ curl http://localhost:8888/config
+ $ wget -O - http://localhost:8888/config
should return some basic configuration status data about the service.
@@ -845,7 +853,7 @@ Instance setup
First of all, we recommend the use of the single-page administration
application that is served by default at the base URL of the merchant backend.
You can use it to perform all steps described in this section (and more!),
-using a simple Web interface instead of the ``curl`` commands given below.
+using a simple Web interface instead of the ``wget`` commands given below.
The first step for using the backend involves the creation of a ``default``
instance. The ``default`` instance can also create / delete / configure other
@@ -1273,8 +1281,8 @@ merchant. Attempting to upgrade from or to a version in Git is not supported
and may result in subtle data loss.
To safely upgrade the merchant, you should first stop the existing
-``taler-merchant-httpd`` process, backup your merchant database (see Postgres
-manual), and then install the latest version of the code.
+``taler-merchant-httpd`` process, backup your merchant database (see
+PostgreSQL manual), and then install the latest version of the code.
If you REVOKED database permissions, ensure that the rights to CREATE,
DROP, and ALTER tables are GRANTed to ``$USER`` again. Then, run:
@@ -1602,7 +1610,7 @@ A relatively minimal configuration could look like this:
Note that the public key must match the exchange's
-private key and that the Postgres database must
+private key and that the PostgreSQL database must
exist before launching the benchmark. You also
will need to ensure that the Exchange's
details are set up.
@@ -1723,5 +1731,5 @@ request to the merchant, for example:
.. code-block:: console
- $ curl http://$(docker-machine ip)/
+ $ wget -O - http://$(docker-machine ip)/
# A greeting message should be returned by the merchant.
diff --git a/taler-nfc-guide.rst b/taler-nfc-guide.rst
index 1b3cfb1..fbc7a9e 100644
--- a/taler-nfc-guide.rst
+++ b/taler-nfc-guide.rst
@@ -22,7 +22,8 @@ Background: Payment Processing with GNU Taler
The following steps show a simple payment process with GNU Taler. Examples are
written in `Bash <https://www.gnu.org/software/bash/>`_ syntax,
using `curl <https://curl.haxx.se/docs/manpage.html>`_ to make HTTP(S) requests.
-
+They make use of the :http:post:`[/instances/$INSTANCE]/private/orders`
+and :http:get:`[/instances/$INSTANCE]/private/orders` endpoints.
1. The merchant creates an *order*, which contains the details of the payment
and the product/service that the customer will receive.
@@ -45,7 +46,7 @@ using `curl <https://curl.haxx.se/docs/manpage.html>`_ to make HTTP(S) requests.
can be opened, and give a warning if it is detected that the devices does not have Internet
connectivity.
- The following :http:post:`/private/orders` request to the merchant backend creates a
+ The following POST ``/private/orders`` request to the merchant backend creates a
simple order:
.. code-block:: console
@@ -69,7 +70,7 @@ using `curl <https://curl.haxx.se/docs/manpage.html>`_ to make HTTP(S) requests.
}
2. The merchant checks the payment status of the order using
- :http:get:`/private/orders/$ORDER_ID`:
+ GET ``/private/orders/$ORDER_ID``:
.. code-block:: console
@@ -135,7 +136,8 @@ using `curl <https://curl.haxx.se/docs/manpage.html>`_ to make HTTP(S) requests.
before responding with the fulfillment page.
For in-store payments, the merchant must periodically check the payment status.
- Instead of polling in a busy loop, the ``timeout_ms`` parameter of :http:get:`/private/orders/$ORDER_ID`
+ Instead of polling in a busy loop, the ``timeout_ms`` parameter
+ of GET ``/private/orders/$ORDER_ID``
should be used.
diff --git a/taler-wallet-cli-manual.rst b/taler-wallet-cli-manual.rst
index 0758f9e..1a2efcb 100644
--- a/taler-wallet-cli-manual.rst
+++ b/taler-wallet-cli-manual.rst
@@ -127,7 +127,7 @@ is functional:
# Now, directly deposit coins with the exchange into a target account
# (Usually, a payment is made via a merchant. The wallet provides
# this functionality for testing.)
- $ taler-wallet-cli deposit create EUR:5 payto://sepa/$IBAN
+ $ taler-wallet-cli deposit create EUR:5 payto://iban/$IBAN
# Check if transaction was successful.
# (If not, fix issue with exchange and run "run-pending" command again)