[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-docs] branch master updated: update exchange REST API: remove pai
From: |
gnunet |
Subject: |
[taler-docs] branch master updated: update exchange REST API: remove paid history API, authenticate GET coin history API, add start offset and ETag specs for both histories |
Date: |
Mon, 18 Sep 2023 14:46:38 +0200 |
This is an automated email from the git hooks/post-receive script.
grothoff pushed a commit to branch master
in repository docs.
The following commit(s) were added to refs/heads/master by this push:
new 90448a05 update exchange REST API: remove paid history API,
authenticate GET coin history API, add start offset and ETag specs for both
histories
90448a05 is described below
commit 90448a05fae6b27db2825d3d77902a821b61a512
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Mon Sep 18 14:46:35 2023 +0200
update exchange REST API: remove paid history API, authenticate GET coin
history API, add start offset and ETag specs for both histories
---
core/api-exchange.rst | 1493 +++++++++++++++++++++++++------------------------
1 file changed, 775 insertions(+), 718 deletions(-)
diff --git a/core/api-exchange.rst b/core/api-exchange.rst
index 71a15454..e7934bff 100644
--- a/core/api-exchange.rst
+++ b/core/api-exchange.rst
@@ -1636,7 +1636,7 @@ exchange.
.. http:get:: /reserves/$RESERVE_PUB
- Request information about a reserve.
+ Request summary information about a reserve.
**Request:**
@@ -1667,970 +1667,906 @@ exchange.
}
-.. http:post:: /reserves/$RESERVE_PUB/status
+Withdraw
+~~~~~~~~
- Request information about a reserve or an account.
+.. http:post:: /csr-withdraw
- **Request:**
+ Obtain exchange-side input values in preparation for a
+ withdraw step for certain denomination cipher types,
+ specifically at this point for Clause-Schnorr blind
+ signatures.
- The request body must be a `ReserveStatusRequest` object.
+ **Request:** The request body must be a `WithdrawPrepareRequest` object.
**Response:**
:http:statuscode:`200 OK`:
- The exchange responds with a `ReserveStatus` object; the reserve was known
to the exchange.
- :http:statuscode:`403 Forbidden`:
- The *TALER_SIGNATURE_RESERVE_STATUS_REQUEST* signature is invalid.
- This response comes with a standard `ErrorDetail` response. Alternatively,
the provided timestamp is not close to the current time.
+ The request was successful, and the response is a
`WithdrawPrepareResponse`. Note that repeating exactly the same request
+ will again yield the same response (assuming none of the denomination is
expired).
:http:statuscode:`404 Not found`:
- The reserve key does not belong to a reserve known to the exchange.
+ The denomination key is not known to the exchange.
+ :http:statuscode:`410 Gone`:
+ The requested denomination key is not yet or no longer valid.
+ It either before the validity start, past the expiration or was revoked.
The response is a
+ `DenominationExpiredMessage`. Clients must evaluate
+ the error code provided to understand which of the
+ cases this is and handle it accordingly.
**Details:**
- .. ts:def:: ReserveStatusRequest
-
- interface ReserveStatusRequest {
- // Signature of purpose
- // ``TALER_SIGNATURE_RESERVE_STATUS_REQUEST`` over
- // a `TALER_ReserveStatusRequestSignaturePS`.
- reserve_sig: EddsaSignature;
-
- // Time when the client made the request.
- // Timestamp must be reasonably close to the time of
- // the exchange, otherwise the exchange may reject
- // the request.
- request_timestamp: Timestamp;
- }
+ .. ts:def:: WithdrawPrepareRequest
- .. ts:def:: ReserveStatus
+ interface WithdrawPrepareRequest {
- interface ReserveStatus {
- // Balance left in the reserve.
- balance: Amount;
+ // Nonce to be used by the exchange to derive
+ // its private inputs from. Must not have ever
+ // been used before.
+ nonce: CSNonce;
- // If set, gives the maximum age group that the client is required to set
- // during withdrawal.
- maximum_age_group: number;
+ // Hash of the public key of the denomination the
+ // request relates to.
+ denom_pub_hash: HashCode;
- // Transaction history for this reserve.
- // May be partial (!).
- history: TransactionHistoryItem[];
}
- Objects in the transaction history have the following format:
+ .. ts:def:: WithdrawPrepareResponse
- .. ts:def:: TransactionHistoryItem
+ type WithdrawPrepareResponse =
+ | ExchangeWithdrawValue;
- // Union discriminated by the "type" field.
- type TransactionHistoryItem =
- | AccountSetupTransaction
- | ReserveHistoryTransaction
- | ReserveWithdrawTransaction
- | ReserveAgeWithdrawTransaction
- | ReserveCreditTransaction
- | ReserveClosingTransaction
- | ReserveOpenRequestTransaction
- | ReserveCloseRequestTransaction
- | PurseMergeTransaction;
+ .. ts:def:: ExchangeWithdrawValue
- .. ts:def:: AccountSetupTransaction
+ type ExchangeWithdrawValue =
+ | ExchangeRsaWithdrawValue
+ | ExchangeCsWithdrawValue;
- interface AccountSetupTransaction {
- type: "SETUP";
+ .. ts:def:: ExchangeRsaWithdrawValue
- // KYC fee agreed to by the reserve owner.
- kyc_fee: Amount;
+ interface ExchangeRsaWithdrawValue {
+ cipher: "RSA";
+ }
- // Time when the KYC was triggered.
- kyc_timestamp: Timestamp;
+ .. ts:def:: ExchangeCsWithdrawValue
- // 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;
+ interface ExchangeCsWithdrawValue {
+ cipher: "CS";
- // Signature created with the reserve's private key.
- // Must be of purpose ``TALER_SIGNATURE_ACCOUNT_SETUP_REQUEST`` over
- // a ``TALER_AccountSetupRequestSignaturePS``.
- reserve_sig: EddsaSignature;
+ // CSR R0 value
+ r_pub_0: CsRPublic;
+ // CSR R1 value
+ r_pub_1: CsRPublic;
}
- .. ts:def:: ReserveHistoryTransaction
-
- interface ReserveHistoryTransaction {
- type: "HISTORY";
- // Fee agreed to by the reserve owner.
- amount: Amount;
+.. http:post:: /reserves/$RESERVE_PUB/withdraw
- // Time when the request was made.
- request_timestamp: Timestamp;
+ Withdraw a coin of the specified denomination. Note that the client should
+ commit all of the request details, including the private key of the coin and
+ the blinding factor, to disk *before* issuing this request, so that it can
+ recover the information if necessary in case of transient failures, like
+ power outage, network outage, etc.
- // Signature created with the reserve's private key.
- // Must be of purpose ``TALER_SIGNATURE_RESERVE_HISTORY_REQUEST`` over
- // a `TALER_ReserveHistoryRequestSignaturePS`.
- reserve_sig: EddsaSignature;
+ **Request:** The request body must be a `WithdrawRequest` object.
- }
+ **Response:**
- .. ts:def:: ReserveWithdrawTransaction
+ :http:statuscode:`200 OK`:
+ The request was successful, and the response is a `WithdrawResponse`.
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 signature is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not found`:
+ The denomination key or the reserve are not known to the exchange. If the
+ denomination key is unknown, this suggests a bug in the wallet as the
+ wallet should have used current denomination keys from ``/keys``.
+ In this case, the response will be a `DenominationUnknownMessage`.
+ If the reserve is unknown, the wallet should not report a hard error yet,
but
+ instead simply wait for up to a day, as the wire transaction might simply
+ not yet have completed and might be known to the exchange in the near
future.
+ In this case, the wallet should repeat the exact same request later again
+ using exactly the same blinded coin.
+ :http:statuscode:`409 Conflict`:
+ One of the following reasons occured:
- interface ReserveWithdrawTransaction {
- type: "WITHDRAW";
+ 1. The balance of the reserve is not sufficient to withdraw the coins of
the
+ indicated denominations. The response is `WithdrawError` object.
- // Amount withdrawn.
- amount: Amount;
+ 2. The reserve has a birthday set and requires a request to
``/age-withdraw`` instead.
+ The response comes with a standard `ErrorDetail` response with error-code
``TALER_EC_EXCHANGE_RESERVES_AGE_RESTRICTION_REQUIRED`` and an additional field
``maximum_allowed_age`` for the maximum age (in years) that the client can
commit to in the call to ``/age-withdraw``
+ :http:statuscode:`410 Gone`:
+ The requested denomination key is not yet or no longer valid.
+ It either before the validity start, past the expiration or was revoked.
The response is a
+ `DenominationExpiredMessage`. Clients must evaluate
+ the error code provided to understand which of the
+ cases this is and handle it accordingly.
+ :http:statuscode:`451 Unavailable for Legal Reasons`:
+ This reserve has received funds from a purse or the amount withdrawn
+ exceeds another legal threshold and thus the reserve must
+ be upgraded to an account (with KYC) before the withdraw can
+ complete. Note that this response does NOT affirm that the
+ withdraw will ultimately complete with the requested amount.
+ The user should be redirected to the provided location to perform
+ the required KYC checks to open the account before withdrawing.
+ Afterwards, the request should be repeated.
+ The response will be an `KycNeededRedirect` object.
- // Hash of the denomination public key of the coin.
- h_denom_pub: HashCode;
+ Implementation note: internally, we need to
+ distinguish between upgrading the reserve to an
+ account (due to P2P payment) and identifying the
+ owner of the origin bank account (due to exceeding
+ the withdraw amount threshold), as we need to create
+ a different payto://-URI for the KYC check depending
+ on the case.
- // Hash of the blinded coin to be signed.
- h_coin_envelope: HashCode;
- // Signature over a `TALER_WithdrawRequestPS`
- // with purpose ``TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW``
- // created with the reserve's private key.
- reserve_sig: EddsaSignature;
+ **Details:**
- // Fee that is charged for withdraw.
- withdraw_fee: Amount;
- }
+ .. ts:def:: DenominationExpiredMessage
- .. ts:def:: ReserveAgeWithdrawTransaction
+ interface DenominationExpiredMessage {
- interface ReserveAgeWithdrawTransaction {
- type: "AGEWITHDRAW";
+ // Taler error code. Note that beyond
+ // expiration this message format is also
+ // used if the key is not yet valid, or
+ // has been revoked.
+ code: number;
- // Total Amount withdrawn.
- amount: Amount;
+ // Signature by the exchange over a
+ // `TALER_DenominationExpiredAffirmationPS`.
+ // Must have purpose ``TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_EXPIRED``.
+ exchange_sig: EddsaSignature;
- // Commitment of all ``n*kappa`` blinded coins.
- h_commitment: HashCode;
+ // Public key of the exchange used to create
+ // the 'exchange_sig.
+ exchange_pub: EddsaPublicKey;
- // Signature over a `TALER_AgeWithdrawRequestPS`
- // with purpose ``TALER_SIGNATURE_WALLET_RESERVE_AGE_WITHDRAW``
- // created with the reserve's private key.
- reserve_sig: EddsaSignature;
+ // Hash of the denomination public key that is unknown.
+ h_denom_pub: HashCode;
- // Fee that is charged for withdraw.
- withdraw_fee: Amount;
- }
+ // When was the signature created.
+ timestamp: Timestamp;
+ // What kind of operation was requested that now
+ // failed?
+ oper: string;
+ }
- .. ts:def:: ReserveCreditTransaction
- interface ReserveCreditTransaction {
- type: "CREDIT";
+ .. ts:def:: WithdrawRequest
- // Amount deposited.
- amount: Amount;
+ interface WithdrawRequest {
+ // Hash of a denomination public key (RSA), specifying the type of coin
the client
+ // would like the exchange to create.
+ denom_pub_hash: HashCode;
- // Sender account ``payto://`` URL.
- sender_account_url: string;
+ // Coin's blinded public key, should be (blindly) signed by the
exchange's
+ // denomination private key.
+ coin_ev: CoinEnvelope;
- // Opaque identifier internal to the exchange that
- // uniquely identifies the wire transfer that credited the reserve.
- wire_reference: Integer;
+ // Signature of `TALER_WithdrawRequestPS` created with
+ // the `reserves's private key <reserve-priv>`
+ // using purpose ``TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW``.
+ reserve_sig: EddsaSignature;
- // Timestamp of the incoming wire transfer.
- timestamp: Timestamp;
}
+ .. ts:def:: WithdrawResponse
- .. ts:def:: ReserveClosingTransaction
+ interface WithdrawResponse {
+ // The blinded signature over the 'coin_ev', affirms the coin's
+ // validity after unblinding.
+ ev_sig: BlindedDenominationSignature;
- interface ReserveClosingTransaction {
- type: "CLOSING";
+ }
- // Closing balance.
- amount: Amount;
+ .. ts:def:: BlindedDenominationSignature
- // Closing fee charged by the exchange.
- closing_fee: Amount;
+ type BlindedDenominationSignature =
+ | RsaBlindedDenominationSignature
+ | CSBlindedDenominationSignature;
- // Wire transfer subject.
- wtid: Base32;
+ .. ts:def:: RsaBlindedDenominationSignature
- // ``payto://`` URI of the wire account into which the funds were
returned to.
- receiver_account_details: string;
+ interface RsaBlindedDenominationSignature {
+ cipher: "RSA";
- // 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;
+ // (blinded) RSA signature
+ blinded_rsa_signature: BlindedRsaSignature;
}
+ .. ts:def:: CSBlindedDenominationSignature
- .. ts:def:: ReserveOpenRequestTransaction
-
- interface ReserveOpenRequestTransaction {
- type: "OPEN";
-
- // Open fee paid from the reserve.
- open_fee: Amount;
+ interface CSBlindedDenominationSignature {
+ type: "CS";
- // This is a signature over
- // a struct `TALER_ReserveOpenPS` with purpose
- // ``TALER_SIGNATURE_WALLET_RESERVE_OPEN``.
- reserve_sig: EddsaSignature;
+ // Signer chosen bit value, 0 or 1, used
+ // in Clause Blind Schnorr to make the
+ // ROS problem harder.
+ b: Integer;
- // Timestamp of the open request.
- request_timestamp: Timestamp;
+ // Blinded scalar calculated from c_b.
+ s: Cs25519Scalar;
- // Requested expiration.
- requested_expiration: Timestamp;
+ }
- // Requested number of free open purses.
- requested_min_purses: Integer;
+ .. ts:def:: KycNeededRedirect
- }
+ interface KycNeededRedirect {
- .. ts:def:: ReserveCloseRequestTransaction
+ // Numeric `error code <error-codes>` unique to the condition.
+ // Should always be ``TALER_EC_EXCHANGE_GENERIC_KYC_REQUIRED``.
+ code: number;
- interface ReserveCloseRequestTransaction {
- type: "CLOSE";
+ // Human-readable description of the error, i.e. "missing parameter",
"commitment violation", ...
+ // Should give a human-readable hint about the error's nature. Optional,
may change without notice!
+ hint?: string;
- // This is a signature over
- // a struct `TALER_ReserveClosePS` with purpose
- // ``TALER_SIGNATURE_WALLET_RESERVE_CLOSE``.
- reserve_sig: EddsaSignature;
+ // Hash of the payto:// account URI that identifies
+ // the account which is being KYCed.
+ h_payto: PaytoHash;
- // Target account ``payto://``, optional.
- h_payto?: PaytoHash;
+ // Legitimization target that the merchant should
+ // use to check for its KYC status using
+ // the ``/kyc-check/$REQUIREMENT_ROW/...`` endpoint.
+ requirement_row: Integer;
- // Timestamp of the close request.
- request_timestamp: Timestamp;
}
- .. ts:def:: ReserveCreditTransaction
-
- interface ReserveCreditTransaction {
- type: "CREDIT";
+ .. ts:def:: WithdrawError
- // Amount deposited.
- amount: Amount;
+ interface WithdrawError {
+ // Text describing the error.
+ hint: string;
- // Sender account ``payto://`` URL.
- sender_account_url: string;
+ // Detailed error code.
+ code: Integer;
- // Opaque identifier internal to the exchange that
- // uniquely identifies the wire transfer that credited the reserve.
- wire_reference: Integer;
+ // Amount left in the reserve.
+ balance: Amount;
- // Timestamp of the incoming wire transfer.
- timestamp: Timestamp;
+ // History of the reserve's activity, in the same format
+ // as returned by ``/reserve/$RID/history``.
+ history: TransactionHistoryItem[]
}
- .. ts:def:: PurseMergeTransaction
-
- interface PurseMergeTransaction {
- type: "MERGE";
-
- // 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;
+Batch Withdraw
+~~~~~~~~~~~~~~
- // 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;
+.. http:post:: /reserves/$RESERVE_PUB/batch-withdraw
- // Client-side timestamp of when the merge request was made.
- merge_timestamp: Timestamp;
+ 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
+ recover the information if necessary in case of transient failures, like
+ power outage, network outage, etc.
- // 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;
+ **Request:** The request body must be a `BatchWithdrawRequest` object.
- // Purse fee the reserve owner paid for the purse creation.
- purse_fee: Amount;
+ **Response:**
- // Total amount merged into the reserve.
- // (excludes fees).
- amount: Amount;
+ :http:statuscode:`200 OK`:
+ The request was successful, and the response is a `BatchWithdrawResponse`.
+ 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`:
+ A signature is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not found`:
+ A denomination key or the reserve are not known to the exchange. If the
+ denomination key is unknown, this suggests a bug in the wallet as the
+ wallet should have used current denomination keys from ``/keys``.
+ In this case, the response will be a `DenominationUnknownMessage`.
+ If the reserve is unknown, the wallet should not report a hard error yet,
but
+ instead simply wait for up to a day, as the wire transaction might simply
+ not yet have completed and might be known to the exchange in the near
future.
+ In this case, the wallet should repeat the exact same request later again
+ using exactly the same blinded coin.
+ :http:statuscode:`409 Conflict`:
+ One of the following reasons occured:
- // True if the purse was actually merged.
- // If false, only the purse_fee has an impact
- // on the reserve balance!
- merged: boolean;
- }
+ 1. The balance of the reserve is not sufficient to withdraw the coins of
the
+ indicated denominations. The response is `WithdrawError` object.
+ 2. The reserve has a birthday set and requires a request to
``/age-withdraw`` instead.
+ The response comes with a standard `ErrorDetail` response with error-code
``TALER_EC_EXCHANGE_RESERVES_AGE_RESTRICTION_REQUIRED`` and an additional field
``maximum_allowed_age`` for the maximum age (in years) that the client can
commit to in the call to ``/age-withdraw``
+ :http:statuscode:`410 Gone`:
+ A requested denomination key is not yet or no longer valid.
+ It either before the validity start, past the expiration or was revoked.
+ The response is a `DenominationExpiredMessage`. Clients must evaluate the
+ error code provided to understand which of the cases this is and handle it
+ accordingly.
+ :http:statuscode:`451 Unavailable for Legal Reasons`:
+ This reserve has received funds from a purse or the amount withdrawn
+ exceeds another legal threshold and thus the reserve must
+ be upgraded to an account (with KYC) before the withdraw can
+ complete. Note that this response does NOT affirm that the
+ withdraw will ultimately complete with the requested amount.
+ The user should be redirected to the provided location to perform
+ the required KYC checks to open the account before withdrawing.
+ Afterwards, the request should be repeated.
+ The response will be an `KycNeededRedirect` object.
-.. http:post:: /reserves/$RESERVE_PUB/history
+ Implementation note: internally, we need to
+ distinguish between upgrading the reserve to an
+ account (due to P2P payment) and identifying the
+ owner of the origin bank account (due to exceeding
+ the withdraw amount threshold), as we need to create
+ a different payto://-URI for the KYC check depending
+ on the case.
- Request information about the full history of
- a reserve or an account.
- **Request:**
+ **Details:**
- The request body must be a `ReserveHistoryRequest` object.
+ .. ts:def:: BatchWithdrawRequest
- **Response:**
+ interface BatchWithdrawRequest {
+ // Array of requests for the individual coins to withdraw.
+ planchets: WithdrawRequest[];
- :http:statuscode:`200 OK`:
- The exchange responds with a `ReserveStatus` object; the reserve was known
to the exchange.
- :http:statuscode:`403 Forbidden`:
- The *TALER_SIGNATURE_RESERVE_HISTORY_REQUEST* is invalid.
- This response comes with a standard `ErrorDetail` response.
Alternatively, the provided timestamp is not close to the current time.
- :http:statuscode:`404 Not found`:
- The reserve key does not belong to a reserve known to the exchange.
- :http:statuscode:`412 Precondition failed`:
- The balance in the reserve is insufficient to pay for the history request.
- This response comes with a standard `ErrorDetail` response.
+ }
- **Details:**
- .. ts:def:: ReserveHistoryRequest
+ .. ts:def:: BatchWithdrawResponse
- interface ReserveHistoryRequest {
- // Signature of type
- // ``TALER_SIGNATURE_RESERVE_HISTORY_REQUEST``
- // over a `TALER_ReserveHistoryRequestSignaturePS`.
- reserve_sig: EddsaSignature;
+ interface BatchWithdrawResponse {
+ // Array of blinded signatures, in the same order as was
+ // given in the request.
+ ev_sigs: WithdrawResponse[];
- // Time when the client made the request.
- // Timestamp must be reasonably close to the time of
- // the exchange, otherwise the exchange may reject
- // the request.
- request_timestamp: Timestamp;
}
+Withdraw with Age Restriction
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.. _delete-reserve:
-
-.. http:DELETE:: /reserves/$RESERVE_PUB
+If the reserve was marked with a maximum age group, the client has to perform a
+cut&choose protocol with the exchange. It first calls
+``/reserves/$RESERVE_PUB/age-withdraw`` and commits to ``n*kappa`` coins. On
+success, the exchange answers this request with an noreveal-index. The client
+then has to call ``/age-withdraw/$ACH/reveal`` to reveal all ``n*(kappa - 1)``
+coins along with their age commitments to proof that they were appropriate.
+If so, the exchange will blindly sign ``n`` undisclosed coins from the request.
- Forcefully closes a reserve.
- The request header must contain an *Account-Request-Signature*.
- Note: this endpoint is not currently implemented!
- **Request:**
+.. http:POST:: /reserves/$RESERVE_PUB/age-withdraw
- *Account-Request-Signature*: The client must provide Base-32 encoded EdDSA
signature made with ``$ACCOUNT_PRIV``, affirming its authorization to delete
the account. The purpose used MUST be ``TALER_SIGNATURE_RESERVE_CLOSE``.
+ Withdraw multiple coins *with age restriction* 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 recover the information if necessary in case of
+ transient failures, like power outage, network outage, etc.
- :query force=BOOLEAN: *Optional.* If set to 'true' specified, the exchange
- will delete the account even if there is a balance remaining.
+ **Request:** The request body must be a `AgeWithdrawRequest` object.
**Response:**
:http:statuscode:`200 OK`:
- The operation succeeded, the exchange provides details
- about the account deletion.
- The response will include a `ReserveClosedResponse` object.
+ The request was successful, and the response is a `AgeWithdrawResponse`.
+ 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 *Account-Request-Signature* is invalid.
+ A signature is invalid.
This response comes with a standard `ErrorDetail` response.
- :http:statuscode:`404 Not found`:
- The account is unknown to the exchange.
:http:statuscode:`409 Conflict`:
- The account is still has digital cash in it, the associated
- wire method is ``void`` and the *force* option was not provided.
- This response comes with a standard `ErrorDetail` response.
-
- **Details:**
-
- .. ts:def:: ReserveClosedResponse
+ One of two reasons occured:
- interface ReserveClosedResponse {
+ 1. The balance of the reserve is not sufficient to withdraw the coins of
the
+ given amount. The response is a `WithdrawError` object.
- // Final balance of the account.
- closing_amount: Amount;
-
- // Current time of the exchange, used as part of
- // what the exchange signs over.
- close_time: Timestamp;
-
- // Hash of the wire account into which the remaining
- // balance will be transferred. Note: may be the
- // hash over ``payto://void/`, in which case the
- // balance is forfeit to the profit of the exchange.
- h_wire: HashCode;
-
- // This is a signature over a
- // struct ``TALER_AccountDeleteConfirmationPS`` with purpose
- // ``TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED``.
- exchange_sig: EddsaSignature;
-
- }
-
-
-
-Withdraw
-~~~~~~~~
-
-.. http:post:: /csr-withdraw
-
- Obtain exchange-side input values in preparation for a
- withdraw step for certain denomination cipher types,
- specifically at this point for Clause-Schnorr blind
- signatures.
-
- **Request:** The request body must be a `WithdrawPrepareRequest` object.
-
- **Response:**
-
- :http:statuscode:`200 OK`:
- The request was successful, and the response is a
`WithdrawPrepareResponse`. Note that repeating exactly the same request
- will again yield the same response (assuming none of the denomination is
expired).
- :http:statuscode:`404 Not found`:
- The denomination key is not known to the exchange.
+ 2. The provided value for ``max_age`` is higher than the allowed value
according to the reserve's birthday.
+ The response comes with a standard `ErrorDetail` response with error-code
``TALER_EC_EXCHANGE_AGE_WITHDRAW_MAXIMUM_AGE_TOO_LARGE`` and an additional
field ``maximum_allowed_age`` for the maximum age (in years) that the client
can commit to in a call to ``/age-withdraw``
:http:statuscode:`410 Gone`:
- The requested denomination key is not yet or no longer valid.
- It either before the validity start, past the expiration or was revoked.
The response is a
- `DenominationExpiredMessage`. Clients must evaluate
- the error code provided to understand which of the
- cases this is and handle it accordingly.
-
- **Details:**
+ A requested denomination key is not yet or no longer valid.
+ It either before the validity start, past the expiration or was revoked.
+ The response is a `DenominationExpiredMessage`. Clients must evaluate the
+ error code provided to understand which of the cases this is and handle it
+ accordingly.
+ :http:statuscode:`451 Unavailable for Legal Reasons`:
+ This reserve has received funds from a purse or the amount withdrawn
+ exceeds another legal threshold and thus the reserve must
+ be upgraded to an account (with KYC) before the withdraw can
+ complete. Note that this response does NOT affirm that the
+ withdraw will ultimately complete with the requested amount.
+ The user should be redirected to the provided location to perform
+ the required KYC checks to open the account before withdrawing.
+ Afterwards, the request should be repeated.
+ The response will be an `KycNeededRedirect` object.
- .. ts:def:: WithdrawPrepareRequest
+ .. ts:def:: AgeWithdrawRequest
- interface WithdrawPrepareRequest {
+ interface AgeWithdrawRequest {
+ // Array of ``n`` hash codes of denomination public keys to order.
+ // These denominations MUST support age restriction as defined in the
+ // output to /keys.
+ // 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.
+ denoms_h: HashCode[];
- // Nonce to be used by the exchange to derive
- // its private inputs from. Must not have ever
- // been used before.
- nonce: CSNonce;
+ // ``n`` arrays of ``kappa`` entries with blinded coin envelopes. Each
+ // (toplevel) entry represents ``kappa`` canditates for a particular
+ // coin. The exchange will respond with an index ``gamma``, which is
+ // the index that shall remain undisclosed during the reveal phase.
+ // The SHA512 hash $ACH over the blinded coin envelopes is the commitment
+ // that is later used as the key to the reveal-URL.
+ blinded_coins_evs: CoinEnvelope[][];
- // Hash of the public key of the denomination the
- // request relates to.
- denom_pub_hash: HashCode;
+ // The maximum age to commit to. MUST be the same as the maximum
+ // age in the reserve.
+ max_age: number;
+ // Signature of `TALER_AgeWithdrawRequestPS` created with
+ // the `reserves's private key <reserve-priv>`
+ // using purpose ``TALER_SIGNATURE_WALLET_RESERVE_AGE_WITHDRAW``.
+ reserve_sig: EddsaSignature;
}
- .. ts:def:: WithdrawPrepareResponse
-
- type WithdrawPrepareResponse =
- | ExchangeWithdrawValue;
-
- .. ts:def:: ExchangeWithdrawValue
+ .. ts:def:: AgeWithdrawResponse
- type ExchangeWithdrawValue =
- | ExchangeRsaWithdrawValue
- | ExchangeCsWithdrawValue;
+ interface AgeWithdrawResponse {
+ // index of the commitments that the client doesn't
+ // have to disclose
+ noreveal_index: Integer;
- .. ts:def:: ExchangeRsaWithdrawValue
+ // Signature of `TALER_AgeWithdrawConfirmationPS` whereby
+ // the exchange confirms the ``noreveal_index``.
+ exchange_sig: EddsaSignature;
- interface ExchangeRsaWithdrawValue {
- cipher: "RSA";
+ // `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:: ExchangeCsWithdrawValue
-
- interface ExchangeCsWithdrawValue {
- cipher: "CS";
-
- // CSR R0 value
- r_pub_0: CsRPublic;
- // CSR R1 value
- r_pub_1: CsRPublic;
- }
+.. http:POST:: /age-withdraw/$ACH/reveal
-.. http:post:: /reserves/$RESERVE_PUB/withdraw
+ The client has previously committed to multiple coins with age restriction
+ in a call to ``/reserve/$RESERVE_PUB/age-withdraw`` and got a
+ `AgeWithdrawResponse` from the exchange. By calling this
+ endpoint, the client has to reveal each coin and their ``kappa - 1``
+ age commitments, except for the age commitments with index
+ ``noreveal_index``. The hash of all commitments from the former withdraw
+ request is given as the ``$ACH`` value in the URL to this endpoint.
- Withdraw a coin of the specified denomination. Note that the client should
- commit all of the request details, including the private key of the coin and
- the blinding factor, to disk *before* issuing this request, so that it can
- recover the information if necessary in case of transient failures, like
- power outage, network outage, etc.
- **Request:** The request body must be a `WithdrawRequest` object.
+ **Request:** The request body must be a `AgeWithdrawRevealRequest` object.
**Response:**
:http:statuscode:`200 OK`:
- The request was successful, and the response is a `WithdrawResponse`.
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 signature is invalid.
- This response comes with a standard `ErrorDetail` response.
+ The request was successful, and the response is a
`AgeWithdrawRevealResponse`.
+ 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:`404 Not found`:
- The denomination key or the reserve are not known to the exchange. If the
- denomination key is unknown, this suggests a bug in the wallet as the
- wallet should have used current denomination keys from ``/keys``.
- In this case, the response will be a `DenominationUnknownMessage`.
- If the reserve is unknown, the wallet should not report a hard error yet,
but
- instead simply wait for up to a day, as the wire transaction might simply
- not yet have completed and might be known to the exchange in the near
future.
- In this case, the wallet should repeat the exact same request later again
- using exactly the same blinded coin.
+ The provided commitment $ACH is unknown.
:http:statuscode:`409 Conflict`:
- One of the following reasons occured:
+ The reveal operation failed and the response is an `WithdrawError` object.
+ The error codes indicate one of two cases:
- 1. The balance of the reserve is not sufficient to withdraw the coins of
the
- indicated denominations. The response is `WithdrawError` object.
+ 1. An age commitment for at least one of the coins did not fulfill the
+ required maximum age requirement of the corresponding reserve.
+ Error code:
+ ``TALER_EC_EXCHANGE_GENERIC_COIN_AGE_REQUIREMENT_FAILURE``.
+ 2. The computation of the hash of the commitment with provided input does
+ result in the value $ACH.
+ Error code:
+ ``TALER_EC_EXCHANGE_AGE_WITHDRAW_REVEAL_INVALID_HASH``
- 2. The reserve has a birthday set and requires a request to
``/age-withdraw`` instead.
- The response comes with a standard `ErrorDetail` response with error-code
``TALER_EC_EXCHANGE_RESERVES_AGE_RESTRICTION_REQUIRED`` and an additional field
``maximum_allowed_age`` for the maximum age (in years) that the client can
commit to in the call to ``/age-withdraw``
- :http:statuscode:`410 Gone`:
- The requested denomination key is not yet or no longer valid.
- It either before the validity start, past the expiration or was revoked.
The response is a
- `DenominationExpiredMessage`. Clients must evaluate
- the error code provided to understand which of the
- cases this is and handle it accordingly.
- :http:statuscode:`451 Unavailable for Legal Reasons`:
- This reserve has received funds from a purse or the amount withdrawn
- exceeds another legal threshold and thus the reserve must
- be upgraded to an account (with KYC) before the withdraw can
- complete. Note that this response does NOT affirm that the
- withdraw will ultimately complete with the requested amount.
- The user should be redirected to the provided location to perform
- the required KYC checks to open the account before withdrawing.
- Afterwards, the request should be repeated.
- The response will be an `KycNeededRedirect` object.
- Implementation note: internally, we need to
- distinguish between upgrading the reserve to an
- account (due to P2P payment) and identifying the
- owner of the origin bank account (due to exceeding
- the withdraw amount threshold), as we need to create
- a different payto://-URI for the KYC check depending
- on the case.
+ .. ts:def:: AgeWithdrawRevealRequest
+ interface AgeWithdrawRevealRequest {
+ // Array of ``n`` of ``(kappa - 1)`` disclosed coin master secrets, from
+ // which the coins' private key, blinding, nonce (for Clause-Schnorr) and
+ // age-restriction is calculated.
+ //
+ // Given each coin's private key and age commitment, the exchange will
+ // calculate each coin's blinded hash value und use all those (disclosed)
+ // blinded hashes together with the non-disclosed envelopes ``coin_evs``
+ // during the verification of the original age-withdraw-commitment.
+ disclosed_coin_secrets: AgeRestrictedCoinSecret[][];
+ }
- **Details:**
+ .. ts:def:: AgeRestrictedCoinSecret
- .. ts:def:: DenominationExpiredMessage
+ // The Master key material from which the coins' private key ``coin_priv``,
+ // blinding ``beta`` and nonce ``nonce`` (for Clause-Schnorr) itself are
+ // derived as usually in wallet-core. Given a coin's master key material,
+ // the age commitment for the coin MUST be derived from this private key as
+ // follows:
+ //
+ // Let m ∈ {1,...,M} be the maximum age group as defined in the reserve
+ // that the wallet can commit to.
+ //
+ // For age group $AG ∈ {1,...m}, set
+ // seed = HDKF(coin_secret, "age-commitment", $AG)
+ // p[$AG] = Edx25519_generate_private(seed)
+ // and calculate the corresponding Edx25519PublicKey as
+ // q[$AG] = Edx25519_public_from_private(p[$AG])
+ //
+ // For age groups $AG ∈ {m,...,M}, set
+ // f[$AG] = HDKF(coin_secret, "age-factor", $AG)
+ // and calculate the corresponding Edx25519PublicKey as
+ // q[$AG] = Edx25519_derive_public(`PublishedAgeRestrictionBaseKey`,
f[$AG])
+ //
+ type AgeRestrictedCoinSecret = string;
- interface DenominationExpiredMessage {
+ .. ts:def:: PublishedAgeRestrictionBaseKey
- // Taler error code. Note that beyond
- // expiration this message format is also
- // used if the key is not yet valid, or
- // has been revoked.
- code: number;
+ // The value for ``PublishedAgeRestrictionBaseKey`` is a randomly chosen
+ // `Edx25519PublicKey` for which the private key is not known to the
clients. It is
+ // used during the age-withdraw protocol so that clients can proof that
they
+ // derived all public keys to age groups higher than their allowed maximum
+ // from this particular value.
+ const PublishedAgeRestrictionBaseKey =
+ new
Edx25519PublicKey("CH0VKFDZ2GWRWHQBBGEK9MWV5YDQVJ0RXEE0KYT3NMB69F0R96TG");
- // Signature by the exchange over a
- // `TALER_DenominationExpiredAffirmationPS`.
- // Must have purpose ``TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_EXPIRED``.
- exchange_sig: EddsaSignature;
+ .. ts:def:: AgeWithdrawRevealResponse
- // Public key of the exchange used to create
- // the 'exchange_sig.
- exchange_pub: EddsaPublicKey;
+ interface AgeWithdrawRevealResponse {
+ // List of the exchange's blinded RSA signatures on the new coins.
+ ev_sigs : BlindedDenominationSignature[];
+ }
- // Hash of the denomination public key that is unknown.
- h_denom_pub: HashCode;
- // When was the signature created.
- timestamp: Timestamp;
+.. _reserve-history:
- // What kind of operation was requested that now
- // failed?
- oper: string;
- }
+---------------
+Reserve History
+---------------
+.. http:get:: /reserves/$RESERVE_PUB/history
- .. ts:def:: WithdrawRequest
+ Request information about the full history of
+ a reserve or an account.
- interface WithdrawRequest {
- // Hash of a denomination public key (RSA), specifying the type of coin
the client
- // would like the exchange to create.
- denom_pub_hash: HashCode;
+ **Request:**
- // Coin's blinded public key, should be (blindly) signed by the
exchange's
- // denomination private key.
- coin_ev: CoinEnvelope;
+ The GET request should come with the following HTTP headers:
- // Signature of `TALER_WithdrawRequestPS` created with
- // the `reserves's private key <reserve-priv>`
- // using purpose ``TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW``.
- reserve_sig: EddsaSignature;
+ *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.
- .. ts:def:: WithdrawResponse
+ :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.
- interface WithdrawResponse {
- // The blinded signature over the 'coin_ev', affirms the coin's
- // validity after unblinding.
- ev_sig: BlindedDenominationSignature;
+ **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.
- .. ts:def:: BlindedDenominationSignature
+ **Details:**
- type BlindedDenominationSignature =
- | RsaBlindedDenominationSignature
- | CSBlindedDenominationSignature;
+ .. ts:def:: ReserveHistory
- .. ts:def:: RsaBlindedDenominationSignature
+ interface ReserveHistory {
+ // Balance left in the reserve.
+ balance: Amount;
- interface RsaBlindedDenominationSignature {
- cipher: "RSA";
+ // If set, gives the maximum age group that the client is required to set
+ // during withdrawal.
+ maximum_age_group: number;
- // (blinded) RSA signature
- blinded_rsa_signature: BlindedRsaSignature;
+ // Transaction history for this reserve.
+ // May be partial (!).
+ history: TransactionHistoryItem[];
}
- .. ts:def:: CSBlindedDenominationSignature
-
- interface CSBlindedDenominationSignature {
- type: "CS";
+ Objects in the transaction history have the following format:
- // Signer chosen bit value, 0 or 1, used
- // in Clause Blind Schnorr to make the
- // ROS problem harder.
- b: Integer;
+ .. ts:def:: TransactionHistoryItem
- // Blinded scalar calculated from c_b.
- s: Cs25519Scalar;
+ // Union discriminated by the "type" field.
+ type TransactionHistoryItem =
+ | AccountSetupTransaction
+ | ReserveWithdrawTransaction
+ | ReserveAgeWithdrawTransaction
+ | ReserveCreditTransaction
+ | ReserveClosingTransaction
+ | ReserveOpenRequestTransaction
+ | ReserveCloseRequestTransaction
+ | PurseMergeTransaction;
- }
+ .. ts:def:: AccountSetupTransaction
- .. ts:def:: KycNeededRedirect
+ interface AccountSetupTransaction {
+ type: "SETUP";
- interface KycNeededRedirect {
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
- // Numeric `error code <error-codes>` unique to the condition.
- // Should always be ``TALER_EC_EXCHANGE_GENERIC_KYC_REQUIRED``.
- code: number;
+ // KYC fee agreed to by the reserve owner.
+ kyc_fee: Amount;
- // Human-readable description of the error, i.e. "missing parameter",
"commitment violation", ...
- // Should give a human-readable hint about the error's nature. Optional,
may change without notice!
- hint?: string;
+ // Time when the KYC was triggered.
+ kyc_timestamp: Timestamp;
- // Hash of the payto:// account URI that identifies
- // the account which is being KYCed.
- h_payto: PaytoHash;
+ // 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;
- // Legitimization target that the merchant should
- // use to check for its KYC status using
- // the ``/kyc-check/$REQUIREMENT_ROW/...`` endpoint.
- requirement_row: Integer;
+ // Signature created with the reserve's private key.
+ // Must be of purpose ``TALER_SIGNATURE_ACCOUNT_SETUP_REQUEST`` over
+ // a ``TALER_AccountSetupRequestSignaturePS``.
+ reserve_sig: EddsaSignature;
}
- .. ts:def:: WithdrawError
+ .. ts:def:: ReserveWithdrawTransaction
- interface WithdrawError {
- // Text describing the error.
- hint: string;
+ interface ReserveWithdrawTransaction {
+ type: "WITHDRAW";
- // 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;
- // Amount left in the reserve.
- balance: Amount;
+ // Amount withdrawn.
+ amount: Amount;
- // History of the reserve's activity, in the same format
- // as returned by ``/reserve/$RID/history``.
- history: TransactionHistoryItem[]
- }
+ // Hash of the denomination public key of the coin.
+ h_denom_pub: HashCode;
+ // Hash of the blinded coin to be signed.
+ h_coin_envelope: HashCode;
+ // Signature over a `TALER_WithdrawRequestPS`
+ // with purpose ``TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW``
+ // created with the reserve's private key.
+ reserve_sig: EddsaSignature;
+ // Fee that is charged for withdraw.
+ withdraw_fee: Amount;
+ }
-Batch Withdraw
-~~~~~~~~~~~~~~
+ .. ts:def:: ReserveAgeWithdrawTransaction
+ interface ReserveAgeWithdrawTransaction {
+ type: "AGEWITHDRAW";
-.. http:post:: /reserves/$RESERVE_PUB/batch-withdraw
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
- 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
- recover the information if necessary in case of transient failures, like
- power outage, network outage, etc.
+ // Total Amount withdrawn.
+ amount: Amount;
- **Request:** The request body must be a `BatchWithdrawRequest` object.
+ // Commitment of all ``n*kappa`` blinded coins.
+ h_commitment: HashCode;
- **Response:**
+ // Signature over a `TALER_AgeWithdrawRequestPS`
+ // with purpose ``TALER_SIGNATURE_WALLET_RESERVE_AGE_WITHDRAW``
+ // created with the reserve's private key.
+ reserve_sig: EddsaSignature;
- :http:statuscode:`200 OK`:
- The request was successful, and the response is a `BatchWithdrawResponse`.
- 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`:
- A signature is invalid.
- This response comes with a standard `ErrorDetail` response.
- :http:statuscode:`404 Not found`:
- A denomination key or the reserve are not known to the exchange. If the
- denomination key is unknown, this suggests a bug in the wallet as the
- wallet should have used current denomination keys from ``/keys``.
- In this case, the response will be a `DenominationUnknownMessage`.
- If the reserve is unknown, the wallet should not report a hard error yet,
but
- instead simply wait for up to a day, as the wire transaction might simply
- not yet have completed and might be known to the exchange in the near
future.
- In this case, the wallet should repeat the exact same request later again
- using exactly the same blinded coin.
- :http:statuscode:`409 Conflict`:
- One of the following reasons occured:
+ // Fee that is charged for withdraw.
+ withdraw_fee: Amount;
+ }
- 1. The balance of the reserve is not sufficient to withdraw the coins of
the
- indicated denominations. The response is `WithdrawError` object.
- 2. The reserve has a birthday set and requires a request to
``/age-withdraw`` instead.
- The response comes with a standard `ErrorDetail` response with error-code
``TALER_EC_EXCHANGE_RESERVES_AGE_RESTRICTION_REQUIRED`` and an additional field
``maximum_allowed_age`` for the maximum age (in years) that the client can
commit to in the call to ``/age-withdraw``
- :http:statuscode:`410 Gone`:
- A requested denomination key is not yet or no longer valid.
- It either before the validity start, past the expiration or was revoked.
- The response is a `DenominationExpiredMessage`. Clients must evaluate the
- error code provided to understand which of the cases this is and handle it
- accordingly.
- :http:statuscode:`451 Unavailable for Legal Reasons`:
- This reserve has received funds from a purse or the amount withdrawn
- exceeds another legal threshold and thus the reserve must
- be upgraded to an account (with KYC) before the withdraw can
- complete. Note that this response does NOT affirm that the
- withdraw will ultimately complete with the requested amount.
- The user should be redirected to the provided location to perform
- the required KYC checks to open the account before withdrawing.
- Afterwards, the request should be repeated.
- The response will be an `KycNeededRedirect` object.
+ .. ts:def:: ReserveCreditTransaction
- Implementation note: internally, we need to
- distinguish between upgrading the reserve to an
- account (due to P2P payment) and identifying the
- owner of the origin bank account (due to exceeding
- the withdraw amount threshold), as we need to create
- a different payto://-URI for the KYC check depending
- on the case.
+ 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;
- **Details:**
+ // Amount deposited.
+ amount: Amount;
- .. ts:def:: BatchWithdrawRequest
+ // Sender account ``payto://`` URL.
+ sender_account_url: string;
- interface BatchWithdrawRequest {
- // Array of requests for the individual coins to withdraw.
- planchets: WithdrawRequest[];
+ // 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:: BatchWithdrawResponse
+ .. ts:def:: ReserveClosingTransaction
- interface BatchWithdrawResponse {
- // Array of blinded signatures, in the same order as was
- // given in the request.
- ev_sigs: WithdrawResponse[];
+ interface ReserveClosingTransaction {
+ type: "CLOSING";
- }
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
-Withdraw with Age Restriction
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // Closing balance.
+ amount: Amount;
-If the reserve was marked with a maximum age group, the client has to perform a
-cut&choose protocol with the exchange. It first calls
-``/reserves/$RESERVE_PUB/age-withdraw`` and commits to ``n*kappa`` coins. On
-success, the exchange answers this request with an noreveal-index. The client
-then has to call ``/age-withdraw/$ACH/reveal`` to reveal all ``n*(kappa - 1)``
-coins along with their age commitments to proof that they were appropriate.
-If so, the exchange will blindly sign ``n`` undisclosed coins from the request.
+ // Closing fee charged by the exchange.
+ closing_fee: Amount;
+ // Wire transfer subject.
+ wtid: Base32;
-.. http:POST:: /reserves/$RESERVE_PUB/age-withdraw
+ // ``payto://`` URI of the wire account into which the funds were
returned to.
+ receiver_account_details: string;
- Withdraw multiple coins *with age restriction* 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 recover the information if necessary in case of
- transient failures, like power outage, network outage, etc.
+ // This is a signature over a
+ // struct `TALER_ReserveCloseConfirmationPS` with purpose
+ // ``TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED``.
+ exchange_sig: EddsaSignature;
- **Request:** The request body must be a `AgeWithdrawRequest` object.
+ // Public key used to create 'exchange_sig'.
+ exchange_pub: EddsaPublicKey;
- **Response:**
+ // Time when the reserve was closed.
+ timestamp: Timestamp;
+ }
- :http:statuscode:`200 OK`:
- The request was successful, and the response is a `AgeWithdrawResponse`.
- 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`:
- A signature is invalid.
- This response comes with a standard `ErrorDetail` response.
- :http:statuscode:`409 Conflict`:
- One of two reasons occured:
- 1. The balance of the reserve is not sufficient to withdraw the coins of
the
- given amount. The response is a `WithdrawError` object.
+ .. ts:def:: ReserveOpenRequestTransaction
- 2. The provided value for ``max_age`` is higher than the allowed value
according to the reserve's birthday.
- The response comes with a standard `ErrorDetail` response with error-code
``TALER_EC_EXCHANGE_AGE_WITHDRAW_MAXIMUM_AGE_TOO_LARGE`` and an additional
field ``maximum_allowed_age`` for the maximum age (in years) that the client
can commit to in a call to ``/age-withdraw``
- :http:statuscode:`410 Gone`:
- A requested denomination key is not yet or no longer valid.
- It either before the validity start, past the expiration or was revoked.
- The response is a `DenominationExpiredMessage`. Clients must evaluate the
- error code provided to understand which of the cases this is and handle it
- accordingly.
- :http:statuscode:`451 Unavailable for Legal Reasons`:
- This reserve has received funds from a purse or the amount withdrawn
- exceeds another legal threshold and thus the reserve must
- be upgraded to an account (with KYC) before the withdraw can
- complete. Note that this response does NOT affirm that the
- withdraw will ultimately complete with the requested amount.
- The user should be redirected to the provided location to perform
- the required KYC checks to open the account before withdrawing.
- Afterwards, the request should be repeated.
- The response will be an `KycNeededRedirect` object.
+ 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;
- .. ts:def:: AgeWithdrawRequest
+ // Open fee paid from the reserve.
+ open_fee: Amount;
- interface AgeWithdrawRequest {
- // Array of ``n`` hash codes of denomination public keys to order.
- // These denominations MUST support age restriction as defined in the
- // output to /keys.
- // 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.
- denoms_h: HashCode[];
+ // This is a signature over
+ // a struct `TALER_ReserveOpenPS` with purpose
+ // ``TALER_SIGNATURE_WALLET_RESERVE_OPEN``.
+ reserve_sig: EddsaSignature;
- // ``n`` arrays of ``kappa`` entries with blinded coin envelopes. Each
- // (toplevel) entry represents ``kappa`` canditates for a particular
- // coin. The exchange will respond with an index ``gamma``, which is
- // the index that shall remain undisclosed during the reveal phase.
- // The SHA512 hash $ACH over the blinded coin envelopes is the commitment
- // that is later used as the key to the reveal-URL.
- blinded_coins_evs: CoinEnvelope[][];
+ // Timestamp of the open request.
+ request_timestamp: Timestamp;
- // The maximum age to commit to. MUST be the same as the maximum
- // age in the reserve.
- max_age: number;
+ // Requested expiration.
+ requested_expiration: Timestamp;
+
+ // Requested number of free open purses.
+ requested_min_purses: Integer;
- // Signature of `TALER_AgeWithdrawRequestPS` created with
- // the `reserves's private key <reserve-priv>`
- // using purpose ``TALER_SIGNATURE_WALLET_RESERVE_AGE_WITHDRAW``.
- reserve_sig: EddsaSignature;
}
- .. ts:def:: AgeWithdrawResponse
+ .. ts:def:: ReserveCloseRequestTransaction
- interface AgeWithdrawResponse {
- // index of the commitments that the client doesn't
- // have to disclose
- noreveal_index: Integer;
+ interface ReserveCloseRequestTransaction {
+ type: "CLOSE";
- // Signature of `TALER_AgeWithdrawConfirmationPS` whereby
- // the exchange confirms the ``noreveal_index``.
- exchange_sig: EddsaSignature;
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: 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;
+ // This is a signature over
+ // a struct `TALER_ReserveClosePS` with purpose
+ // ``TALER_SIGNATURE_WALLET_RESERVE_CLOSE``.
+ reserve_sig: EddsaSignature;
+
+ // Target account ``payto://``, optional.
+ h_payto?: PaytoHash;
+
+ // Timestamp of the close request.
+ request_timestamp: Timestamp;
}
+ .. ts:def:: ReserveCreditTransaction
+ interface ReserveCreditTransaction {
+ type: "CREDIT";
-.. http:POST:: /age-withdraw/$ACH/reveal
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
- The client has previously committed to multiple coins with age restriction
- in a call to ``/reserve/$RESERVE_PUB/age-withdraw`` and got a
- `AgeWithdrawResponse` from the exchange. By calling this
- endpoint, the client has to reveal each coin and their ``kappa - 1``
- age commitments, except for the age commitments with index
- ``noreveal_index``. The hash of all commitments from the former withdraw
- request is given as the ``$ACH`` value in the URL to this endpoint.
+ // Amount deposited.
+ amount: Amount;
+ // Sender account ``payto://`` URL.
+ sender_account_url: string;
- **Request:** The request body must be a `AgeWithdrawRevealRequest` object.
+ // Opaque identifier internal to the exchange that
+ // uniquely identifies the wire transfer that credited the reserve.
+ wire_reference: Integer;
- **Response:**
+ // Timestamp of the incoming wire transfer.
+ timestamp: Timestamp;
+ }
- :http:statuscode:`200 OK`:
- The request was successful, and the response is a
`AgeWithdrawRevealResponse`.
- 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:`404 Not found`:
- The provided commitment $ACH is unknown.
- :http:statuscode:`409 Conflict`:
- The reveal operation failed and the response is an `WithdrawError` object.
- The error codes indicate one of two cases:
+ .. ts:def:: PurseMergeTransaction
- 1. An age commitment for at least one of the coins did not fulfill the
- required maximum age requirement of the corresponding reserve.
- Error code:
- ``TALER_EC_EXCHANGE_GENERIC_COIN_AGE_REQUIREMENT_FAILURE``.
- 2. The computation of the hash of the commitment with provided input does
- result in the value $ACH.
- Error code:
- ``TALER_EC_EXCHANGE_AGE_WITHDRAW_REVEAL_INVALID_HASH``
+ 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;
- .. ts:def:: AgeWithdrawRevealRequest
+ // SHA-512 hash of the contact of the purse.
+ h_contract_terms: HashCode;
- interface AgeWithdrawRevealRequest {
- // Array of ``n`` of ``(kappa - 1)`` disclosed coin master secrets, from
- // which the coins' private key, blinding, nonce (for Clause-Schnorr) and
- // age-restriction is calculated.
- //
- // Given each coin's private key and age commitment, the exchange will
- // calculate each coin's blinded hash value und use all those (disclosed)
- // blinded hashes together with the non-disclosed envelopes ``coin_evs``
- // during the verification of the original age-withdraw-commitment.
- disclosed_coin_secrets: AgeRestrictedCoinSecret[][];
- }
+ // EdDSA public key used to approve merges of this purse.
+ merge_pub: EddsaPublicKey;
- .. ts:def:: AgeRestrictedCoinSecret
+ // Minimum age required for all coins deposited into the purse.
+ min_age: Integer;
- // The Master key material from which the coins' private key ``coin_priv``,
- // blinding ``beta`` and nonce ``nonce`` (for Clause-Schnorr) itself are
- // derived as usually in wallet-core. Given a coin's master key material,
- // the age commitment for the coin MUST be derived from this private key as
- // follows:
- //
- // Let m ∈ {1,...,M} be the maximum age group as defined in the reserve
- // that the wallet can commit to.
- //
- // For age group $AG ∈ {1,...m}, set
- // seed = HDKF(coin_secret, "age-commitment", $AG)
- // p[$AG] = Edx25519_generate_private(seed)
- // and calculate the corresponding Edx25519PublicKey as
- // q[$AG] = Edx25519_public_from_private(p[$AG])
- //
- // For age groups $AG ∈ {m,...,M}, set
- // f[$AG] = HDKF(coin_secret, "age-factor", $AG)
- // and calculate the corresponding Edx25519PublicKey as
- // q[$AG] = Edx25519_derive_public(`PublishedAgeRestrictionBaseKey`,
f[$AG])
- //
- type AgeRestrictedCoinSecret = string;
+ // Number that identifies who created the purse
+ // and how it was paid for.
+ flags: Integer;
- .. ts:def:: PublishedAgeRestrictionBaseKey
+ // Purse public key.
+ purse_pub: EddsaPublicKey;
- // The value for ``PublishedAgeRestrictionBaseKey`` is a randomly chosen
- // `Edx25519PublicKey` for which the private key is not known to the
clients. It is
- // used during the age-withdraw protocol so that clients can proof that
they
- // derived all public keys to age groups higher than their allowed maximum
- // from this particular value.
- const PublishedAgeRestrictionBaseKey =
- new
Edx25519PublicKey("CH0VKFDZ2GWRWHQBBGEK9MWV5YDQVJ0RXEE0KYT3NMB69F0R96TG");
+ // EdDSA signature of the account/reserve affirming the merge
+ // over a `TALER_AccountMergeSignaturePS`.
+ // Must be of purpose ``TALER_SIGNATURE_ACCOUNT_MERGE``
+ reserve_sig: EddsaSignature;
- .. ts:def:: AgeWithdrawRevealResponse
+ // Client-side timestamp of when the merge request was made.
+ merge_timestamp: Timestamp;
- interface AgeWithdrawRevealResponse {
- // List of the exchange's blinded RSA signatures on the new coins.
- ev_sigs : BlindedDenominationSignature[];
+ // 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;
}
@@ -2640,7 +2576,7 @@ If so, the exchange will blindly sign ``n`` undisclosed
coins from the request.
Coin History
------------
-.. http:GET:: /coins/$COIN_PUB
+.. http:GET:: /coins/$COIN_PUB/history
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
@@ -2649,17 +2585,35 @@ Coin History
**Request:**
- If possible, clients should set an "If-none-match" HTTP header based on a
- previous "Etag" returned by the exchange.
+ 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 ``$RESERVE_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 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.
@@ -2689,6 +2643,11 @@ Coin History
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
@@ -2732,6 +2691,11 @@ Coin History
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
@@ -2761,6 +2725,11 @@ Coin History
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;
+
// The total amount of the coin's value restored
// by this transaction.
// The amount given excludes the transaction fee.
@@ -2791,6 +2760,11 @@ Coin History
interface CoinRecoupTransaction {
type: "RECOUP";
+ // 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
@@ -2832,6 +2806,11 @@ Coin History
interface CoinOldCoinRecoupTransaction {
type: "OLD-COIN-RECOUP";
+ // 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 current coin value can thus be computed by
@@ -2856,6 +2835,11 @@ Coin History
interface CoinRecoupRefreshTransaction {
type: "RECOUP-REFRESH";
+ // 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
@@ -2898,6 +2882,11 @@ Coin History
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;
+
// The total amount of the coin's value absorbed
// by this transaction.
// Note that this means the amount given includes
@@ -2932,6 +2921,11 @@ Coin History
interface CoinPurseRefundTransaction {
type: "PURSE-REFUND";
+ // 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 refund fee.
@@ -2961,6 +2955,11 @@ Coin History
interface CoinReserveOpenDepositTransaction {
type: "RESERVE-OPEN-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
// by this transaction.
// Note that this means the amount given includes
@@ -5490,3 +5489,61 @@ naturally expire and possibly (5) wire the funds to a
designated account.
wire_amount: Amount;
}
+
+
+.. _delete-reserve:
+
+.. http:DELETE:: /reserves/$RESERVE_PUB
+
+ Forcefully closes a reserve.
+ The request header must contain an *Account-Request-Signature*.
+ Note: this endpoint is not currently implemented!
+
+ **Request:**
+
+ *Account-Request-Signature*: The client must provide Base-32 encoded EdDSA
signature made with ``$ACCOUNT_PRIV``, affirming its authorization to delete
the account. The purpose used MUST be ``TALER_SIGNATURE_RESERVE_CLOSE``.
+
+ :query force=BOOLEAN: *Optional.* If set to 'true' specified, the exchange
+ will delete the account even if there is a balance remaining.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The operation succeeded, the exchange provides details
+ about the account deletion.
+ The response will include a `ReserveDeletedResponse` object.
+ :http:statuscode:`403 Forbidden`:
+ The *Account-Request-Signature* is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not found`:
+ The account is unknown to the exchange.
+ :http:statuscode:`409 Conflict`:
+ The account is still has digital cash in it, the associated
+ wire method is ``void`` and the *force* option was not provided.
+ This response comes with a standard `ErrorDetail` response.
+
+ **Details:**
+
+ .. ts:def:: ReserveDeletedResponse
+
+ interface ReserveDeletedResponse {
+
+ // Final balance of the account.
+ closing_amount: Amount;
+
+ // Current time of the exchange, used as part of
+ // what the exchange signs over.
+ close_time: Timestamp;
+
+ // Hash of the wire account into which the remaining
+ // balance will be transferred. Note: may be the
+ // hash over ``payto://void/`, in which case the
+ // balance is forfeit to the profit of the exchange.
+ h_wire: HashCode;
+
+ // This is a signature over a
+ // struct ``TALER_AccountDeleteConfirmationPS`` with purpose
+ // ``TALER_SIGNATURE_EXCHANGE_RESERVE_DELETED``.
+ exchange_sig: EddsaSignature;
+
+ }
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [taler-docs] branch master updated: update exchange REST API: remove paid history API, authenticate GET coin history API, add start offset and ETag specs for both histories,
gnunet <=