- POST /recoup-refresh#
Demand that coins of revoked denominations, which originated from one particular call to
/meltand/reveal-melt, be paid back to the old coin they were refreshed from.All coins in one request MUST originate from the same refresh operation. The client identifies that operation by the public key of the old coin and the refresh commitment
rcof the original melt request. As with/recoup-withdraw, the client discloses the secret material of the coins to be recouped and provides the envelope hashes of the other coins of the same operation, so that the exchange can recompute the hash over the batch of coins it signed and compare it with the commitment it stored.The residual value of each disclosed coin is credited to the old coin. The old coin may then be spent or melted again, even if the deposit expiration of its denomination has passed in the meantime (a “zombie” coin). The refresh fee paid in the original operation is not recouped.
The exchange only accepts this request for coins of denominations that are listed in the
recoupfield of/keys.The base URL for this request 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.
This endpoint was introduced in protocol vRECOUP and replaces the former
/coins/$COIN_PUB/recoup-refreshendpoint.Request:
The request body must be a RecoupRefreshRequest object.
Response:
- 200 OK:
The request was successful and the response is a RecoupRefreshResponse. Repeating exactly the same request yields the same response (the signature may differ if the exchange has rotated its signing key in the meantime), so if the network goes down before the client can commit the result to disk, the recoup is not lost.
- 400 Bad Request:
The request body is malformed or a parameter is invalid. This response comes with a standard ErrorDetail response. Possible error codes include
TALER_EC_GENERIC_PARAMETER_MALFORMED(also used ifcoin_datadoes not contain at least one disclosed coin) andTALER_EC_EXCHANGE_RECOUP_REFRESH_BATCH_SIZE_MISMATCH(the number of entries incoin_datadiffers from the number of coins the exchange signed in the original refresh operation).- 403 Forbidden:
A signature is invalid. This response comes with a standard ErrorDetail response. Possible error codes include
TALER_EC_EXCHANGE_RECOUP_REFRESH_SIGNATURE_INVALID(acoin_sig) orTALER_EC_EXCHANGE_DENOMINATION_SIGNATURE_INVALID(adenom_sig).- 404 Not found:
One of the following reasons occurred:
A denomination key is unknown. The response is a DenominationUnknownMessage with error code
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN.The exchange has no record of a refresh operation for the given
rc, or the operation found was not a refresh ofold_coin_pub. This response comes with a standard ErrorDetail response with error codeTALER_EC_EXCHANGE_RECOUP_REFRESH_MELT_NOT_FOUND.
- 409 Conflict:
One of the following reasons occurred:
The hash the exchange recomputed over the
coin_dataarray does not match the commitment of the refresh operation, so at least one disclosed coin was not part of it. This response comes with a standard ErrorDetail response with error codeTALER_EC_EXCHANGE_RECOUP_REFRESH_COMMITMENT_MISMATCH.The denomination of a disclosed coin differs from the denomination recorded for that position of the refresh operation. This response comes with a standard ErrorDetail response with error code
TALER_EC_EXCHANGE_RECOUP_REFRESH_DENOMINATION_MISMATCH.A disclosed coin has no residual value left. The response is a DepositDoubleSpendError with error code
TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS.The same coin public key was previously used with a different denomination or age commitment. The response is a CoinDenominationConflictError with error code
TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEYor a CoinAgeCommitmentConflictError with error codeTALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_AGE_HASH.
In all of these cases nothing is credited, not even for the other coins in the request.
- 410 Gone:
The denomination of a disclosed coin is not eligible for recoup. The response is a DenominationGoneMessage with error code
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED(past the deposit expiration) orTALER_EC_EXCHANGE_RECOUP_REFRESH_NOT_ELIGIBLE(the denomination was not revoked).- 412 Precondition Failed:
The denomination of a disclosed coin is not yet valid. The response is a DenominationGoneMessage with error code
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE.- 413 Request entity too large:
The uploaded body is to long, it exceeds the size limit. Returned with an error code of
TALER_EC_GENERIC_UPLOAD_EXCEEDS_LIMIT.- 500 Internal Server Error:
The exchange encountered an internal error. This response comes with a standard ErrorDetail response. Possible error codes include
TALER_EC_EXCHANGE_RECOUP_REFRESH_BLINDING_FAILED,TALER_EC_GENERIC_DB_FETCH_FAILED,TALER_EC_GENERIC_DB_COMMIT_FAILED, orTALER_EC_GENERIC_DB_INVARIANT_FAILURE.- 502 Bad gateway:
The exchange could not reach its signing helper to create the confirmation signatures. Returned with an error code of
TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE. Wallets should retry the request (with some delay) at a later time.- 503 Service Unavailable:
The exchange currently has no signing keys available. This response comes with a standard ErrorDetail response with a code of
TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING.
Details:
interface RecoupRefreshRequest { // Public key of the old coin that was melted. // The recouped value is credited to this coin. old_coin_pub: CoinPublicKey; // The refresh commitment of the original melt request, // see TALER_RefreshCommitmentP. This identifies the // refresh operation. rc: HashCode; // Exactly one entry per coin the exchange signed in the // refresh operation, that is the n coins of the batch at // the noreveal_index returned in the MeltResponse, in the // order of the original request. // At least one entry MUST be a RecoupedCoin and its // coin_sig MUST be created with purpose // TALER_SIGNATURE_WALLET_COIN_RECOUP_REFRESH. coin_data: RecoupCoinData[]; }
Note that for denominations of cipher type Clause-Schnorr the client does not need to provide the session nonce or the R-value pair: the exchange derives the nonce from the
blinding_seedof the original melt request and the coin’s position incoin_data(exactly as the wallet does for a melt), and it stored the R-values it returned in/blinding-prepare.The exchange processes the request as
/recoup-withdrawdoes, with the refresh operation looked up underrc, the hash overcoin_datacompared against the hash of the batch at thenoreveal_index, and the residual value of every disclosed coin credited toold_coin_pubin one database transaction.interface RecoupRefreshResponse { // Public key of the old coin that was credited. old_coin_pub: CoinPublicKey; // The refresh commitment of the refresh operation, as in the request. rc: HashCode; // Time when the exchange accepted the recoup. All coins // of one request share this timestamp. timestamp: Timestamp; // Total amount credited to the old coin, that is the sum // of the amount values in recoups. total_amount: Amount; // One entry per RecoupedCoin in the request, in the same order. recoups: RecoupedCoinResult[]; // Signature over TALER_RecoupRefreshBatchConfirmationPS with // purpose TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH_BATCH, // affirming the recoup of all coins in recoups. exchange_sig: EddsaSignature; // Public key used to create exchange_sig. // Should match one of the exchange's signing keys from /keys. exchange_pub: EddsaPublicKey; }
The coin histories report each recouped coin individually, see CoinRecoupRefreshTransaction for the recouped coin and CoinRecoupRefreshReceiverTransaction for the old coin. Those entries carry a signature per coin over TALER_RecoupRefreshConfirmationPS, which the exchange creates when a history is requested; the batch signature above is only part of the response to this request.