commit 18d2d85c0ed4a7479709da571b08c36fcb23661d
parent a8cbf1b2b2c997958d37340cd0a537c9db9e4cb0
Author: Özgür Kesim <oec-taler@kesim.org>
Date: Wed, 10 Dec 2025 15:55:19 +0100
[exchange] reorganize sections, better order according to protocol flow
Diffstat:
| M | core/api-exchange.rst | | | 3107 | ++++++++++++++++++++++++++++++++++++++++--------------------------------------- |
1 file changed, 1556 insertions(+), 1551 deletions(-)
diff --git a/core/api-exchange.rst b/core/api-exchange.rst
@@ -1689,10 +1689,6 @@ exchange.
.. _withdraw:
.. http:post:: /withdraw
- .. note:: This endpoint is available starting with API version **v26**.
- It combines and replaces the endpoints ``/reserves/$RESERVE_PUB/batch-withdraw``
- and ``/reserves/$RESERVE_PUB/age-withdraw``.
-
Withdraw multiple coins from the same reserve. Note that the client should
commit all of the request details, including the private key of the coins and
the blinding factors, to disk *before* issuing this request, so that it can
@@ -1776,8 +1772,7 @@ exchange.
The response is a `DenominationGoneMessage` with a code of
``TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED``.
2. The denominatoin key was revoked. The response is a
- plain `ErrorDetail` with a code of
- ``TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED``.
+ plain `ErrorDetail` with a code of ``TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED``.
:http:statuscode:`412 Precondition Failed`:
A requested denomination key is not yet valid.
It is before the validity start time.
@@ -1828,279 +1823,186 @@ exchange.
**Details:**
- .. ts:def:: WithdrawRequest
-
- interface WithdrawRequest {
- // Cipher that is used for the rerserve's signatures.
- // For now, only ed25519 signatures are applicable,
- // but this might change in future versions.
- cipher: "ED25519";
-
- // The reserve's public key, for the the cipher ED25519,
- // to verify the signature ``reserve_sig``.
- reserve_pub: EddsaPublicKey;
-
- // Array of ``n`` hash codes of denomination public keys to order.
- // The sum of all denomination's values and fees MUST be
- // at most the balance of the reserve. The balance of
- // the reserve will be immediatley reduced by that amount.
- // If ``max_age`` is set, these denominations MUST support
- // age restriction as defined in the output to /keys.
- denoms_h: HashCode[];
-
- // If set, the maximum age to commit to. This implies:
- // 1.) it MUST be the same value as the maximum age
- // of the reserve.
- // 2.) ``coin_evs`` MUST be an array of ``n*kappa``
- // 3.) the denominations in ``denoms_h`` MUST support
- // age restriction.
- max_age?: Integer;
-
- // Master seed for the Clause-Schnorr R-value creation.
- // MUST match the /blinding-prepare request.
- // MUST NOT have been used in any prior withdraw request.
- // MUST be present if one of the fresh coin's
- // denomination is of type Clause-Schnorr.
- blinding_seed?: BlindingMasterSeed;
-
- // Array of blinded coin envelopes of type `CoinEnvelope`.
- // If ``max_age`` is not set, MUST be n entries.
- // If ``max_age`` is set, MUST be ``n*kappa`` entries,
- // arranged in [0..n)..[0..n), with the first n entries
- // belonging to kappa=0 etc.
- // In case of age restriction, the exchange will
- // respond with an index ``gamma``, which is the index
- // that shall remain undisclosed during the subsequent
- // reveal phase.
- // This hash value along with the reserve's public key
- // will also be used for recoup operations, if needed.
- coin_evs: CoinEnvelope[];
-
- // Signature of `TALER_WithdrawRequestPS` created with
- // the `reserves's private key <reserve-priv>`.
- reserve_sig: EddsaSignature;
- }
-
- .. ts:def:: WithdrawResponse
-
- interface WithdrawResponse {
- // Array of blinded signatures over each ``coin_evs``,
- // in the same order as was given in the request.
- // The blinded signatures affirm the coin's validity
- // after unblinding.
- ev_sigs: BlindedDenominationSignature[];
-
- }
-
- .. ts:def:: BlindedDenominationSignature
-
- type BlindedDenominationSignature = DenomCipher & (
- | RsaBlindedDenominationSignature
- | CSBlindedDenominationSignature
- )
-
- .. ts:def:: RsaBlindedDenominationSignature
-
- interface RsaBlindedDenominationSignature extends DenomCipher {
- cipher: "RSA";
-
- // (blinded) RSA signature
- blinded_rsa_signature: BlindedRsaSignature;
- }
-
- .. ts:def:: CSBlindedDenominationSignature
-
- interface CSBlindedDenominationSignature extends DenomCipher {
- cipher: "CS";
-
- // 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;
-
- }
-
- .. ts:def:: AgeWithdrawResponse
-
- interface AgeWithdrawResponse {
- // index of the commitments that the client doesn't
- // have to disclose in the subsequent call to
- // ``/reveal-withdraw``.
- noreveal_index: Integer;
-
- // Signature of `TALER_WithdrawConfirmationPS` whereby
- // the exchange confirms the ``noreveal_index``.
- exchange_sig: EddsaSignature;
-
- // `Public EdDSA key <sign-key-pub>` of the exchange that was used to
- // generate the signature. Should match one of the exchange's signing
- // keys from ``/keys``. Again given explicitly as the client might
- // otherwise be confused by clock skew as to which signing key was used.
- exchange_pub: EddsaPublicKey;
-
- }
-
- .. ts:def:: DenominationGoneMessage
+.. ts:def:: WithdrawRequest
+
+ interface WithdrawRequest {
+ // Cipher that is used for the rerserve's signatures.
+ // For now, only ed25519 signatures are applicable,
+ // but this might change in future versions.
+ cipher: "ED25519";
+
+ // The reserve's public key, for the the cipher ED25519,
+ // to verify the signature ``reserve_sig``.
+ reserve_pub: EddsaPublicKey;
+
+ // Array of ``n`` hash codes of denomination public keys to order.
+ // The sum of all denomination's values and fees MUST be
+ // at most the balance of the reserve. The balance of
+ // the reserve will be immediatley reduced by that amount.
+ // If ``max_age`` is set, these denominations MUST support
+ // age restriction as defined in the output to /keys.
+ denoms_h: HashCode[];
- interface DenominationGoneMessage {
+ // If set, the maximum age to commit to. This implies:
+ // 1.) it MUST be the same value as the maximum age
+ // of the reserve.
+ // 2.) ``coin_evs`` MUST be an array of ``n*kappa``
+ // 3.) the denominations in ``denoms_h`` MUST support
+ // age restriction.
+ max_age?: Integer;
+
+ // Master seed for the Clause-Schnorr R-value creation.
+ // MUST match the /blinding-prepare request.
+ // MUST NOT have been used in any prior withdraw request.
+ // MUST be present if one of the fresh coin's
+ // denomination is of type Clause-Schnorr.
+ blinding_seed?: BlindingMasterSeed;
+
+ // Array of blinded coin envelopes of type `CoinEnvelope`.
+ // If ``max_age`` is not set, MUST be n entries.
+ // If ``max_age`` is set, MUST be ``n*kappa`` entries,
+ // arranged in [0..n)..[0..n), with the first n entries
+ // belonging to kappa=0 etc.
+ // In case of age restriction, the exchange will
+ // respond with an index ``gamma``, which is the index
+ // that shall remain undisclosed during the subsequent
+ // reveal phase.
+ // This hash value along with the reserve's public key
+ // will also be used for recoup operations, if needed.
+ coin_evs: CoinEnvelope[];
+
+ // Signature of `TALER_WithdrawRequestPS` created with
+ // the `reserves's private key <reserve-priv>`.
+ reserve_sig: EddsaSignature;
+ }
- // Taler error code. Note that beyond
- // expiration this message format is also
- // used if the key is not yet valid, or
- // has been revoked. May be one of
- // - ``TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE``
- // - ``TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED``
- // - ``TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED``
- code: Integer;
-
- // Signature by the exchange over a
- // `TALER_DenominationExpiredAffirmationPS`.
- // Must have purpose ``TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_EXPIRED``.
- exchange_sig: EddsaSignature;
-
- // Public key of the exchange used to create
- // the 'exchange_sig.
- exchange_pub: EddsaPublicKey;
+.. ts:def:: WithdrawResponse
- // Hash of the denomination public key that is unknown.
- h_denom_pub: HashCode;
+ interface WithdrawResponse {
+ // Array of blinded signatures over each ``coin_evs``,
+ // in the same order as was given in the request.
+ // The blinded signatures affirm the coin's validity
+ // after unblinding.
+ ev_sigs: BlindedDenominationSignature[];
- // When was the signature created.
- timestamp: Timestamp;
+ }
- // What kind of operation was requested that now
- // failed?
- oper: string;
+.. ts:def:: BlindedDenominationSignature
- }
+ type BlindedDenominationSignature = DenomCipher & (
+ | RsaBlindedDenominationSignature
+ | CSBlindedDenominationSignature
+ )
+.. ts:def:: RsaBlindedDenominationSignature
- .. ts:def:: WithdrawError
+ interface RsaBlindedDenominationSignature extends DenomCipher {
+ cipher: "RSA";
- interface SingleWithdrawError {
- // Text describing the error.
- hint: string;
+ // (blinded) RSA signature
+ blinded_rsa_signature: BlindedRsaSignature;
+ }
- // Detailed error code.
- code: Integer;
+.. ts:def:: CSBlindedDenominationSignature
- // Amount left in the reserve.
- balance: Amount;
+ interface CSBlindedDenominationSignature extends DenomCipher {
+ cipher: "CS";
- }
+ // 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;
-------
-Reveal
-------
+ }
-These endpoints are called by the client
+.. ts:def:: AgeWithdrawResponse
-#. after a call to `melt`_.
- Now the client has to disclose --for each coin--
- all but one of the κ secrets that went into creating the blinded coin's planchets,
- the transfer public keys (linking the ownership of the old and new coin),
- and the commitment to age restriction,
- as proof that the age restriction was set correctly (if applicable).
-#. after a call to `withdraw`_, *if* the original request had ``max_age`` set
- and the response was of type `AgeWithdrawResponse`.
- Now the client has to disclose for each coin all but one of the κ secrets
- that went into creating the blinded coin's planchets,
- including the commitment to age restriction,
- and prove that the age restriction was set correctly.
+ interface AgeWithdrawResponse {
+ // index of the commitments that the client doesn't
+ // have to disclose in the subsequent call to
+ // ``/reveal-withdraw``.
+ noreveal_index: Integer;
+ // Signature of `TALER_WithdrawConfirmationPS` whereby
+ // the exchange confirms the ``noreveal_index``.
+ exchange_sig: EddsaSignature;
-.. http:post:: /reveal-melt
+ // `Public EdDSA key <sign-key-pub>` of the exchange that was used to
+ // generate the signature. Should match one of the exchange's signing
+ // keys from ``/keys``. Again given explicitly as the client might
+ // otherwise be confused by clock skew as to which signing key was used.
+ exchange_pub: EddsaPublicKey;
- Reveal previously committed values to the exchange, except for the values
- corresponding to the ``noreveal_index`` returned by the ``/melt`` step.
+ }
- The base URL for ``/reveal-melt``-request may differ from the main base URL of
- the exchange. Clients SHOULD respect the ``reveal_base_url`` returned for the
- coin during melt operations. The exchange MUST return a
- 307 or 308 redirection to the correct base URL if the client failed to
- respect the ``reveal_base_url`` or if the allocation has changed.
+.. ts:def:: DenominationGoneMessage
- The request body is a `RevealMeltRequest`.
+ interface DenominationGoneMessage {
- This endpoint was introduced in this form in protocol **vDOLDPLUS**.
+ // Taler error code. Note that beyond
+ // expiration this message format is also
+ // used if the key is not yet valid, or
+ // has been revoked. May be one of
+ // - ``TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE``
+ // - ``TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED``
+ // - ``TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED``
+ code: Integer;
- :http:statuscode:`200 OK`:
- The coin's' secret material matched the commitment and the original request was well-formed.
- The response body is a `RevealResponse`.
- :http:statuscode:`403 Forbidden`:
- One of the signatures is invalid.
- This response comes with a standard `ErrorDetail` response.
- :http:statuscode:`404 Not found`:
- The provided commitment is unknown.
- :http:statuscode:`409 Conflict`:
- There is a problem between the original commitment and the revealed secret data.
- The returned information is proof of the mismatch,
- and therefore rather verbose, as it includes most of the original /melt request,
- but of course expected to be primarily used for diagnostics.
+ // Signature by the exchange over a
+ // `TALER_DenominationExpiredAffirmationPS`.
+ // Must have purpose ``TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_EXPIRED``.
+ exchange_sig: EddsaSignature;
- The response body is a `RevealConflictResponse`.
+ // Public key of the exchange used to create
+ // the 'exchange_sig.
+ exchange_pub: EddsaPublicKey;
- **Details:**
+ // Hash of the denomination public key that is unknown.
+ h_denom_pub: HashCode;
- Request body for a ``reveal-melt`` request
- contains a JSON object with the following fields:
+ // When was the signature created.
+ timestamp: Timestamp;
- .. ts:def:: RevealMeltRequest
+ // What kind of operation was requested that now
+ // failed?
+ oper: string;
- interface RevealMeltRequest {
- // The refresh commitment from the ``/melt/`` step,
- // see `TALER_RefreshCommitmentP`.
- rc: HashCode;
+ }
- // @since v27
- // @deprecated vDOLDPLUS
- // The disclosed kappa-1 signatures by the old coin's private key,
- // over Hash1a("Refresh", Cp, r, i), where Cp is the melted coin's public key,
- // r is the public refresh nonce from the metling step and i runs over the
- // _disclosed_ kappa-1 indices.
- signatures: CoinSignature[kappa-1];
- // @since vDOLDPLUS
- // The seeds for the transfer secrets to reveal.
- // For the kappa many batches of n coin candidates,
- // each of the seeds in this list are expanded via HKDF:
- // ``ts[k][] = HKDF(sizeof(HashCode)*n, ts_seeds[k], "ts")``
- // An individual coin's transfer secret at kappa-index k and
- // coin index i in the batch is then ``ts[k][i]``.
- transfer_secret_seeds: HashCode[kappa-1];
+.. ts:def:: WithdrawError
- // IFF the denomination of the old coin had support for age restriction,
- // the client MUST provide the original age commitment, i. e. the
- // vector of public keys, or omitted otherwise.
- // The size of the vector MUST be the number of age groups as defined by the
- // Exchange in the field ``.age_groups`` of the extension ``age_restriction``.
- age_commitment?: Edx25519PublicKey[];
+ interface SingleWithdrawError {
+ // Text describing the error.
+ hint: string;
- }
+ // Detailed error code.
+ code: Integer;
- .. ts:def:: RevealResponse
+ // Amount left in the reserve.
+ balance: Amount;
- type RevealResponse = WithdrawResponse;
+ }
- .. ts:def:: RevealConflictResponse
- interface RevealConflictResponse {
- // Text describing the error.
- hint: string;
+------------------
- // Detailed error code.
- code: Integer;
- // Commitment as calculated by the exchange from the revealed data.
- rc_expected: HashCode;
- }
+.. _reveal-withdraw:
+**Reveal-Withdraw**
+This endpoint is called by the client after a call to `withdraw`_,
+*if* the original request had ``max_age`` set and
+the response was of type `AgeWithdrawResponse`.
+Now the client has to disclose for each coin all but one of the κ secrets
+that went into creating the blinded coin's planchets,
+including the commitment to age restriction,
+and prove that the age restriction was set correctly.
.. http:post:: /reveal-withdraw
@@ -2203,1597 +2105,1801 @@ These endpoints are called by the client
-.. _reserve-history:
+----------
+Refreshing
+----------
----------------
-Reserve History
----------------
+Refreshing creates ``n`` new coins from ``m`` old coins, where the sum of
+denominations of the new coins must be smaller than the sum of the old coins'
+denominations plus melting (refresh) and withdrawal fees charged by the exchange.
+The refreshing API can be used by wallets to melt partially spent coins, making
+transactions with the freshly exchangeed coins unlinkabe to previous transactions
+by anyone except the wallet itself.
-.. http:get:: /reserves/$RESERVE_PUB/history
+Refreshing is a two step process, consisting of
- Request information about the full history of
- a reserve or an account.
+1. the **melting** of the old coin, together with ``kappa`` batches
+ of blinded planchets candidates,
+2. the **reveal** of ``kappa-1`` secrets to prove the proper construction
+ of the (revealed) batches of blinded planchets candidates.
- **Request:**
- The GET request should come with the following HTTP headers:
+^^^^
+Melt
+^^^^
- *If-None-Match*:
- The client MAY provide an ``If-None-Match`` header with an
- Etag. In that case, the server MUST additionally respond with an ``304``
- status code in case the reserve history matches the provided Etag.
+.. _melt:
+.. http:post:: /melt
- *Taler-Reserve-History-Signature*:
- The client MUST provide Base-32 encoded
- EdDSA signature over a ``TALER_SIGNATURE_RESERVE_HISTORY_REQUEST`` made with
- the respective ``$RESERVE_PRIV``, affirming desire to download the current
- reserve transaction history.
+ "Melts" a coin. Invalidates the coins and prepares for exchanging of fresh
+ coins. Taler uses a global parameter ``kappa`` for the cut-and-choose
+ component of the protocol, for which this request is the commitment. Thus,
+ various arguments are given ``kappa``-times in this step. At present ``kappa``
+ is always 3.
- :query start=OFFSET: *Optional.* Only return reserve history entries with
- offsets above the given OFFSET. Allows clients to not
- retrieve history entries they already have.
+ The base URL for ``/melt/``-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.
- **Response:**
+ This endpoint was introduced in this form in protocol **vDOLDPLUS**.
:http:statuscode:`200 OK`:
- The exchange responds with a `ReserveHistory` object; the reserve was known to the exchange.
- :http:statuscode:`204 No content`:
- The reserve history is known, but at this point from the given starting point it is empty. Can only happen if OFFSET was positive.
- :http:statuscode:`304 Not modified`:
- The reserve history matches the one identified by the "If-none-match" HTTP header of the request.
+ The request was successful. The response body is `MeltResponse` in this case.
:http:statuscode:`403 Forbidden`:
- The *TALER_SIGNATURE_RESERVE_HISTORY_REQUEST* is invalid.
- This response comes with a standard `ErrorDetail` response.
+ One of the signatures is invalid.
:http:statuscode:`404 Not found`:
- The reserve key does not belong to a reserve known to the exchange.
+ The exchange does not recognize the denomination key as belonging to the exchange,
+ or it has expired.
+ 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
+ (``TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS`` or
+ ``TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY``).
+ The response is `DepositDoubleSpendError` in both cases.
+ :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
+ `DenominationGoneMessage`. Clients must evaluate
+ the error code provided to understand which of the
+ cases this is and handle it accordingly.
**Details:**
- .. ts:def:: ReserveHistory
-
- interface ReserveHistory {
- // Balance left in the reserve.
- balance: Amount;
-
- // If set, gives the maximum age group that the client is required to set
- // during withdrawal.
- maximum_age_group: Integer;
-
- // Transaction history for this reserve.
- // May be partial (!).
- history: TransactionHistoryItem[];
- }
-
- Objects in the transaction history have the following format:
-
- .. ts:def:: TransactionHistoryItem
+ .. ts:def:: MeltRequest
- // Union discriminated by the "type" field.
- type TransactionHistoryItem =
- | AccountSetupTransaction
- | ReserveWithdrawTransaction
- | ReserveCreditTransaction
- | ReserveClosingTransaction
- | ReserveOpenRequestTransaction
- | ReserveCloseRequestTransaction
- | PurseMergeTransaction;
+ interface MeltRequest {
+ // The old coin's public key
+ old_coin_pub: CoinPublicKey;
- .. ts:def:: AccountSetupTransaction
+ // Hash of the denomination public key of the old coin, to determine total coin value.
+ old_denom_pub_h: HashCode;
- interface AccountSetupTransaction {
- type: "SETUP";
+ // The hash of the age-commitment for the old coin. Only present
+ // if the denomination has support for age restriction.
+ old_age_commitment_h?: AgeCommitmentHash;
- // Offset of this entry in the reserve history.
- // Useful to request incremental histories via
- // the "start" query parameter.
- history_offset: Integer;
+ // Signature over the old `coin public key <eddsa-coin-pub>` by the denomination.
+ old_denom_sig: DenominationSignature;
- // KYC fee agreed to by the reserve owner.
- kyc_fee: Amount;
+ // Amount of the value of the old coin that should be melted as part of
+ // this refresh operation, including melting fee. I.e.:
+ // melting fee of the old coin
+ // + sum over all values of fresh coins
+ // + sum over all withdraw fees for the fresh coins
+ value_with_fee: Amount;
- // Time when the KYC was triggered.
- kyc_timestamp: Timestamp;
+ // @since v27
+ // @deprecated vDOLDPLUS
+ // Seed from which the nonces for the n*κ coin candidates are derived from.
+ refresh_seed: HashCode;
- // Hash of the wire details of the account.
- // Note that this hash is unsalted and potentially
- // private (as it could be inverted), hence access
- // to this endpoint must be authorized using the
- // private key of the reserve.
- h_wire: HashCode;
+ // @since vDOLDPLUS
+ // This value is opaque to the exchange. It was provided by the client
+ // as part of the original refresh request, and was therefore
+ // verified with the coin_sig below.
+ //
+ // Note: The honest owner of the old coin SHOULD use this value
+ // and the old coin's private key to derive kappa many
+ // transfer secret seeds like this:
+ // ``ts_seeds[k] = SHA512(master_refresh_seed, old_coin_priv, "s", k)``
+ // Each of the kappa seeds is then expanded via HKDF:
+ // ``ts[k][] = HKDF(sizeof(HashCode)*n, ts_seeds[k], "ts")``
+ // An individual coin's transfer secret at kappa-index k and
+ // coin index i in the batch is then ``ts[k][i]``
+ // This ensures that the honest owner of the old coin can replay
+ // a MeltRequest from the coin history provided by the exchange
+ // (which includes this value), in case a wallet was restored
+ // from a backup into a state prior to the refresh operation.
+ master_refresh_seed: HashCode;
- // Signature created with the reserve's private key.
- // Must be of purpose ``TALER_SIGNATURE_ACCOUNT_SETUP_REQUEST`` over
- // a ``TALER_AccountSetupRequestSignaturePS``.
- reserve_sig: EddsaSignature;
+ // Master seed for the Clause-Schnorr R-value
+ // creation. Must match the /blinding-prepare 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.
+ blinding_seed?: BlindingMasterSeed;
- }
+ // Array of ``n`` new hash codes of denomination public keys
+ // for the new coins to order.
+ denoms_h: HashCode[];
- .. ts:def:: ReserveWithdrawTransaction
+ // ``kappa`` arrays of ``n`` entries for blinded coin candidates,
+ // each matching the respective entries in ``denoms_h``.
+ coin_evs: CoinEnvelope[kappa][];
- interface ReserveWithdrawTransaction {
- type: "WITHDRAW";
+ // @since vDOLDPLUS
+ // ``kappa`` arrays of ``n`` entries of transfer public keys each.
+ // These are ephemeral ECDHE keys that allow the owner of a coin
+ // to (re-)obtain the derived coins from a refresh operation, f.e. should
+ // the wallet state be restored from a backup, prior to the refresh operation.
+ transfer_pubs: EddsaPublicKey[kappa][];
- // Offset of this entry in the reserve history.
- // Useful to request incremental histories via
- // the "start" query parameter.
- history_offset: Integer;
+ // Signature by the `coin <coin-priv>` over `TALER_RefreshMeltCoinAffirmationPS`.
+ confirm_sig: EddsaSignature;
- // Amount withdrawn.
- amount: Amount;
+ }
- // Total fee that is charged for withdraw.
- withdraw_fee: Amount;
+ For details about the HKDF used to derive the new coin private keys and
+ the blinding factors from ECDHE between the transfer public keys and
+ the private key of the melted coin, please refer to the
+ implementation in ``libtalerutil``.
- // Total number of coins in the withdraw request
- num_coins: Integer;
+ .. ts:def:: MeltResponse
- // Signature over a `TALER_WithdrawRequestPS`
- // with purpose ``TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW``
- // created with the reserve's private key.
- reserve_sig: EddsaSignature;
+ interface MeltResponse {
+ // Which of the ``kappa`` indices does the client not have to reveal
+ // by calling the ``/reveal-melt`` endpoint.
+ noreveal_index: Integer;
- // The hash of the all the planchets that were provided during the
- // call to /withdraw.
- h_planchets: HashCode;
+ // Signature of `TALER_RefreshMeltConfirmationPS` whereby the exchange
+ // affirms the successful melt and confirming the ``noreveal_index``.
+ exchange_sig: EddsaSignature;
- // The blinding seed that was provided. It will be NULL if
- // no denominations of cipher type Clause-Schnorr were invovled
- blinding_seed?: BlindingMasterSeed;
+ // `Public EdDSA key <sign-key-pub>` of the exchange that was used to generate the signature.
+ // Should match one of the exchange's signing keys from ``/keys``. Again given
+ // explicitly as the client might otherwise be confused by clock skew as to
+ // which signing key was used.
+ exchange_pub: EddsaPublicKey;
- // The array of hashes of public key of denominations for the coins.
- denom_pub_hashes: HashCode[];
+ // Base URL to use for operations on the refresh context
+ // (so the reveal operation). If not given,
+ // the base URL is the same as the one used for this request.
+ // Can be used if the base URL for ``/reveal-melt/`` differs from that
+ // for ``/melt/``, i.e. for load balancing. Clients SHOULD
+ // respect the reveal_base_url if provided. Any HTTP server
+ // belonging to an exchange MUST generate a 307 or 308 redirection
+ // to the correct base URL should a client uses the wrong base
+ // URL, or if the base URL has changed since the melt.
+ //
+ // When melting the same coin twice (technically allowed
+ // as the response might have been lost on the network),
+ // the exchange may return different values for the ``reveal_base_url``.
+ reveal_base_url?: string;
- // The maximum age committed to, if the withdraw request
- // required age-restriction
- max_age?: Integer;
+ }
- // The noreveal index that was returned as part
- // of a age-restricted withdraw, if applicable
- noreveal_index?: Integer;
- }
+^^^^^^^^^^^
+Reveal-Melt
+^^^^^^^^^^^
+This endpoint is called by the client after a call to `melt`_.
+Now the client has to disclose --for each coin--
+all but one of the κ secrets that went into creating the blinded coin's planchets,
+the transfer public keys (linking the ownership of the old and new coin),
+and the commitment to age restriction,
+as proof that the age restriction was set correctly (if applicable).
- .. ts:def:: ReserveCreditTransaction
+.. http:post:: /reveal-melt
- interface ReserveCreditTransaction {
- type: "CREDIT";
+ Reveal previously committed values to the exchange, except for the values
+ corresponding to the ``noreveal_index`` returned by the ``/melt`` step.
- // Offset of this entry in the reserve history.
- // Useful to request incremental histories via
- // the "start" query parameter.
- history_offset: Integer;
+ The base URL for ``/reveal-melt``-request may differ from the main base URL of
+ the exchange. Clients SHOULD respect the ``reveal_base_url`` returned for the
+ coin during melt operations. The exchange MUST return a
+ 307 or 308 redirection to the correct base URL if the client failed to
+ respect the ``reveal_base_url`` or if the allocation has changed.
- // Amount deposited.
- amount: Amount;
+ The request body is a `RevealMeltRequest`.
- // Sender account full payto:// URI.
- sender_account_url: string;
+ This endpoint was introduced in this form in protocol **vDOLDPLUS**.
- // Opaque identifier internal to the exchange that
- // uniquely identifies the wire transfer that credited the reserve.
- wire_reference: Integer;
+ :http:statuscode:`200 OK`:
+ The coin's' secret material matched the commitment and the original request was well-formed.
+ The response body is a `RevealResponse`.
+ :http:statuscode:`403 Forbidden`:
+ One of the signatures is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not found`:
+ The provided commitment is unknown.
+ :http:statuscode:`409 Conflict`:
+ There is a problem between the original commitment and the revealed secret data.
+ The returned information is proof of the mismatch,
+ and therefore rather verbose, as it includes most of the original /melt request,
+ but of course expected to be primarily used for diagnostics.
- // Timestamp of the incoming wire transfer.
- timestamp: Timestamp;
- }
+ The response body is a `RevealConflictResponse`.
+ **Details:**
- .. ts:def:: ReserveClosingTransaction
+ Request body for a ``reveal-melt`` request
+ contains a JSON object with the following fields:
- interface ReserveClosingTransaction {
- type: "CLOSING";
+ .. ts:def:: RevealMeltRequest
- // Offset of this entry in the reserve history.
- // Useful to request incremental histories via
- // the "start" query parameter.
- history_offset: Integer;
+ interface RevealMeltRequest {
+ // The refresh commitment from the ``/melt/`` step,
+ // see `TALER_RefreshCommitmentP`.
+ rc: HashCode;
- // Closing balance.
- amount: Amount;
+ // @since v27
+ // @deprecated vDOLDPLUS
+ // The disclosed kappa-1 signatures by the old coin's private key,
+ // over Hash1a("Refresh", Cp, r, i), where Cp is the melted coin's public key,
+ // r is the public refresh nonce from the metling step and i runs over the
+ // _disclosed_ kappa-1 indices.
+ signatures: CoinSignature[kappa-1];
- // Closing fee charged by the exchange.
- closing_fee: Amount;
+ // @since vDOLDPLUS
+ // The seeds for the transfer secrets to reveal.
+ // For the kappa many batches of n coin candidates,
+ // each of the seeds in this list are expanded via HKDF:
+ // ``ts[k][] = HKDF(sizeof(HashCode)*n, ts_seeds[k], "ts")``
+ // An individual coin's transfer secret at kappa-index k and
+ // coin index i in the batch is then ``ts[k][i]``.
+ transfer_secret_seeds: HashCode[kappa-1];
- // Wire transfer subject.
- wtid: Base32;
+ // IFF the denomination of the old coin had support for age restriction,
+ // the client MUST provide the original age commitment, i. e. the
+ // vector of public keys, or omitted otherwise.
+ // The size of the vector MUST be the number of age groups as defined by the
+ // Exchange in the field ``.age_groups`` of the extension ``age_restriction``.
+ age_commitment?: Edx25519PublicKey[];
- // Full payto URI of the wire account into which the funds were returned to.
- receiver_account_details: string;
+ }
- // This is a signature over a
- // struct `TALER_ReserveCloseConfirmationPS` with purpose
- // ``TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED``.
- exchange_sig: EddsaSignature;
+ .. ts:def:: RevealResponse
- // Public key used to create 'exchange_sig'.
- exchange_pub: EddsaPublicKey;
+ type RevealResponse = WithdrawResponse;
- // Time when the reserve was closed.
- timestamp: Timestamp;
- }
+ .. ts:def:: RevealConflictResponse
- .. ts:def:: ReserveOpenRequestTransaction
+ interface RevealConflictResponse {
+ // Text describing the error.
+ hint: string;
- interface ReserveOpenRequestTransaction {
- type: "OPEN";
+ // Detailed error code.
+ code: Integer;
- // Offset of this entry in the reserve history.
- // Useful to request incremental histories via
- // the "start" query parameter.
- history_offset: Integer;
+ // Commitment as calculated by the exchange from the revealed data.
+ rc_expected: HashCode;
- // Open fee paid from the reserve.
- open_fee: Amount;
+ }
- // This is a signature over
- // a struct `TALER_ReserveOpenPS` with purpose
- // ``TALER_SIGNATURE_WALLET_RESERVE_OPEN``.
- reserve_sig: EddsaSignature;
- // Timestamp of the open request.
- request_timestamp: Timestamp;
+.. _deposit-par:
- // Requested expiration.
- requested_expiration: Timestamp;
+-------
+Deposit
+-------
- // Requested number of free open purses.
- requested_min_purses: Integer;
+Deposit operations are requested f.e. by a merchant during a transaction or a
+bidder during an auction.
- }
+For the deposit operation during purchase, the merchant has to obtain the
+deposit permission for a coin from their customer who owns the coin. When
+depositing a coin, the merchant is credited an amount specified in the deposit
+permission, possibly a fraction of the total coin's value, minus the deposit
+fee as specified by the coin's denomination.
- .. ts:def:: ReserveCloseRequestTransaction
+For auctions, a bidder performs an deposit operation and provides all relevant
+information for the auction policy (such as timeout and public key as bidder)
+and can use the ``exchange_sig`` field from the `DepositSuccess` message as a
+proof to the seller for the escrow of sufficient fund.
- interface ReserveCloseRequestTransaction {
- type: "CLOSE";
-
- // Offset of this entry in the reserve history.
- // Useful to request incremental histories via
- // the "start" query parameter.
- history_offset: Integer;
-
- // This is a signature over
- // a struct `TALER_ReserveClosePS` with purpose
- // ``TALER_SIGNATURE_WALLET_RESERVE_CLOSE``.
- reserve_sig: EddsaSignature;
-
- // Hash over the full payto URI of the target account.
- h_payto?: FullPaytoHash;
-
- // Timestamp of the close request.
- request_timestamp: Timestamp;
- }
-
- .. ts:def:: PurseMergeTransaction
-
- interface PurseMergeTransaction {
- type: "MERGE";
-
- // Offset of this entry in the reserve history.
- // Useful to request incremental histories via
- // the "start" query parameter.
- history_offset: Integer;
-
- // SHA-512 hash of the contact of the purse.
- h_contract_terms: HashCode;
-
- // EdDSA public key used to approve merges of this purse.
- merge_pub: EddsaPublicKey;
-
- // Minimum age required for all coins deposited into the purse.
- min_age: Integer;
-
- // Number that identifies who created the purse
- // and how it was paid for.
- flags: Integer;
-
- // Purse public key.
- purse_pub: EddsaPublicKey;
-
- // EdDSA signature of the account/reserve affirming the merge
- // over a `TALER_AccountMergeSignaturePS`.
- // Must be of purpose ``TALER_SIGNATURE_ACCOUNT_MERGE``
- reserve_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 merged into an account. At this
- // point, all of the deposits made should be
- // auto-refunded.
- purse_expiration: Timestamp;
-
- // Purse fee the reserve owner paid for the purse creation.
- purse_fee: Amount;
-
- // Total amount merged into the reserve.
- // (excludes fees).
- amount: Amount;
-
- // True if the purse was actually merged.
- // If false, only the purse_fee has an impact
- // on the reserve balance!
- merged: boolean;
- }
+.. _deposit:
-.. _coin-history:
-
-------------
-Coin History
-------------
-
-.. http:get:: /coins/$COIN_PUB/history
+.. http:post:: /batch-deposit
- Obtain the transaction history of a coin. Used only in special cases, like
- when the exchange claims a double-spending error and the wallet does not
- believe it. Usually, the wallet knows the transaction history of each coin
- and thus has no need to inquire.
+ Deposit multiple coins and ask the exchange to transfer the given :ref:`amount`
+ into the merchant's bank account. This API is used by the merchant to redeem
+ the digital coins.
**Request:**
- The GET request should come with the following HTTP headers:
-
- *If-None-Match*:
- The client MAY provide an ``If-None-Match`` header with an
- Etag. In that case, the server MUST additionally respond with an ``304``
- status code in case the coin history matches the provided Etag.
-
- *Taler-Coin-History-Signature*:
- The client MUST provide Base-32 encoded EdDSA signature over a
- ``TALER_SIGNATURE_COIN_HISTORY_REQUEST`` made with the respective
- ``$COIN_PRIV``, affirming desire to download the current coin
- transaction history.
-
- :query start=OFFSET: *Optional.* Only return coin history entries with
- offsets above the given OFFSET. Allows clients to not
- retrieve history entries they already have.
+ The request body must be a `BatchDepositRequest` object.
**Response:**
:http:statuscode:`200 OK`:
The operation succeeded, the exchange confirms that no double-spending took
- place. The response will include a `CoinHistoryResponse` object.
- :http:statuscode:`204 No content`:
- The reserve history is known, but at this point from the given starting point it is empty. Can only happen if OFFSET was positive.
- :http:statuscode:`304 Not modified`:
- The coin history has not changed since the previous query (detected via Etag
- in "If-none-match" header).
+ place. The response will include a `DepositSuccess` object.
:http:statuscode:`403 Forbidden`:
- The *TALER_SIGNATURE_COIN_HISTORY_REQUEST* is invalid.
+ One of the signatures is invalid.
This response comes with a standard `ErrorDetail` response.
:http:statuscode:`404 Not found`:
- The coin public key is not (yet) known to the exchange.
+ Either one of the denomination keys is not recognized (expired or invalid),
+ or the wire type is not recognized.
+ If a denomination key is unknown, the response will be
+ a `DenominationUnknownMessage`.
+ :http:statuscode:`409 Conflict`:
+ The deposit operation has either failed because a coin has insufficient
+ residual value, or because the same public key of a coin has been
+ previously used with a different denomination.
+ Which case it is can be decided by looking at the error code:
+
+ 1. ``TALER_EC_EXCHANGE_DEPOSIT_CONFLICTING_CONTRACT`` (same coin used in different ways),
+ 2. ``TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS`` (balance insufficient),
+ 3. ``TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY`` (same coin public key, but different denomination).
+ 4. ``TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_AGE_HASH`` (same coin public key, but different age commitment).
+
+ The request should not be repeated again with this coin. Instead, the client
+ can get from the exchange via the ``/coin/$COIN_PUB/history`` endpoint the record
+ of the transactions known for this coin's public key.
+ :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
+ `DenominationGoneMessage`. Clients must evaluate
+ the error code provided to understand which of the
+ cases this is and handle it accordingly.
+ :http:statuscode:`451 Unavailable For Legal Reasons`:
+ This merchant has not yet passed the KYC checks.
+ The client must pass KYC checks before proceeding with the deposit.
+ The response will be an `LegitimizationNeededResponse` object.
+ @since protocol **v21**.
**Details:**
- .. ts:def:: CoinHistoryResponse
+ .. ts:def:: BatchDepositRequest
- interface CoinHistoryResponse {
- // Current balance of the coin.
- balance: Amount;
+ interface BatchDepositRequest {
- // Hash of the coin's denomination.
- h_denom_pub: HashCode;
+ // The merchant's account details as a full payto URI.
+ merchant_payto_uri: string;
- // Transaction history for the coin.
- history: CoinSpendHistoryItem[];
- }
+ // The salt is used to hide the ``payto_uri`` from customers
+ // when computing the ``h_wire`` of the merchant.
+ wire_salt: WireSalt;
- .. ts:def:: CoinSpendHistoryItem
+ // SHA-512 hash of the contract of the merchant with the customer. Further
+ // details are never disclosed to the exchange.
+ h_contract_terms: HashCode;
- // Union discriminated by the "type" field.
- type CoinSpendHistoryItem =
- | CoinDepositTransaction
- | CoinMeltTransaction
- | CoinRefundTransaction
- | CoinRecoupTransaction
- | CoinOldCoinRecoupTransaction
- | CoinRecoupRefreshTransaction
- | CoinPurseDepositTransaction
- | CoinPurseRefundTransaction
- | CoinReserveOpenDepositTransaction;
-
- .. ts:def:: CoinDepositTransaction
-
- interface CoinDepositTransaction {
- type: "DEPOSIT";
+ // Merchant's signature over the h_contract_terms.
+ // @since protocol **v22**
+ merchant_sig: EddsaSignature;
- // Offset of this entry in the reserve history.
- // Useful to request incremental histories via
- // the "start" query parameter.
- history_offset: Integer;
+ // The list of coins that are going to be deposited with this Request.
+ coins: BatchDepositRequestCoin[];
- // The total amount of the coin's value absorbed (or restored in the
- // case of a refund) by this transaction.
- // The amount given includes
- // the deposit fee. The current coin value can thus be computed by
- // subtracting this amount.
- amount: Amount;
+ // Timestamp when the contract was finalized.
+ timestamp: Timestamp;
- // Deposit fee.
- deposit_fee: Amount;
+ // Indicative time by which the exchange undertakes to transfer the funds to
+ // the merchant, in case of successful payment. A wire transfer deadline of 'never'
+ // is not allowed.
+ wire_transfer_deadline: Timestamp;
- // Public key of the merchant.
+ // EdDSA `public key of the merchant <merchant-pub>`, so that the client can identify the
+ // merchant for refund requests.
merchant_pub: EddsaPublicKey;
- // Date when the operation was made.
- timestamp: Timestamp;
-
// Date until which the merchant can issue a refund to the customer via the
- // exchange, possibly zero if refunds are not allowed.
+ // exchange, to be omitted if refunds are not allowed.
+ //
+ // THIS FIELD WILL BE DEPRICATED, once the refund mechanism becomes a
+ // policy via extension.
refund_deadline?: Timestamp;
- // Hash over the proposal data of the contract that
- // is being paid.
- h_contract_terms: HashCode;
+ // CAVEAT: THIS IS WORK IN PROGRESS
+ // (Optional) policy for the batch-deposit.
+ // This might be a refund, auction or escrow policy.
+ policy?: DepositPolicy;
+ }
- // Hash of the bank account from where we received the funds.
- h_wire: HashCode;
+ .. ts:def:: BatchDepositRequestCoin
- // Hash of the public denomination key used to sign the coin.
- // Needed because 'coin_sig' signs over this, and
- // that is important to fix the coin's denomination.
- h_denom_pub: HashCode;
+ interface BatchDepositRequestCoin {
+ // EdDSA public key of the coin being deposited.
+ coin_pub: EddsaPublicKey;
- // Hash over the deposit policy extension. Optional.
- h_policy?: HashCode;
+ // Hash of denomination RSA key with which the coin is signed.
+ denom_pub_hash: HashCode;
- // Hash over auxiliary wallet data provided by the wallet
- // to complete the contract. Optional.
- wallet_data_hash?: HashCode;
+ // Exchange's unblinded RSA signature of the coin.
+ ub_sig: DenominationSignature;
- // Hash over the age commitment of the coin. Optional.
- h_age_commitment?: HashCode;
+ // Amount to be deposited, can be a fraction of the
+ // coin's total value.
+ contribution: Amount;
// Signature over `TALER_DepositRequestPS`, made by the customer with the
// `coin's private key <coin-priv>`.
coin_sig: EddsaSignature;
-
}
- .. ts:def:: CoinMeltTransaction
-
- interface CoinMeltTransaction {
- type: "MELT";
-
- // Offset of this entry in the reserve history.
- // Useful to request incremental histories via
- // the "start" query parameter.
- history_offset: Integer;
-
- // The total amount of the coin's value absorbed by this transaction.
- // Note that for melt this means the amount given includes
- // the melt fee. The current coin value can thus be computed by
- // subtracting the amounts.
- amount: Amount;
-
- // Melt fee.
- melt_fee: Amount;
-
- // Commitment from the melt operation, see `TALER_RefreshCommitmentP`
- rc: HashCode;
+ .. ts:def:: DenominationSignature
- // Hash of the public denomination key used to sign the old coin.
- // Needed because 'coin_sig' signs over this, and
- // that is important to fix the coin's denomination.
- old_denom_pub_h: HashCode;
+ type DenominationSignature = DenomCipher & (
+ | RsaDenominationSignature
+ | CSDenominationSignature
+ );
- // Hash over the age commitment of the coin. Optional.
- old_age_commitment_h?: AgeCommitmentHash;
+ .. ts:def:: RsaDenominationSignature
- // @since vDOLDPLUS
- // This value is opaque to the exchange. It was provided by the client
- // as part of the original refresh request, and was therefore verified
- // with the confirm_sig below.
- // If the reveal step was not performed yet by the old coin owner,
- // they can use this value and the old coin's private key to derive
- // all indivual seeds for the n*κ coin candidates for the original
- // refresh request and replay it
- master_refresh_seed: HashCode;
+ interface RsaDenominationSignature extends DenomCipher {
+ cipher: "RSA";
- // @since vDOLDPLUS
- // The kappa*n list of transfer public keys that were provided by the
- // old coin owner during the melt request.
- transfer_pubs: EddsaPublicKey[kappa][];
+ // RSA signature
+ rsa_signature: RsaSignature;
+ }
- // @since vDOLDPLUS
- // The n denomination public keys for the fresh coins
- // that the coin owner had requested.
- denoms_h: HashCode[];
+ .. ts:def:: CSDenominationSignature
- // @since vDOLDPLUS
- // The `noreveal_index` value that was returned by the exchange as response
- // to the melt request.
- noreveal_index: Integer;
+ interface CSDenominationSignature extends DenomCipher {
+ cipher: "CS";
- // @since vDOLDPLUS
- // If the reveal step was successfully peformed by the coin owner,
- // this field contains the blind coin signatures that were returned
- // by the exchange for the chosen batch of coins.
- ev_sigs?: BlindedDenominationSignature[];
-
- // Master seed for the Clause-Schnorr R-value
- // Present if one of the fresh coin's
- // denominations is of type Clause-Schnorr.
- blinding_seed?: BlindingMasterSeed;
+ // R value component of the signature.
+ cs_signature_r: Cs25519Point;
- // Signature by the coin over a
- // `TALER_RefreshMeltCoinAffirmationPS` of
- // purpose ``TALER_SIGNATURE_WALLET_COIN_MELT``.
- confirm_sig: EddsaSignature;
+ // s value component of the signature.
+ cs_signature_s: Cs25519Scalar;
}
- .. ts:def:: CoinRefundTransaction
-
- interface CoinRefundTransaction {
- type: "REFUND";
-
- // Offset of this entry in the reserve history.
- // Useful to request incremental histories via
- // the "start" query parameter.
- history_offset: Integer;
+ .. ts:def:: DepositPolicy
- // The total amount of the coin's value restored
- // by this transaction.
- // The amount given excludes the transaction fee.
- // The current coin value can thus be computed by
- // adding the amounts to the coin's denomination value.
- amount: Amount;
+ type DepositPolicy =
+ | PolicyMerchantRefund
+ | PolicyBrandtVickreyAuction
+ | PolicyEscrowedPayment;
- // Refund fee.
- refund_fee: Amount;
+ .. ts:def:: PolicyMerchantRefund
- // Hash over the proposal data of the contract that
- // is being refunded.
- h_contract_terms: HashCode;
+ // CAVEAT: THIS IS STILL WORK IN PROGRESS.
+ // This policy is optional and might not be supported by the exchange.
+ // If it does, the exchange MUST show support for this policy in the
+ // ``extensions`` field in the response to ``/keys``.
+ interface PolicyMerchantRefund {
+ type: "merchant_refund";
- // Public key of the merchant.
+ // EdDSA `public key of the merchant <merchant-pub>`, so that the client
+ // can identify the merchant for refund requests.
merchant_pub: EddsaPublicKey;
- // Refund transaction ID.
- rtransaction_id: Integer;
-
- // `EdDSA Signature <eddsa-sig>` authorizing the REFUND over a
- // `TALER_MerchantRefundConfirmationPS` with
- // purpose ``TALER_SIGNATURE_MERCHANT_REFUND_OK``. Made with
- // the `public key of the merchant <merchant-pub>`.
- merchant_sig: EddsaSignature;
-
+ // Date until which the merchant can issue a refund to the customer via
+ // the ``/extensions/policy_refund``-endpoint of the exchange.
+ deadline: Timestamp;
}
- .. ts:def:: CoinRecoupTransaction
-
- interface CoinRecoupTransaction {
- type: "RECOUP";
+ .. ts:def:: PolicyBrandtVickreyAuction
- // Offset of this entry in the reserve history.
- // Useful to request incremental histories via
- // the "start" query parameter.
- history_offset: Integer;
-
- // The total amount of the coin's value absorbed
- // by this transaction.
- // The current coin value can thus be computed by
- // subtracting the amount from
- // the coin's denomination value.
- amount: Amount;
-
- // Signature by the exchange over a
- // `TALER_RecoupConfirmationPS`, must be
- // of purpose ``TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP``.
- exchange_sig: EddsaSignature;
+ // CAVEAT: THIS IS STILL WORK IN PROGRESS.
+ // This policy is optional and might not be supported by the exchange.
+ // If it does, the exchange MUST show support for this policy in the
+ // ``extensions`` field in the response to ``/keys``.
+ interface PolicyBrandtVickreyAuction {
+ type: "brandt_vickrey_auction";
- // Public key of the private key used to create 'exchange_sig'.
- exchange_pub: EddsaPublicKey;
+ // Public key of this bidder.
+ //
+ // The bidder uses this key to sign the auction information and
+ // the messages it sends to the seller during the auction.
+ bidder_pub: EddsaPublicKey;
- // Signature by the coin over a
- // `TALER_RecoupRequestPS` with purpose
- // ``TALER_SIGNATURE_WALLET_COIN_RECOUP``.
- coin_sig: EddsaSignature;
+ // Hash of the auction terms
+ //
+ // The hash should be taken over a normalized JSON object of type
+ // `BrandtVickreyAuction`.
+ h_auction: HashCode;
- // Hash of the public denomination key used to sign the coin.
- // Needed because 'coin_sig' signs over this, and
- // that is important to fix the coin's denomination.
- h_denom_pub: HashCode;
+ // The amount that this bidder commits to for this auction
+ //
+ // This amount can be larger than the contribution of a single coin.
+ // The bidder can increase funding of this auction policy by using
+ // sufficiently many coins during the deposit operation (single or batch)
+ // with the same policy.
+ commitment: Amount;
- // Coin blinding key that was used in the original withdraw request.
- coin_blind: DenominationBlindingKeyP;
+ // Date until the auction must have been successfully executed and
+ // a valid transcript provided to the
+ // ``/extensions/policy_brandt_vickrey_auction``-endpoint of the
+ // exchange.
+ //
+ // [If the auction has not been executed by then] OR [has been executed
+ // before then, but this bidder did not win], the coin's value doesn't
+ // change and the owner can refresh the coin.
+ //
+ // If this bidder won the auction, the winning price/amount from the
+ // outcome will be substracted from the coin and transfered to the
+ // merchant's ``payout_uri`` from the deposit request (minus a potential
+ // auction fee). For any remaining value, the bidder can refresh the
+ // coin to retrieve change.
+ deadline: Timestamp;
+ }
- // The hash of the withdraw commitment of the original withdraw
- // request that this coin was part of
- h_commitment: HashCode;
+ .. ts:def:: BrandtVickreyAuction
- // Coin's index in the original withdraw request, starting at 0
- coin_index: Integer;
+ // CAVEAT: THIS IS STILL WORK IN PROGRESS.
+ // This structure defines an auction of Brandt-Vickory kind.
+ // It is used for the `PolicyBrandtVickreyAuction`.
+ interface BrandtVickreyAuction {
+ // Start date of the auction
+ time_start: Timestamp;
- // Reserve receiving the recoup.
- reserve_pub: EddsaPublicKey;
+ // Maximum duration per round. There are four rounds in an auction of
+ // Brandt-Vickrey kind.
+ time_round: RelativeTime;
- // Date when the operation was made.
- timestamp: Timestamp;
+ // This integer m refers to the (m+1)-type of the Brandt-Vickrey-auction.
+ // - Type 0 refers to an auction with one highest-price winner,
+ // - Type 1 refers to an auction with one winner, paying the second
+ // highest price,
+ // - Type 2 refers to an auction with two winners, paying
+ // the third-highest price,
+ // - etc.
+ auction_type: Integer;
- }
+ // The vector of prices for the Brandt-Vickrey auction. The values MUST
+ // be in strictly increasing order.
+ prices: Amount[];
- .. ts:def:: CoinOldCoinRecoupTransaction
+ // The type of outcome of the auction.
+ // In case the auction is declared public, each bidder can calculate the
+ // winning price. This field is not relevant for the replay of a
+ // transcript, as the transcript must be provided by the seller who sees
+ // the winner(s) and winning price of the auction.
+ outcome_public: boolean;
- interface CoinOldCoinRecoupTransaction {
- type: "OLD-COIN-RECOUP";
+ // The public key of the seller.
+ pubkey: EddsaPublicKey;
- // Offset of this entry in the reserve history.
- // Useful to request incremental histories via
- // the "start" query parameter.
- history_offset: Integer;
+ // The seller's account details as a full payto URI.
+ payto_uri: string;
+ }
- // The total amount of the coin's value restored
- // by this transaction.
- // The current coin value can thus be computed by
- // adding the amount to the coin's denomination value.
- amount: Amount;
- // Date when the operation was made.
- timestamp: Timestamp;
+ .. ts:def:: PolicyEscrowedPayment
- // Signature by the exchange over a
- // `TALER_RecoupRefreshConfirmationPS`
- // of purpose ``TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH``.
- exchange_sig: EddsaSignature;
+ // CAVEAT: THIS IS STILL WORK IN PROGRESS
+ // This policy is optional and might not be supported by the exchange.
+ // If it does, the exchange MUST show support for this policy in the
+ // ``extensions`` field in the response to ``/keys``.
+ interface PolicyEscrowedPayment {
+ type: "escrowed_payment";
- // Public key of the private key used to create 'exchange_sig'.
- exchange_pub: EddsaPublicKey;
+ // Public key of this trustor, the owner of the coins.
+ //
+ // To claim the deposit, the merchant must provide the valid signature
+ // of the ``h_contract_terms`` field from the deposit, signed by _this_
+ // key, to the ``/extensions/policy_escrow``-endpoint of the exchange,
+ // after the date specified in ``not_before`` and before the date
+ // specified in ``not_after``.
+ trustor_pub: EddsaPublicKey;
+ // Latest date by which the deposit must be claimed. If the deposit
+ // has not been claimed by that date, the deposited coins can be
+ // refreshed by the (still) owner.
+ deadline: Timestamp;
}
- .. ts:def:: CoinRecoupRefreshTransaction
-
- interface CoinRecoupRefreshTransaction {
- type: "RECOUP-REFRESH";
+ The deposit operation succeeds if the coin is valid for making a deposit and
+ has enough residual value that has not already been deposited or melted.
- // Offset of this entry in the reserve history.
- // Useful to request incremental histories via
- // the "start" query parameter.
- history_offset: Integer;
+ .. ts:def:: DepositSuccess
- // The total amount of the coin's value absorbed
- // by this transaction.
- // The current coin value can thus be computed by
- // subtracting this amounts from
- // the coin's denomination value.
- amount: Amount;
+ interface DepositSuccess {
+ // Optional base URL of the exchange for looking up wire transfers
+ // associated with this transaction. If not given,
+ // the base URL is the same as the one used for this request.
+ // Can be used if the base URL for ``/transactions/`` differs from that
+ // for ``/coins/``, i.e. for load balancing. Clients SHOULD
+ // respect the ``transaction_base_url`` if provided. Any HTTP server
+ // belonging to an exchange MUST generate a 307 or 308 redirection
+ // to the correct base URL should a client uses the wrong base
+ // URL, or if the base URL has changed since the deposit.
+ transaction_base_url?: string;
- // Signature by the exchange over a
- // `TALER_RecoupRefreshConfirmationPS`
- // of purpose ``TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH``.
- exchange_sig: EddsaSignature;
+ // Timestamp when the deposit was received by the exchange.
+ exchange_timestamp: Timestamp;
- // Public key used to sign 'exchange_sig'.
+ // `Public EdDSA key of the exchange <sign-key-pub>` that was used to
+ // generate the signature.
+ // Should match one of the exchange's signing keys from ``/keys``. It is given
+ // explicitly as the client might otherwise be confused by clock skew as to
+ // which signing key was used.
exchange_pub: EddsaPublicKey;
- // FIXME-#9828: implementation returns old_coin_pub here
-
- // Signature by the coin over a `TALER_RecoupRequestPS`
- // with purpose ``TALER_SIGNATURE_WALLET_COIN_RECOUP``.
- coin_sig: EddsaSignature;
-
- // Hash of the public denomination key used to sign the coin.
- // Needed because 'coin_sig' signs over this, and
- // that is important to fix the coin's denomination.
- h_denom_pub: HashCode;
+ // Deposit confirmation signature from the exchange.
+ // The EdDSA signature of `TALER_DepositConfirmationPS` using a current
+ // `signing key of the exchange <sign-key-priv>` affirming the successful
+ // deposit and that the exchange will transfer the funds after the refund
+ // deadline, or as soon as possible if the refund deadline is zero.
+ exchange_sig: EddsaSignature;
+ }
- // Coin blinding key that was used in the original withdraw request.
- coin_blind: DenominationBlindingKeyP;
+ .. ts:def:: DepositDoubleSpendError
- // The hash of the withdraw commitment of the original withdraw
- // request that this coin was part of
- h_commitment: HashCode;
+ interface DepositDoubleSpendError {
- // Coin's index in the original withdraw request, starting at 0
- coin_index: Integer;
+ // Must be TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS
+ // or TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY
+ code: Integer;
- // Blinding factor of the revoked new coin.
- new_coin_blinding_secret: DenominationBlindingKeySecret;
+ // A string explaining that the user tried to
+ // double-spend.
+ hint: string;
- // Blinded public key of the revoked new coin.
- new_coin_ev: DenominationBlindingKeySecret;
+ // EdDSA public key of a coin being double-spent.
+ coin_pub: EddsaPublicKey;
- // Date when the operation was made.
- timestamp: Timestamp;
+ // Hash of the public key of the denomination of the coin.
+ h_denom_pub: HashCode;
}
- .. ts:def:: CoinPurseDepositTransaction
- interface CoinPurseDepositTransaction {
- type: "PURSE-DEPOSIT";
- // Offset of this entry in the reserve history.
- // Useful to request incremental histories via
- // the "start" query parameter.
- history_offset: Integer;
+------
+Recoup
+------
- // The total amount of the coin's value absorbed
- // by this transaction.
- // Note that this means the amount given includes
- // the deposit fee. The current coin value can thus be computed by
- // subtracting the amount from
- // the coin's denomination value.
- amount: Amount;
+The purpose of this API is to allow coins to be cashed back in,
+in certain exceptional situations.
+This API is only used if the exchange is either about to go out of
+business or has had its private signing keys compromised (so in
+either case, the protocol is only used in **abnormal**
+situations). In the above cases, the exchange signals to the
+wallets that the emergency cash back protocol has been activated
+by putting the affected denomination keys into the cash-back
+part of the ``/keys`` response. If and only if this has happened,
+coins that were signed with those denomination keys can be cashed
+in using this API.
- // Base URL of the exchange the purse lives at.
- exchange_base_url: string;
+For a recoup, a coin has to provide the necessary information to
+identify the original transaction (either a withdraw or a refresh) it
+became minted, and proof ownership of the coin itself.
- // The hash of the age-commitment for the coin. Only present
- // if the denomination has support for age restriction.
- h_age_commitment?: AgeCommitmentHash;
- // Deposit fee.
- deposit_fee: Amount;
+.. http:post:: /recoup-withdraw
- // Public key of the purse.
- purse_pub: EddsaPublicKey;
+ Demand that a batch of coins be refunded to the reserve,
+ from which the coins were originally withdrawn.
+ The coins must have been originated from the same call to withdraw, and be
+ a subset of that original batch.
+ The remaining amount on the coin will be credited to the reserve
+ that the coins were withdrawn from, in the same withdraw request.
- // True if the deposit was refunded for any reason.
- refunded: boolean;
+ Note that the original withdrawal fees will **not** be recouped.
- // Signature by the coin over a
- // `TALER_PurseDepositSignaturePS` of
- // purpose ``TALER_SIGNATURE_PURSE_DEPOSIT``.
- coin_sig: EddsaSignature;
+ .. note:: This endpoint still Work-in-Progress. It will be implemented in **vRECOUP**, sometime after **vDOLDPLUS**.
- // Hash of the public denomination key used to sign the coin.
- // Needed because 'coin_sig' signs over this, and
- // that is important to fix the coin's denomination.
- h_denom_pub: HashCode;
+ **Request:**
- }
+ The request body must be a `RecoupWithdrawRequest` object.
- .. ts:def:: CoinPurseRefundTransaction
+ It provides sufficient information to
+ a) identify the originating withdraw request
+ b) proof that the coins to be recouped were part of that withdraw request
+ c) proof ownership of all coins requested to be recouped.
- interface CoinPurseRefundTransaction {
- type: "PURSE-REFUND";
+ **Response:**
- // Offset of this entry in the reserve history.
- // Useful to request incremental histories via
- // the "start" query parameter.
- history_offset: Integer;
+ :http:statuscode:`200 OK`:
+ The request was successful, and the response is a `ReserveSummary`.
+ :http:statuscode:`403 Forbidden`:
+ A coin's signature is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not found`:
+ A denomination key is unknown,
+ the withdraw commitment is unknown
+ or a blinded coin is not known to have been withdrawn.
+ If a denomination key is unknown, the response will be
+ a `DenominationUnknownMessage`.
+ :http:statuscode:`409 Conflict`:
+ The operation is not allowed
+ as a coin has insufficient residual value,
+ or because the same public key of a 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_FUNDS``).
+ The response is a `DepositDoubleSpendError`.
+ :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 not yet revoked.
+ The response is a `DenominationGoneMessage`.
+ Clients must evaluate the error code provided
+ to understand which of the cases this is and handle it accordingly.
- // The total amount of the coin's value restored
- // by this transaction.
- // The amount given excludes the refund fee.
- // The current coin value can thus be computed by
- // adding the amount to the coin's denomination value.
- amount: Amount;
+ **Details:**
- // Refund fee (of the coin's denomination). The deposit
- // fee will be waived.
- refund_fee: Amount;
+ .. ts:def:: RecoupWithdrawRequest
- // Signature by the exchange over a
- // ``TALER_CoinPurseRefundConfirmationPS``
- // of purpose ``TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_REFUND``.
- exchange_sig: EddsaSignature;
+ interface RecoupWithdrawRequest {
+ // Public key of the reserve that will receive the recoup.
+ // MUST be the same as the one from the original withdraw.
+ reserve_pub: EddsaPublicKey;
- // Public key used to sign 'exchange_sig'.
- exchange_pub: EddsaPublicKey;
+ // The details about the coins:
+ // An array of either
+ // a) the hash code of a blinded coin envelope (not to be recouped)
+ // b) the disclosed coin details, in order to recoup it.
+ // From these, the hash of all coin envelopes
+ // from the original withdraw can be reconstructed.
+ coin_data: RecoupCoinData[];
+ }
- // Public key of the purse that expired.
- purse_pub: EddsaPublicKey;
+ .. ts:def:: RecoupCoinData
- }
+ // This is either
+ // a) the hash code of a blinded coin envelope (not to be recouped)
+ // b) the disclosed coin details, in order to recoup it.
+ type RecoupCoinData =
+ | NonRecoupedCoin
+ | RecoupDisclosedCoinDetails;
- .. ts:def:: CoinReserveOpenDepositTransaction
+ .. ts:def:: NonRecoupedCoin
- interface CoinReserveOpenDepositTransaction {
- type: "RESERVE-OPEN-DEPOSIT";
+ interface NonRecoupedCoin {
+ type: "non_recouped_coin";
- // Offset of this entry in the reserve history.
- // Useful to request incremental histories via
- // the "start" query parameter.
- history_offset: Integer;
+ // This is the SHA512 hash code of a blinded coin envelope,
+ // including the corresponding denomination's hash.
+ // It is the output of the TALER_coin_ev_hash function
+ // from libtalerutil.
+ coin_ev: BlindedCoinEnvelopeHash;
+ };
- // The total amount of the coin's value absorbed
- // by this transaction.
- // Note that this means the amount given includes
- // the deposit fee.
- coin_contribution: Amount;
+ .. ts:def:: BlindedCoinEnvelopeHash
- // Signature of the reserve open operation being paid for.
- reserve_sig: EddsaSignature;
+ // The hash value of a blinded coin envelope,
+ // as it its generated by the function TALER_coin_ev_hash
+ // in libtalerutil.
+ type BlindedCoinEnvelopeHash = HashCode;
- // Signature by the coin over a
- // `TALER_ReserveOpenDepositSignaturePS` of
- // purpose ``TALER_SIGNATURE_RESERVE_OPEN_DEPOSIT``.
- coin_sig: EddsaSignature;
+ .. ts:def:: RecoupDisclosedCoinDetails
- }
+ // This object provides all necessary coin data
+ // in order to call TALER_denom_blind and retrieve
+ // a blinded coin planchet, from which we can
+ // calculate the blinded coin envelope hash.
+ // It also contains the denomination's signature
+ // for the (unblinded) coin's public key,
+ // and the coin's signature to authorize the recoup request.
+ interface RecoupDisclosedCoinDetails {
+ type: "recoup_coin_details";
+ // The coin's public key
+ coin_pub: CoinPublicKey;
-.. _deposit-par:
+ // The blinding secret for this coin
+ // that was used during withdraw
+ coin_blinding_key_secret: DenominationBlindingKeySecret;
--------
-Deposit
--------
+ // The coin's commitment for age restriction,
+ // if the denomination had age restriction support.
+ age_commitment_h?: AgeCommitmentHash;
-Deposit operations are requested f.e. by a merchant during a transaction or a
-bidder during an auction.
+ // The blinding nonce that went into this coin's
+ // blinded envelope
+ cs_session_nonce?: HashCode;
-For the deposit operation during purchase, the merchant has to obtain the
-deposit permission for a coin from their customer who owns the coin. When
-depositing a coin, the merchant is credited an amount specified in the deposit
-permission, possibly a fraction of the total coin's value, minus the deposit
-fee as specified by the coin's denomination.
+ // In case of Clause-Schnorr denomination,
+ // the blinding values that were provided
+ // for this coin, by the exchange, as response
+ // to a call to /blinding-prepare.
+ cs_r_pubs?: CSRPublicPair;
-For auctions, a bidder performs an deposit operation and provides all relevant
-information for the auction policy (such as timeout and public key as bidder)
-and can use the ``exchange_sig`` field from the `DepositSuccess` message as a
-proof to the seller for the escrow of sufficient fund.
+ // Unblinded signature of the coins' public key,
+ // signed by the denomination key.
+ denom_pub_sig: DenominationSignature;
+ // The denomination public key.
+ // This denomination MUST be eligible for recoup,
+ // i.e. being listed in the "recoup" section of /config.
+ denom_pub_h: HashCode;
-.. _deposit:
+ // Signature of `TALER_RecoupRequestPS`,
+ // created by this coin's private key.
+ coin_sig: EddsaSignature;
+ }
-.. http:post:: /batch-deposit
- Deposit multiple coins and ask the exchange to transfer the given :ref:`amount`
- into the merchant's bank account. This API is used by the merchant to redeem
- the digital coins.
+.. http:post:: /recoup-refresh
+
+ Demand that a batch of coins be refunded to the original coin,
+ from which the coins were originally refreshed.
+ The coins must have been originated from the same call to refresh, and be
+ a subset of that original batch.
+ The remaining amount on the coin will be credited to the original coin
+ that the coins were refreshed from, in the same refresh request.
+
+ The base URL for coin related 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.
+
+ Note that the original refresh fees will **not** be recouped.
+
+ .. note:: This endpoint still Work-in-Progress. It will be implemented in **vRECOUP**, sometime after **vDOLDPLUS**.
**Request:**
- The request body must be a `BatchDepositRequest` object.
+ The request body must be a `RecoupRefreshRequest` object.
**Response:**
:http:statuscode:`200 OK`:
- The operation succeeded, the exchange confirms that no double-spending took
- place. The response will include a `DepositSuccess` object.
+ 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:`403 Forbidden`:
- One of the signatures is invalid.
+ The coin's signature is invalid.
This response comes with a standard `ErrorDetail` response.
:http:statuscode:`404 Not found`:
- Either one of the denomination keys is not recognized (expired or invalid),
- or the wire type is not recognized.
- If a denomination key is unknown, the response will be
+ 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 deposit operation has either failed because a coin has insufficient
- residual value, or because the same public key of a coin has been
- previously used with a different denomination.
- Which case it is can be decided by looking at the error code:
-
- 1. ``TALER_EC_EXCHANGE_DEPOSIT_CONFLICTING_CONTRACT`` (same coin used in different ways),
- 2. ``TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS`` (balance insufficient),
- 3. ``TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY`` (same coin public key, but different denomination).
- 4. ``TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_AGE_HASH`` (same coin public key, but different age commitment).
-
- The request should not be repeated again with this coin. Instead, the client
- can get from the exchange via the ``/coin/$COIN_PUB/history`` endpoint the record
- of the transactions known for this coin's public key.
+ 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 revoked. The response is a
+ It either before the validity start, past the expiration or was not yet revoked. The response is a
`DenominationGoneMessage`. Clients must evaluate
the error code provided to understand which of the
cases this is and handle it accordingly.
- :http:statuscode:`451 Unavailable For Legal Reasons`:
- This merchant has not yet passed the KYC checks.
- The client must pass KYC checks before proceeding with the deposit.
- The response will be an `LegitimizationNeededResponse` object.
- @since protocol **v21**.
**Details:**
- .. ts:def:: BatchDepositRequest
+ .. ts:def:: RecoupRefreshRequest
- interface BatchDepositRequest {
+ interface RecoupRefreshRequest {
+ // Public key of the original coin that will receive the recoup.
+ // MUST be the same as the one from the original refresh request.
+ old_coin_pub: EddsaPublicKey;
- // The merchant's account details as a full payto URI.
- merchant_payto_uri: string;
+ // The details about the coins:
+ // An array of either
+ // a) the hash code of a blinded coin envelope (not to be recouped)
+ // b) the disclosed coin details, in order to recoup it.
+ // From these, the hash of all coin envelopes
+ // from the original refresh can be reconstructed.
+ coin_data: RecoupCoinData[];
+ }
- // The salt is used to hide the ``payto_uri`` from customers
- // when computing the ``h_wire`` of the merchant.
- wire_salt: WireSalt;
- // SHA-512 hash of the contract of the merchant with the customer. Further
- // details are never disclosed to the exchange.
- h_contract_terms: HashCode;
+ .. ts:def:: RecoupRefreshConfirmation
- // Merchant's signature over the h_contract_terms.
- // @since protocol **v22**
- merchant_sig: EddsaSignature;
+ interface RecoupRefreshConfirmation {
+ // TODO[oec]: What is needed here?
+ // Public key of the old coin that will receive the recoup.
+ old_coin_pub: EddsaPublicKey;
+ }
- // The list of coins that are going to be deposited with this Request.
- coins: BatchDepositRequestCoin[];
- // Timestamp when the contract was finalized.
- timestamp: Timestamp;
- // Indicative time by which the exchange undertakes to transfer the funds to
- // the merchant, in case of successful payment. A wire transfer deadline of 'never'
- // is not allowed.
- wire_transfer_deadline: Timestamp;
+.. _exchange_refund:
- // EdDSA `public key of the merchant <merchant-pub>`, so that the client can identify the
- // merchant for refund requests.
- merchant_pub: EddsaPublicKey;
+-------
+Refunds
+-------
- // Date until which the merchant can issue a refund to the customer via the
- // exchange, to be omitted if refunds are not allowed.
- //
- // THIS FIELD WILL BE DEPRICATED, once the refund mechanism becomes a
- // policy via extension.
- refund_deadline?: Timestamp;
+.. http:post:: /coins/$COIN_PUB/refund
- // CAVEAT: THIS IS WORK IN PROGRESS
- // (Optional) policy for the batch-deposit.
- // This might be a refund, auction or escrow policy.
- policy?: DepositPolicy;
- }
+ Undo deposit of the given coin, restoring its value.
- .. ts:def:: BatchDepositRequestCoin
+ **Request:**
- interface BatchDepositRequestCoin {
- // EdDSA public key of the coin being deposited.
- coin_pub: EddsaPublicKey;
+ The request body must be a `RefundRequest` object.
- // Hash of denomination RSA key with which the coin is signed.
- denom_pub_hash: HashCode;
+ **Response:**
- // Exchange's unblinded RSA signature of the coin.
- ub_sig: DenominationSignature;
+ :http:statuscode:`200 OK`:
+ The operation succeeded, the exchange confirms that the coin can now be refreshed. The response will include a `RefundSuccess` object.
+ :http:statuscode:`403 Forbidden`:
+ Merchant signature is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not found`:
+ The refund operation failed as we could not find a matching deposit operation (coin, contract, transaction ID and merchant public key must all match).
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`409 Conflict`:
+ The exchange has previously received a refund request for the same coin, merchant and contract, but specifying a different amount for the same refund transaction ID. The response will be a `RefundFailure` object.
+ :http:statuscode:`410 Gone`:
+ It is too late for a refund by the exchange, the money was already sent to the merchant.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`412 Precondition failed`:
+ The request transaction ID is identical to a previous refund request by the same
+ merchant for the same coin and contract, but the refund amount differs. (The
+ failed precondition is that the ``rtransaction_id`` is not unique.)
+ The response will be a `RefundFailure` object with the conflicting refund request.
- // Amount to be deposited, can be a fraction of the
- // coin's total value.
- contribution: Amount;
+ **Details:**
- // Signature over `TALER_DepositRequestPS`, made by the customer with the
- // `coin's private key <coin-priv>`.
- coin_sig: EddsaSignature;
- }
+ .. ts:def:: RefundRequest
- .. ts:def:: DenominationSignature
+ interface RefundRequest {
- type DenominationSignature = DenomCipher & (
- | RsaDenominationSignature
- | CSDenominationSignature
- );
+ // Amount to be refunded, can be a fraction of the
+ // coin's total deposit value (including deposit fee);
+ // must be larger than the refund fee.
+ refund_amount: Amount;
- .. ts:def:: RsaDenominationSignature
+ // SHA-512 hash of the contact of the merchant with the customer.
+ h_contract_terms: HashCode;
- interface RsaDenominationSignature extends DenomCipher {
- cipher: "RSA";
+ // 64-bit transaction id of the refund transaction between merchant and customer.
+ rtransaction_id: Integer;
- // RSA signature
- rsa_signature: RsaSignature;
- }
+ // EdDSA public key of the merchant.
+ merchant_pub: EddsaPublicKey;
- .. ts:def:: CSDenominationSignature
+ // EdDSA signature of the merchant over a
+ // `TALER_RefundRequestPS` with purpose
+ // ``TALER_SIGNATURE_MERCHANT_REFUND``
+ // affirming the refund.
+ merchant_sig: EddsaPublicKey;
- interface CSDenominationSignature extends DenomCipher {
- cipher: "CS";
+ }
- // R value component of the signature.
- cs_signature_r: Cs25519Point;
+ .. ts:def:: RefundSuccess
- // s value component of the signature.
- cs_signature_s: Cs25519Scalar;
+ interface RefundSuccess {
+
+ // The EdDSA :ref:`signature` (binary-only) with purpose
+ // ``TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND`` over
+ // a `TALER_RecoupRefreshConfirmationPS`
+ // using a current signing key of the
+ // exchange affirming the successful refund.
+ exchange_sig: EddsaSignature;
+ // Public EdDSA key of the exchange that was used to generate the signature.
+ // Should match one of the exchange's signing keys from ``/keys``. It is given
+ // explicitly as the client might otherwise be confused by clock skew as to
+ // which signing key was used.
+ exchange_pub: EddsaPublicKey;
+ }
+
+ .. ts:def:: RefundFailure
+
+ interface RefundFailure {
+
+ // Numeric error code unique to the condition, which can be either
+ // related to the deposit value being insufficient for the requested
+ // refund(s), or the requested refund conflicting due to refund
+ // transaction number re-use (with different amounts).
+ code: Integer;
+
+ // Human-readable description of the error message.
+ hint: string;
+
+ // Information about the conflicting refund request(s).
+ // This will not be the full history of the coin, but only
+ // the relevant subset of the transactions.
+ history: CoinSpendHistoryItem[];
}
- .. ts:def:: DepositPolicy
- type DepositPolicy =
- | PolicyMerchantRefund
- | PolicyBrandtVickreyAuction
- | PolicyEscrowedPayment;
+.. _reserve-history:
- .. ts:def:: PolicyMerchantRefund
+---------------
+Reserve History
+---------------
- // CAVEAT: THIS IS STILL WORK IN PROGRESS.
- // This policy is optional and might not be supported by the exchange.
- // If it does, the exchange MUST show support for this policy in the
- // ``extensions`` field in the response to ``/keys``.
- interface PolicyMerchantRefund {
- type: "merchant_refund";
+.. http:get:: /reserves/$RESERVE_PUB/history
- // EdDSA `public key of the merchant <merchant-pub>`, so that the client
- // can identify the merchant for refund requests.
- merchant_pub: EddsaPublicKey;
+ Request information about the full history of
+ a reserve or an account.
- // Date until which the merchant can issue a refund to the customer via
- // the ``/extensions/policy_refund``-endpoint of the exchange.
- deadline: Timestamp;
+ **Request:**
+
+ The GET request should come with the following HTTP headers:
+
+ *If-None-Match*:
+ The client MAY provide an ``If-None-Match`` header with an
+ Etag. In that case, the server MUST additionally respond with an ``304``
+ status code in case the reserve history matches the provided Etag.
+
+ *Taler-Reserve-History-Signature*:
+ The client MUST provide Base-32 encoded
+ EdDSA signature over a ``TALER_SIGNATURE_RESERVE_HISTORY_REQUEST`` made with
+ the respective ``$RESERVE_PRIV``, affirming desire to download the current
+ reserve transaction history.
+
+ :query start=OFFSET: *Optional.* Only return reserve history entries with
+ offsets above the given OFFSET. Allows clients to not
+ retrieve history entries they already have.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The exchange responds with a `ReserveHistory` object; the reserve was known to the exchange.
+ :http:statuscode:`204 No content`:
+ The reserve history is known, but at this point from the given starting point it is empty. Can only happen if OFFSET was positive.
+ :http:statuscode:`304 Not modified`:
+ The reserve history matches the one identified by the "If-none-match" HTTP header of the request.
+ :http:statuscode:`403 Forbidden`:
+ The *TALER_SIGNATURE_RESERVE_HISTORY_REQUEST* is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not found`:
+ The reserve key does not belong to a reserve known to the exchange.
+
+ **Details:**
+
+ .. ts:def:: ReserveHistory
+
+ interface ReserveHistory {
+ // Balance left in the reserve.
+ balance: Amount;
+
+ // If set, gives the maximum age group that the client is required to set
+ // during withdrawal.
+ maximum_age_group: Integer;
+
+ // Transaction history for this reserve.
+ // May be partial (!).
+ history: TransactionHistoryItem[];
}
- .. ts:def:: PolicyBrandtVickreyAuction
+ Objects in the transaction history have the following format:
- // CAVEAT: THIS IS STILL WORK IN PROGRESS.
- // This policy is optional and might not be supported by the exchange.
- // If it does, the exchange MUST show support for this policy in the
- // ``extensions`` field in the response to ``/keys``.
- interface PolicyBrandtVickreyAuction {
- type: "brandt_vickrey_auction";
+ .. ts:def:: TransactionHistoryItem
- // Public key of this bidder.
- //
- // The bidder uses this key to sign the auction information and
- // the messages it sends to the seller during the auction.
- bidder_pub: EddsaPublicKey;
+ // Union discriminated by the "type" field.
+ type TransactionHistoryItem =
+ | AccountSetupTransaction
+ | ReserveWithdrawTransaction
+ | ReserveCreditTransaction
+ | ReserveClosingTransaction
+ | ReserveOpenRequestTransaction
+ | ReserveCloseRequestTransaction
+ | PurseMergeTransaction;
- // Hash of the auction terms
- //
- // The hash should be taken over a normalized JSON object of type
- // `BrandtVickreyAuction`.
- h_auction: HashCode;
+ .. ts:def:: AccountSetupTransaction
- // The amount that this bidder commits to for this auction
- //
- // This amount can be larger than the contribution of a single coin.
- // The bidder can increase funding of this auction policy by using
- // sufficiently many coins during the deposit operation (single or batch)
- // with the same policy.
- commitment: Amount;
+ interface AccountSetupTransaction {
+ type: "SETUP";
+
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
+
+ // KYC fee agreed to by the reserve owner.
+ kyc_fee: Amount;
+
+ // Time when the KYC was triggered.
+ kyc_timestamp: Timestamp;
+
+ // Hash of the wire details of the account.
+ // Note that this hash is unsalted and potentially
+ // private (as it could be inverted), hence access
+ // to this endpoint must be authorized using the
+ // private key of the reserve.
+ h_wire: HashCode;
+
+ // Signature created with the reserve's private key.
+ // Must be of purpose ``TALER_SIGNATURE_ACCOUNT_SETUP_REQUEST`` over
+ // a ``TALER_AccountSetupRequestSignaturePS``.
+ reserve_sig: EddsaSignature;
- // Date until the auction must have been successfully executed and
- // a valid transcript provided to the
- // ``/extensions/policy_brandt_vickrey_auction``-endpoint of the
- // exchange.
- //
- // [If the auction has not been executed by then] OR [has been executed
- // before then, but this bidder did not win], the coin's value doesn't
- // change and the owner can refresh the coin.
- //
- // If this bidder won the auction, the winning price/amount from the
- // outcome will be substracted from the coin and transfered to the
- // merchant's ``payout_uri`` from the deposit request (minus a potential
- // auction fee). For any remaining value, the bidder can refresh the
- // coin to retrieve change.
- deadline: Timestamp;
}
- .. ts:def:: BrandtVickreyAuction
+ .. ts:def:: ReserveWithdrawTransaction
- // CAVEAT: THIS IS STILL WORK IN PROGRESS.
- // This structure defines an auction of Brandt-Vickory kind.
- // It is used for the `PolicyBrandtVickreyAuction`.
- interface BrandtVickreyAuction {
- // Start date of the auction
- time_start: Timestamp;
+ interface ReserveWithdrawTransaction {
+ type: "WITHDRAW";
- // Maximum duration per round. There are four rounds in an auction of
- // Brandt-Vickrey kind.
- time_round: RelativeTime;
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
- // This integer m refers to the (m+1)-type of the Brandt-Vickrey-auction.
- // - Type 0 refers to an auction with one highest-price winner,
- // - Type 1 refers to an auction with one winner, paying the second
- // highest price,
- // - Type 2 refers to an auction with two winners, paying
- // the third-highest price,
- // - etc.
- auction_type: Integer;
+ // Amount withdrawn.
+ amount: Amount;
- // The vector of prices for the Brandt-Vickrey auction. The values MUST
- // be in strictly increasing order.
- prices: Amount[];
+ // Total fee that is charged for withdraw.
+ withdraw_fee: Amount;
- // The type of outcome of the auction.
- // In case the auction is declared public, each bidder can calculate the
- // winning price. This field is not relevant for the replay of a
- // transcript, as the transcript must be provided by the seller who sees
- // the winner(s) and winning price of the auction.
- outcome_public: boolean;
+ // Total number of coins in the withdraw request
+ num_coins: Integer;
- // The public key of the seller.
- pubkey: EddsaPublicKey;
+ // Signature over a `TALER_WithdrawRequestPS`
+ // with purpose ``TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW``
+ // created with the reserve's private key.
+ reserve_sig: EddsaSignature;
- // The seller's account details as a full payto URI.
- payto_uri: string;
+ // The hash of the all the planchets that were provided during the
+ // call to /withdraw.
+ h_planchets: HashCode;
+
+ // The blinding seed that was provided. It will be NULL if
+ // no denominations of cipher type Clause-Schnorr were invovled
+ blinding_seed?: BlindingMasterSeed;
+
+ // The array of hashes of public key of denominations for the coins.
+ denom_pub_hashes: HashCode[];
+
+ // The maximum age committed to, if the withdraw request
+ // required age-restriction
+ max_age?: Integer;
+
+ // The noreveal index that was returned as part
+ // of a age-restricted withdraw, if applicable
+ noreveal_index?: Integer;
+
+ }
+
+
+ .. ts:def:: ReserveCreditTransaction
+
+ interface ReserveCreditTransaction {
+ type: "CREDIT";
+
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
+
+ // Amount deposited.
+ amount: Amount;
+
+ // Sender account full payto:// URI.
+ sender_account_url: string;
+
+ // Opaque identifier internal to the exchange that
+ // uniquely identifies the wire transfer that credited the reserve.
+ wire_reference: Integer;
+
+ // Timestamp of the incoming wire transfer.
+ timestamp: Timestamp;
}
- .. ts:def:: PolicyEscrowedPayment
+ .. ts:def:: ReserveClosingTransaction
- // CAVEAT: THIS IS STILL WORK IN PROGRESS
- // This policy is optional and might not be supported by the exchange.
- // If it does, the exchange MUST show support for this policy in the
- // ``extensions`` field in the response to ``/keys``.
- interface PolicyEscrowedPayment {
- type: "escrowed_payment";
+ interface ReserveClosingTransaction {
+ type: "CLOSING";
- // Public key of this trustor, the owner of the coins.
- //
- // To claim the deposit, the merchant must provide the valid signature
- // of the ``h_contract_terms`` field from the deposit, signed by _this_
- // key, to the ``/extensions/policy_escrow``-endpoint of the exchange,
- // after the date specified in ``not_before`` and before the date
- // specified in ``not_after``.
- trustor_pub: EddsaPublicKey;
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
+
+ // Closing balance.
+ amount: Amount;
+
+ // Closing fee charged by the exchange.
+ closing_fee: Amount;
+
+ // Wire transfer subject.
+ wtid: Base32;
+
+ // Full payto URI of the wire account into which the funds were returned to.
+ receiver_account_details: string;
+
+ // This is a signature over a
+ // struct `TALER_ReserveCloseConfirmationPS` with purpose
+ // ``TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED``.
+ exchange_sig: EddsaSignature;
+
+ // Public key used to create 'exchange_sig'.
+ exchange_pub: EddsaPublicKey;
+
+ // Time when the reserve was closed.
+ timestamp: Timestamp;
+ }
+
+
+ .. ts:def:: ReserveOpenRequestTransaction
+
+ interface ReserveOpenRequestTransaction {
+ type: "OPEN";
+
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
+
+ // Open fee paid from the reserve.
+ open_fee: Amount;
+
+ // This is a signature over
+ // a struct `TALER_ReserveOpenPS` with purpose
+ // ``TALER_SIGNATURE_WALLET_RESERVE_OPEN``.
+ reserve_sig: EddsaSignature;
+
+ // Timestamp of the open request.
+ request_timestamp: Timestamp;
+
+ // Requested expiration.
+ requested_expiration: Timestamp;
+
+ // Requested number of free open purses.
+ requested_min_purses: Integer;
+
+ }
+
+ .. ts:def:: ReserveCloseRequestTransaction
+
+ interface ReserveCloseRequestTransaction {
+ type: "CLOSE";
+
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
+
+ // This is a signature over
+ // a struct `TALER_ReserveClosePS` with purpose
+ // ``TALER_SIGNATURE_WALLET_RESERVE_CLOSE``.
+ reserve_sig: EddsaSignature;
+
+ // Hash over the full payto URI of the target account.
+ h_payto?: FullPaytoHash;
- // Latest date by which the deposit must be claimed. If the deposit
- // has not been claimed by that date, the deposited coins can be
- // refreshed by the (still) owner.
- deadline: Timestamp;
+ // Timestamp of the close request.
+ request_timestamp: Timestamp;
}
- The deposit operation succeeds if the coin is valid for making a deposit and
- has enough residual value that has not already been deposited or melted.
+ .. ts:def:: PurseMergeTransaction
- .. ts:def:: DepositSuccess
+ interface PurseMergeTransaction {
+ type: "MERGE";
- interface DepositSuccess {
- // Optional base URL of the exchange for looking up wire transfers
- // associated with this transaction. If not given,
- // the base URL is the same as the one used for this request.
- // Can be used if the base URL for ``/transactions/`` differs from that
- // for ``/coins/``, i.e. for load balancing. Clients SHOULD
- // respect the ``transaction_base_url`` if provided. Any HTTP server
- // belonging to an exchange MUST generate a 307 or 308 redirection
- // to the correct base URL should a client uses the wrong base
- // URL, or if the base URL has changed since the deposit.
- transaction_base_url?: string;
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
- // Timestamp when the deposit was received by the exchange.
- exchange_timestamp: Timestamp;
+ // SHA-512 hash of the contact of the purse.
+ h_contract_terms: HashCode;
- // `Public EdDSA key of the exchange <sign-key-pub>` that was used to
- // generate the signature.
- // Should match one of the exchange's signing keys from ``/keys``. It is given
- // explicitly as the client might otherwise be confused by clock skew as to
- // which signing key was used.
- exchange_pub: EddsaPublicKey;
+ // EdDSA public key used to approve merges of this purse.
+ merge_pub: EddsaPublicKey;
- // Deposit confirmation signature from the exchange.
- // The EdDSA signature of `TALER_DepositConfirmationPS` using a current
- // `signing key of the exchange <sign-key-priv>` affirming the successful
- // deposit and that the exchange will transfer the funds after the refund
- // deadline, or as soon as possible if the refund deadline is zero.
- exchange_sig: EddsaSignature;
- }
+ // Minimum age required for all coins deposited into the purse.
+ min_age: Integer;
- .. ts:def:: DepositDoubleSpendError
+ // Number that identifies who created the purse
+ // and how it was paid for.
+ flags: Integer;
- interface DepositDoubleSpendError {
+ // Purse public key.
+ purse_pub: EddsaPublicKey;
- // Must be TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS
- // or TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY
- code: Integer;
+ // EdDSA signature of the account/reserve affirming the merge
+ // over a `TALER_AccountMergeSignaturePS`.
+ // Must be of purpose ``TALER_SIGNATURE_ACCOUNT_MERGE``
+ reserve_sig: EddsaSignature;
- // A string explaining that the user tried to
- // double-spend.
- hint: string;
+ // Client-side timestamp of when the merge request was made.
+ merge_timestamp: Timestamp;
- // EdDSA public key of a coin being double-spent.
- coin_pub: EddsaPublicKey;
+ // 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 should be
+ // auto-refunded.
+ purse_expiration: Timestamp;
- // Hash of the public key of the denomination of the coin.
- h_denom_pub: HashCode;
+ // Purse fee the reserve owner paid for the purse creation.
+ purse_fee: Amount;
+
+ // Total amount merged into the reserve.
+ // (excludes fees).
+ amount: Amount;
+ // True if the purse was actually merged.
+ // If false, only the purse_fee has an impact
+ // on the reserve balance!
+ merged: boolean;
}
-----------
-Refreshing
-----------
-Refreshing creates ``n`` new coins from ``m`` old coins, where the sum of
-denominations of the new coins must be smaller than the sum of the old coins'
-denominations plus melting (refresh) and withdrawal fees charged by the exchange.
-The refreshing API can be used by wallets to melt partially spent coins, making
-transactions with the freshly exchangeed coins unlinkabe to previous transactions
-by anyone except the wallet itself.
+.. _coin-history:
-.. _melt:
-.. http:post:: /melt
+------------
+Coin History
+------------
- "Melts" a coin. Invalidates the coins and prepares for exchanging of fresh
- coins. Taler uses a global parameter ``kappa`` for the cut-and-choose
- component of the protocol, for which this request is the commitment. Thus,
- various arguments are given ``kappa``-times in this step. At present ``kappa``
- is always 3.
+.. http:get:: /coins/$COIN_PUB/history
- The base URL for ``/melt/``-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.
+Obtain the transaction history of a coin. Used only in special cases, like
+when the exchange claims a double-spending error and the wallet does not
+believe it. Usually, the wallet knows the transaction history of each coin
+and thus has no need to inquire.
+
+**Request:**
+
+The GET request should come with the following HTTP headers:
+
+*If-None-Match*:
+ The client MAY provide an ``If-None-Match`` header with an
+ Etag. In that case, the server MUST additionally respond with an ``304``
+ status code in case the coin history matches the provided Etag.
- This endpoint was introduced in this form in protocol **vDOLDPLUS**.
+*Taler-Coin-History-Signature*:
+ The client MUST provide Base-32 encoded EdDSA signature over a
+ ``TALER_SIGNATURE_COIN_HISTORY_REQUEST`` made with the respective
+ ``$COIN_PRIV``, affirming desire to download the current coin
+ transaction history.
+
+:query start=OFFSET: *Optional.* Only return coin history entries with
+ offsets above the given OFFSET. Allows clients to not
+ retrieve history entries they already have.
+
+**Response:**
- :http:statuscode:`200 OK`:
- The request was successful. The response body is `MeltResponse` in this case.
- :http:statuscode:`403 Forbidden`:
- One of the signatures is invalid.
- :http:statuscode:`404 Not found`:
- The exchange does not recognize the denomination key as belonging to the exchange,
- or it has expired.
- 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
- (``TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS`` or
- ``TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY``).
- The response is `DepositDoubleSpendError` in both cases.
- :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
- `DenominationGoneMessage`. Clients must evaluate
- the error code provided to understand which of the
- cases this is and handle it accordingly.
+:http:statuscode:`200 OK`:
+ The operation succeeded, the exchange confirms that no double-spending took
+ place. The response will include a `CoinHistoryResponse` object.
+:http:statuscode:`204 No content`:
+ The reserve history is known, but at this point from the given starting point it is empty. Can only happen if OFFSET was positive.
+:http:statuscode:`304 Not modified`:
+ The coin history has not changed since the previous query (detected via Etag
+ in "If-none-match" header).
+:http:statuscode:`403 Forbidden`:
+ The *TALER_SIGNATURE_COIN_HISTORY_REQUEST* is invalid.
+ This response comes with a standard `ErrorDetail` response.
+:http:statuscode:`404 Not found`:
+ The coin public key is not (yet) known to the exchange.
- **Details:**
+**Details:**
- .. ts:def:: MeltRequest
+.. ts:def:: CoinHistoryResponse
- interface MeltRequest {
- // The old coin's public key
- old_coin_pub: CoinPublicKey;
+ interface CoinHistoryResponse {
+ // Current balance of the coin.
+ balance: Amount;
- // Hash of the denomination public key of the old coin, to determine total coin value.
- old_denom_pub_h: HashCode;
+ // Hash of the coin's denomination.
+ h_denom_pub: HashCode;
- // The hash of the age-commitment for the old coin. Only present
- // if the denomination has support for age restriction.
- old_age_commitment_h?: AgeCommitmentHash;
+ // Transaction history for the coin.
+ history: CoinSpendHistoryItem[];
+ }
- // Signature over the old `coin public key <eddsa-coin-pub>` by the denomination.
- old_denom_sig: DenominationSignature;
+.. ts:def:: CoinSpendHistoryItem
- // Amount of the value of the old coin that should be melted as part of
- // this refresh operation, including melting fee. I.e.:
- // melting fee of the old coin
- // + sum over all values of fresh coins
- // + sum over all withdraw fees for the fresh coins
- value_with_fee: Amount;
+ // Union discriminated by the "type" field.
+ type CoinSpendHistoryItem =
+ | CoinDepositTransaction
+ | CoinMeltTransaction
+ | CoinRefundTransaction
+ | CoinRecoupTransaction
+ | CoinOldCoinRecoupTransaction
+ | CoinRecoupRefreshTransaction
+ | CoinPurseDepositTransaction
+ | CoinPurseRefundTransaction
+ | CoinReserveOpenDepositTransaction;
+
+.. ts:def:: CoinDepositTransaction
+
+ interface CoinDepositTransaction {
+ type: "DEPOSIT";
+
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
+
+ // The total amount of the coin's value absorbed (or restored in the
+ // case of a refund) by this transaction.
+ // The amount given includes
+ // the deposit fee. The current coin value can thus be computed by
+ // subtracting this amount.
+ amount: Amount;
+
+ // Deposit fee.
+ deposit_fee: Amount;
+
+ // Public key of the merchant.
+ merchant_pub: EddsaPublicKey;
+
+ // Date when the operation was made.
+ timestamp: Timestamp;
+
+ // Date until which the merchant can issue a refund to the customer via the
+ // exchange, possibly zero if refunds are not allowed.
+ refund_deadline?: Timestamp;
+
+ // Hash over the proposal data of the contract that
+ // is being paid.
+ h_contract_terms: HashCode;
+
+ // Hash of the bank account from where we received the funds.
+ h_wire: HashCode;
+
+ // Hash of the public denomination key used to sign the coin.
+ // Needed because 'coin_sig' signs over this, and
+ // that is important to fix the coin's denomination.
+ h_denom_pub: HashCode;
+
+ // Hash over the deposit policy extension. Optional.
+ h_policy?: HashCode;
+
+ // Hash over auxiliary wallet data provided by the wallet
+ // to complete the contract. Optional.
+ wallet_data_hash?: HashCode;
+
+ // Hash over the age commitment of the coin. Optional.
+ h_age_commitment?: HashCode;
+
+ // Signature over `TALER_DepositRequestPS`, made by the customer with the
+ // `coin's private key <coin-priv>`.
+ coin_sig: EddsaSignature;
+
+ }
+
+.. ts:def:: CoinMeltTransaction
+
+ interface CoinMeltTransaction {
+ type: "MELT";
+
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
+
+ // The total amount of the coin's value absorbed by this transaction.
+ // Note that for melt this means the amount given includes
+ // the melt fee. The current coin value can thus be computed by
+ // subtracting the amounts.
+ amount: Amount;
- // @since v27
- // @deprecated vDOLDPLUS
- // Seed from which the nonces for the n*κ coin candidates are derived from.
- refresh_seed: HashCode;
+ // Melt fee.
+ melt_fee: Amount;
+
+ // Commitment from the melt operation, see `TALER_RefreshCommitmentP`
+ rc: HashCode;
+
+ // Hash of the public denomination key used to sign the old coin.
+ // Needed because 'coin_sig' signs over this, and
+ // that is important to fix the coin's denomination.
+ old_denom_pub_h: HashCode;
+
+ // Hash over the age commitment of the coin. Optional.
+ old_age_commitment_h?: AgeCommitmentHash;
+
+ // @since vDOLDPLUS
+ // This value is opaque to the exchange. It was provided by the client
+ // as part of the original refresh request, and was therefore verified
+ // with the confirm_sig below.
+ // If the reveal step was not performed yet by the old coin owner,
+ // they can use this value and the old coin's private key to derive
+ // all indivual seeds for the n*κ coin candidates for the original
+ // refresh request and replay it
+ master_refresh_seed: HashCode;
+
+ // @since vDOLDPLUS
+ // The kappa*n list of transfer public keys that were provided by the
+ // old coin owner during the melt request.
+ transfer_pubs: EddsaPublicKey[kappa][];
+
+ // @since vDOLDPLUS
+ // The n denomination public keys for the fresh coins
+ // that the coin owner had requested.
+ denoms_h: HashCode[];
+
+ // @since vDOLDPLUS
+ // The ``noreveal_index`` value that was returned by the exchange as response
+ // to the melt request.
+ noreveal_index: Integer;
+
+ // @since vDOLDPLUS
+ // If the reveal step was successfully peformed by the coin owner,
+ // this field contains the blind coin signatures that were returned
+ // by the exchange for the chosen batch of coins.
+ ev_sigs?: BlindedDenominationSignature[];
- // @since vDOLDPLUS
- // This value is opaque to the exchange. It was provided by the client
- // as part of the original refresh request, and was therefore
- // verified with the coin_sig below.
- //
- // Note: The honest owner of the old coin SHOULD use this value
- // and the old coin's private key to derive kappa many
- // transfer secret seeds like this:
- // ``ts_seeds[k] = SHA512(master_refresh_seed, old_coin_priv, "s", k)``
- // Each of the kappa seeds is then expanded via HKDF:
- // ``ts[k][] = HKDF(sizeof(HashCode)*n, ts_seeds[k], "ts")``
- // An individual coin's transfer secret at kappa-index k and
- // coin index i in the batch is then ``ts[k][i]``
- // This ensures that the honest owner of the old coin can replay
- // a MeltRequest from the coin history provided by the exchange
- // (which includes this value), in case a wallet was restored
- // from a backup into a state prior to the refresh operation.
- master_refresh_seed: HashCode;
+ // Master seed for the Clause-Schnorr R-value
+ // Present if one of the fresh coin's
+ // denominations is of type Clause-Schnorr.
+ blinding_seed?: BlindingMasterSeed;
- // Master seed for the Clause-Schnorr R-value
- // creation. Must match the /blinding-prepare 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.
- blinding_seed?: BlindingMasterSeed;
+ // Signature by the coin over a
+ // `TALER_RefreshMeltCoinAffirmationPS` of
+ // purpose ``TALER_SIGNATURE_WALLET_COIN_MELT``.
+ confirm_sig: EddsaSignature;
- // Array of ``n`` new hash codes of denomination public keys
- // for the new coins to order.
- denoms_h: HashCode[];
+ }
- // ``kappa`` arrays of ``n`` entries for blinded coin candidates,
- // each matching the respective entries in ``denoms_h``.
- coin_evs: CoinEnvelope[kappa][];
+.. ts:def:: CoinRefundTransaction
- // @since vDOLDPLUS
- // ``kappa`` arrays of ``n`` entries of transfer public keys each.
- // These are ephemeral ECDHE keys that allow the owner of a coin
- // to (re-)obtain the derived coins from a refresh operation, f.e. should
- // the wallet state be restored from a backup, prior to the refresh operation.
- transfer_pubs: EddsaPublicKey[kappa][];
+ interface CoinRefundTransaction {
+ type: "REFUND";
- // Signature by the `coin <coin-priv>` over `TALER_RefreshMeltCoinAffirmationPS`.
- confirm_sig: EddsaSignature;
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
- }
+ // The total amount of the coin's value restored
+ // by this transaction.
+ // The amount given excludes the transaction fee.
+ // The current coin value can thus be computed by
+ // adding the amounts to the coin's denomination value.
+ amount: Amount;
- For details about the HKDF used to derive the new coin private keys and
- the blinding factors from ECDHE between the transfer public keys and
- the private key of the melted coin, please refer to the
- implementation in ``libtalerutil``.
+ // Refund fee.
+ refund_fee: Amount;
- .. ts:def:: MeltResponse
+ // Hash over the proposal data of the contract that
+ // is being refunded.
+ h_contract_terms: HashCode;
- interface MeltResponse {
- // Which of the ``kappa`` indices does the client not have to reveal
- // by calling the ``/reveal-melt`` endpoint.
- noreveal_index: Integer;
+ // Public key of the merchant.
+ merchant_pub: EddsaPublicKey;
- // Signature of `TALER_RefreshMeltConfirmationPS` whereby the exchange
- // affirms the successful melt and confirming the ``noreveal_index``.
- exchange_sig: EddsaSignature;
+ // Refund transaction ID.
+ rtransaction_id: Integer;
- // `Public EdDSA key <sign-key-pub>` of the exchange that was used to generate the signature.
- // Should match one of the exchange's signing keys from ``/keys``. Again given
- // explicitly as the client might otherwise be confused by clock skew as to
- // which signing key was used.
- exchange_pub: EddsaPublicKey;
+ // `EdDSA Signature <eddsa-sig>` authorizing the REFUND over a
+ // `TALER_MerchantRefundConfirmationPS` with
+ // purpose ``TALER_SIGNATURE_MERCHANT_REFUND_OK``. Made with
+ // the `public key of the merchant <merchant-pub>`.
+ merchant_sig: EddsaSignature;
+
+ }
+
+.. ts:def:: CoinRecoupTransaction
+
+ interface CoinRecoupTransaction {
+ type: "RECOUP";
- // Base URL to use for operations on the refresh context
- // (so the reveal operation). If not given,
- // the base URL is the same as the one used for this request.
- // Can be used if the base URL for ``/reveal-melt/`` differs from that
- // for ``/melt/``, i.e. for load balancing. Clients SHOULD
- // respect the reveal_base_url if provided. Any HTTP server
- // belonging to an exchange MUST generate a 307 or 308 redirection
- // to the correct base URL should a client uses the wrong base
- // URL, or if the base URL has changed since the melt.
- //
- // When melting the same coin twice (technically allowed
- // as the response might have been lost on the network),
- // the exchange may return different values for the ``reveal_base_url``.
- reveal_base_url?: string;
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
- }
+ // The total amount of the coin's value absorbed
+ // by this transaction.
+ // The current coin value can thus be computed by
+ // subtracting the amount from
+ // the coin's denomination value.
+ amount: Amount;
+
+ // Signature by the exchange over a
+ // `TALER_RecoupConfirmationPS`, must be
+ // of purpose ``TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP``.
+ exchange_sig: EddsaSignature;
+ // Public key of the private key used to create 'exchange_sig'.
+ exchange_pub: EddsaPublicKey;
-------
-Recoup
-------
+ // Signature by the coin over a
+ // `TALER_RecoupRequestPS` with purpose
+ // ``TALER_SIGNATURE_WALLET_COIN_RECOUP``.
+ coin_sig: EddsaSignature;
-The purpose of this API is to allow coins to be cashed back in,
-in certain exceptional situations.
-This API is only used if the exchange is either about to go out of
-business or has had its private signing keys compromised (so in
-either case, the protocol is only used in **abnormal**
-situations). In the above cases, the exchange signals to the
-wallets that the emergency cash back protocol has been activated
-by putting the affected denomination keys into the cash-back
-part of the ``/keys`` response. If and only if this has happened,
-coins that were signed with those denomination keys can be cashed
-in using this API.
+ // Hash of the public denomination key used to sign the coin.
+ // Needed because 'coin_sig' signs over this, and
+ // that is important to fix the coin's denomination.
+ h_denom_pub: HashCode;
-For a recoup, a coin has to provide the necessary information to
-identify the original transaction (either a withdraw or a refresh) it
-became minted, and proof ownership of the coin itself.
+ // Coin blinding key that was used in the original withdraw request.
+ coin_blind: DenominationBlindingKeyP;
+ // The hash of the withdraw commitment of the original withdraw
+ // request that this coin was part of
+ h_commitment: HashCode;
-.. http:post:: /recoup-withdraw
+ // Coin's index in the original withdraw request, starting at 0
+ coin_index: Integer;
- Demand that a batch of coins be refunded to the reserve,
- from which the coins were originally withdrawn.
- The coins must have been originated from the same call to withdraw, and be
- a subset of that original batch.
- The remaining amount on the coin will be credited to the reserve
- that the coins were withdrawn from, in the same withdraw request.
+ // Reserve receiving the recoup.
+ reserve_pub: EddsaPublicKey;
- Note that the original withdrawal fees will **not** be recouped.
+ // Date when the operation was made.
+ timestamp: Timestamp;
+
+ }
+
+.. ts:def:: CoinOldCoinRecoupTransaction
+
+ interface CoinOldCoinRecoupTransaction {
+ type: "OLD-COIN-RECOUP";
- .. note:: This endpoint still Work-in-Progress. It will be implemented in **vRECOUP**, sometime after **vDOLDPLUS**.
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
- **Request:**
+ // The total amount of the coin's value restored
+ // by this transaction.
+ // The current coin value can thus be computed by
+ // adding the amount to the coin's denomination value.
+ amount: Amount;
- The request body must be a `RecoupWithdrawRequest` object.
+ // Date when the operation was made.
+ timestamp: Timestamp;
- It provides sufficient information to
- a) identify the originating withdraw request
- b) proof that the coins to be recouped were part of that withdraw request
- c) proof ownership of all coins requested to be recouped.
+ // Signature by the exchange over a
+ // `TALER_RecoupRefreshConfirmationPS`
+ // of purpose ``TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH``.
+ exchange_sig: EddsaSignature;
- **Response:**
+ // Public key of the private key used to create 'exchange_sig'.
+ exchange_pub: EddsaPublicKey;
- :http:statuscode:`200 OK`:
- The request was successful, and the response is a `ReserveSummary`.
- :http:statuscode:`403 Forbidden`:
- A coin's signature is invalid.
- This response comes with a standard `ErrorDetail` response.
- :http:statuscode:`404 Not found`:
- A denomination key is unknown,
- the withdraw commitment is unknown
- or a blinded coin is not known to have been withdrawn.
- If a denomination key is unknown, the response will be
- a `DenominationUnknownMessage`.
- :http:statuscode:`409 Conflict`:
- The operation is not allowed
- as a coin has insufficient residual value,
- or because the same public key of a 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_FUNDS``).
- The response is a `DepositDoubleSpendError`.
- :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 not yet revoked.
- The response is a `DenominationGoneMessage`.
- Clients must evaluate the error code provided
- to understand which of the cases this is and handle it accordingly.
+ }
- **Details:**
+.. ts:def:: CoinRecoupRefreshTransaction
- .. ts:def:: RecoupWithdrawRequest
+ interface CoinRecoupRefreshTransaction {
+ type: "RECOUP-REFRESH";
- interface RecoupWithdrawRequest {
- // Public key of the reserve that will receive the recoup.
- // MUST be the same as the one from the original withdraw.
- reserve_pub: EddsaPublicKey;
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
- // The details about the coins:
- // An array of either
- // a) the hash code of a blinded coin envelope (not to be recouped)
- // b) the disclosed coin details, in order to recoup it.
- // From these, the hash of all coin envelopes
- // from the original withdraw can be reconstructed.
- coin_data: RecoupCoinData[];
- }
+ // The total amount of the coin's value absorbed
+ // by this transaction.
+ // The current coin value can thus be computed by
+ // subtracting this amounts from
+ // the coin's denomination value.
+ amount: Amount;
- .. ts:def:: RecoupCoinData
+ // Signature by the exchange over a
+ // `TALER_RecoupRefreshConfirmationPS`
+ // of purpose ``TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH``.
+ exchange_sig: EddsaSignature;
- // This is either
- // a) the hash code of a blinded coin envelope (not to be recouped)
- // b) the disclosed coin details, in order to recoup it.
- type RecoupCoinData =
- | NonRecoupedCoin
- | RecoupDisclosedCoinDetails;
+ // Public key used to sign 'exchange_sig'.
+ exchange_pub: EddsaPublicKey;
- .. ts:def:: NonRecoupedCoin
+ // FIXME-#9828: implementation returns old_coin_pub here
- interface NonRecoupedCoin {
- type: "non_recouped_coin";
+ // Signature by the coin over a `TALER_RecoupRequestPS`
+ // with purpose ``TALER_SIGNATURE_WALLET_COIN_RECOUP``.
+ coin_sig: EddsaSignature;
- // This is the SHA512 hash code of a blinded coin envelope,
- // including the corresponding denomination's hash.
- // It is the output of the TALER_coin_ev_hash function
- // from libtalerutil.
- coin_ev: BlindedCoinEnvelopeHash;
- };
+ // Hash of the public denomination key used to sign the coin.
+ // Needed because 'coin_sig' signs over this, and
+ // that is important to fix the coin's denomination.
+ h_denom_pub: HashCode;
- .. ts:def:: BlindedCoinEnvelopeHash
+ // Coin blinding key that was used in the original withdraw request.
+ coin_blind: DenominationBlindingKeyP;
- // The hash value of a blinded coin envelope,
- // as it its generated by the function TALER_coin_ev_hash
- // in libtalerutil.
- type BlindedCoinEnvelopeHash = HashCode;
+ // The hash of the withdraw commitment of the original withdraw
+ // request that this coin was part of
+ h_commitment: HashCode;
- .. ts:def:: RecoupDisclosedCoinDetails
+ // Coin's index in the original withdraw request, starting at 0
+ coin_index: Integer;
- // This object provides all necessary coin data
- // in order to call TALER_denom_blind and retrieve
- // a blinded coin planchet, from which we can
- // calculate the blinded coin envelope hash.
- // It also contains the denomination's signature
- // for the (unblinded) coin's public key,
- // and the coin's signature to authorize the recoup request.
- interface RecoupDisclosedCoinDetails {
- type: "recoup_coin_details";
+ // Blinding factor of the revoked new coin.
+ new_coin_blinding_secret: DenominationBlindingKeySecret;
- // The coin's public key
- coin_pub: CoinPublicKey;
+ // Blinded public key of the revoked new coin.
+ new_coin_ev: DenominationBlindingKeySecret;
- // The blinding secret for this coin
- // that was used during withdraw
- coin_blinding_key_secret: DenominationBlindingKeySecret;
+ // Date when the operation was made.
+ timestamp: Timestamp;
- // The coin's commitment for age restriction,
- // if the denomination had age restriction support.
- age_commitment_h?: AgeCommitmentHash;
+ }
- // The blinding nonce that went into this coin's
- // blinded envelope
- cs_session_nonce?: HashCode;
+.. ts:def:: CoinPurseDepositTransaction
- // In case of Clause-Schnorr denomination,
- // the blinding values that were provided
- // for this coin, by the exchange, as response
- // to a call to /blinding-prepare.
- cs_r_pubs?: CSRPublicPair;
+ interface CoinPurseDepositTransaction {
+ type: "PURSE-DEPOSIT";
- // Unblinded signature of the coins' public key,
- // signed by the denomination key.
- denom_pub_sig: DenominationSignature;
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
- // The denomination public key.
- // This denomination MUST be eligible for recoup,
- // i.e. being listed in the "recoup" section of /config.
- denom_pub_h: HashCode;
+ // The total amount of the coin's value absorbed
+ // by this transaction.
+ // Note that this means the amount given includes
+ // the deposit fee. The current coin value can thus be computed by
+ // subtracting the amount from
+ // the coin's denomination value.
+ amount: Amount;
- // Signature of `TALER_RecoupRequestPS`,
- // created by this coin's private key.
- coin_sig: EddsaSignature;
- }
+ // Base URL of the exchange the purse lives at.
+ exchange_base_url: string;
+ // The hash of the age-commitment for the coin. Only present
+ // if the denomination has support for age restriction.
+ h_age_commitment?: AgeCommitmentHash;
-.. http:post:: /recoup-refresh
+ // Deposit fee.
+ deposit_fee: Amount;
- Demand that a coin be refunded via wire transfer to the original owner.
+ // Public key of the purse.
+ purse_pub: EddsaPublicKey;
- The base URL for coin related 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.
+ // True if the deposit was refunded for any reason.
+ refunded: boolean;
- The remaining amount on the coin will be credited to
- the old coin that this coin was refreshed from.
+ // Signature by the coin over a
+ // `TALER_PurseDepositSignaturePS` of
+ // purpose ``TALER_SIGNATURE_PURSE_DEPOSIT``.
+ coin_sig: EddsaSignature;
- Note that the original refresh fees will **not** be recouped.
+ // Hash of the public denomination key used to sign the coin.
+ // Needed because 'coin_sig' signs over this, and
+ // that is important to fix the coin's denomination.
+ h_denom_pub: HashCode;
- .. note:: This endpoint still Work-in-Progress. It will be implemented in **vRECOUP**, sometime after **vDOLDPLUS**.
+ }
- **Request:**
+.. ts:def:: CoinPurseRefundTransaction
- The request body must be a `RecoupRefreshRequest` object.
+ interface CoinPurseRefundTransaction {
+ type: "PURSE-REFUND";
- **Response:**
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
- :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:`403 Forbidden`:
- The coin's signature is invalid.
- This response comes with a standard `ErrorDetail` response.
- :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
- `DenominationGoneMessage`. Clients must evaluate
- the error code provided to understand which of the
- cases this is and handle it accordingly.
+ // The total amount of the coin's value restored
+ // by this transaction.
+ // The amount given excludes the refund fee.
+ // The current coin value can thus be computed by
+ // adding the amount to the coin's denomination value.
+ amount: Amount;
- **Details:**
+ // Refund fee (of the coin's denomination). The deposit
+ // fee will be waived.
+ refund_fee: Amount;
- .. ts:def:: RecoupRefreshRequest
+ // Signature by the exchange over a
+ // ``TALER_CoinPurseRefundConfirmationPS``
+ // of purpose ``TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_REFUND``.
+ exchange_sig: EddsaSignature;
- interface RecoupRefreshRequest {
- // The coin's public key
- coin_pub: CoinPublicKey;
+ // Public key used to sign 'exchange_sig'.
+ exchange_pub: EddsaPublicKey;
- // Hash of denomination public key, specifying the type of coin the client
- // would like the exchange to pay back.
- denom_pub_hash: HashCode;
+ // Public key of the purse that expired.
+ purse_pub: EddsaPublicKey;
- // 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;
+.. ts:def:: CoinReserveOpenDepositTransaction
- // Signature of `TALER_RecoupRequestPS` created with
- // the `coin's private key <coin-priv>`.
- coin_sig: EddsaSignature;
+ interface CoinReserveOpenDepositTransaction {
+ type: "RESERVE-OPEN-DEPOSIT";
- // Coin's blinding factor.
- coin_blind_key_secret: DenominationBlindingKeySecret;
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
- // Nonce that was used by the exchange to derive
- // its private inputs from during withdraw. Only
- // present if the cipher of the revoked denomination
- // is of type Clause-Schnorr (CS).
- nonce?: CSNonce;
- }
+ // The total amount of the coin's value absorbed
+ // by this transaction.
+ // Note that this means the amount given includes
+ // the deposit fee.
+ coin_contribution: Amount;
+ // Signature of the reserve open operation being paid for.
+ reserve_sig: EddsaSignature;
- .. ts:def:: RecoupRefreshConfirmation
+ // Signature by the coin over a
+ // `TALER_ReserveOpenDepositSignaturePS` of
+ // purpose ``TALER_SIGNATURE_RESERVE_OPEN_DEPOSIT``.
+ coin_sig: EddsaSignature;
- interface RecoupRefreshConfirmation {
- // Public key of the old coin that will receive the recoup.
- old_coin_pub: EddsaPublicKey;
- }
+ }
-----------------------
@@ -4011,107 +4117,6 @@ typically also view the balance.)
}
-.. _exchange_refund:
-
--------
-Refunds
--------
-
-.. http:post:: /coins/$COIN_PUB/refund
-
- Undo deposit of the given coin, restoring its value.
-
- **Request:**
-
- The request body must be a `RefundRequest` object.
-
- **Response:**
-
- :http:statuscode:`200 OK`:
- The operation succeeded, the exchange confirms that the coin can now be refreshed. The response will include a `RefundSuccess` object.
- :http:statuscode:`403 Forbidden`:
- Merchant signature is invalid.
- This response comes with a standard `ErrorDetail` response.
- :http:statuscode:`404 Not found`:
- The refund operation failed as we could not find a matching deposit operation (coin, contract, transaction ID and merchant public key must all match).
- This response comes with a standard `ErrorDetail` response.
- :http:statuscode:`409 Conflict`:
- The exchange has previously received a refund request for the same coin, merchant and contract, but specifying a different amount for the same refund transaction ID. The response will be a `RefundFailure` object.
- :http:statuscode:`410 Gone`:
- It is too late for a refund by the exchange, the money was already sent to the merchant.
- This response comes with a standard `ErrorDetail` response.
- :http:statuscode:`412 Precondition failed`:
- The request transaction ID is identical to a previous refund request by the same
- merchant for the same coin and contract, but the refund amount differs. (The
- failed precondition is that the ``rtransaction_id`` is not unique.)
- The response will be a `RefundFailure` object with the conflicting refund request.
-
- **Details:**
-
- .. ts:def:: RefundRequest
-
- interface RefundRequest {
-
- // Amount to be refunded, can be a fraction of the
- // coin's total deposit value (including deposit fee);
- // must be larger than the refund fee.
- refund_amount: Amount;
-
- // SHA-512 hash of the contact of the merchant with the customer.
- h_contract_terms: HashCode;
-
- // 64-bit transaction id of the refund transaction between merchant and customer.
- rtransaction_id: Integer;
-
- // EdDSA public key of the merchant.
- merchant_pub: EddsaPublicKey;
-
- // EdDSA signature of the merchant over a
- // `TALER_RefundRequestPS` with purpose
- // ``TALER_SIGNATURE_MERCHANT_REFUND``
- // affirming the refund.
- merchant_sig: EddsaPublicKey;
-
- }
-
- .. ts:def:: RefundSuccess
-
- interface RefundSuccess {
-
- // The EdDSA :ref:`signature` (binary-only) with purpose
- // ``TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND`` over
- // a `TALER_RecoupRefreshConfirmationPS`
- // using a current signing key of the
- // exchange affirming the successful refund.
- exchange_sig: EddsaSignature;
-
- // Public EdDSA key of the exchange that was used to generate the signature.
- // Should match one of the exchange's signing keys from ``/keys``. It is given
- // explicitly as the client might otherwise be confused by clock skew as to
- // which signing key was used.
- exchange_pub: EddsaPublicKey;
- }
-
- .. ts:def:: RefundFailure
-
- interface RefundFailure {
-
- // Numeric error code unique to the condition, which can be either
- // related to the deposit value being insufficient for the requested
- // refund(s), or the requested refund conflicting due to refund
- // transaction number re-use (with different amounts).
- code: Integer;
-
- // Human-readable description of the error message.
- hint: string;
-
- // Information about the conflicting refund request(s).
- // This will not be the full history of the coin, but only
- // the relevant subset of the transactions.
- history: CoinSpendHistoryItem[];
- }
-
-
.. _exchange_w2w:
--------------------------
@@ -5590,7 +5595,7 @@ and freeze or unfreeze accounts suspected of money laundering.
interface EventCounter {
// Name of the statistic that is being returned.
- name: String;
+ name: string;
// Number of events of the specified type in
// the given range.
@@ -6100,7 +6105,7 @@ and freeze or unfreeze accounts suspected of money laundering.
// True if the attributes were filed by an AML officer,
// otherwise they were provided directly by the customer.
- by_aml_officer: Boolean;
+ by_aml_officer: boolean;
// The collected KYC data. NULL if the attribute data could not
// be decrypted (internal error of the exchange, likely the