gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-exchange] branch master updated: next round of exchange API atomi


From: gnunet
Subject: [taler-exchange] branch master updated: next round of exchange API atomization
Date: Sun, 25 Jun 2023 19:10:30 +0200

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository exchange.

The following commit(s) were added to refs/heads/master by this push:
     new 421129a3 next round of exchange API atomization
421129a3 is described below

commit 421129a32ed88fee49108c76e67c16b60f95116b
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Sun Jun 25 19:10:26 2023 +0200

    next round of exchange API atomization
---
 contrib/gana                                       |   2 +-
 src/include/taler_exchange_service.h               | 230 ++++++++++++++-------
 src/lib/exchange_api_batch_withdraw2.c             |  17 +-
 src/lib/exchange_api_common.c                      |  14 +-
 src/lib/exchange_api_csr_melt.c                    |  26 +--
 src/lib/exchange_api_deposits_get.c                |  29 ++-
 src/lib/exchange_api_handle.c                      |  14 ++
 src/lib/exchange_api_melt.c                        |  57 +++--
 src/lib/exchange_api_purse_create_with_deposit.c   |  45 ++--
 src/lib/exchange_api_purse_create_with_merge.c     |  41 ++--
 src/lib/exchange_api_purse_deposit.c               |  30 ++-
 src/lib/exchange_api_purse_merge.c                 |  30 ++-
 src/lib/exchange_api_purses_get.c                  |  34 ++-
 src/lib/exchange_api_recoup.c                      |  41 ++--
 src/lib/exchange_api_recoup_refresh.c              |  30 ++-
 src/lib/exchange_api_refreshes_reveal.c            |  34 +--
 src/lib/exchange_api_refund.c                      |  28 ++-
 src/lib/exchange_api_reserves_close.c              |  26 +--
 src/lib/exchange_api_reserves_history.c            |  40 ++--
 src/lib/exchange_api_reserves_open.c               |  45 ++--
 src/lib/exchange_api_reserves_status.c             |  30 ++-
 src/lib/exchange_api_transfers_get.c               |  31 ++-
 src/lib/exchange_api_withdraw2.c                   |   3 +-
 src/testing/testing_api_cmd_deposits_get.c         |  23 +--
 src/testing/testing_api_cmd_purse_create_deposit.c |   8 +-
 src/testing/testing_api_cmd_purse_deposit.c        |   8 +-
 src/testing/testing_api_cmd_purse_get.c            |  19 +-
 src/testing/testing_api_cmd_purse_merge.c          |   8 +-
 src/testing/testing_api_cmd_recoup.c               |  21 +-
 src/testing/testing_api_cmd_recoup_refresh.c       |  25 ++-
 src/testing/testing_api_cmd_refresh.c              |  52 ++---
 src/testing/testing_api_cmd_refund.c               |  27 +--
 src/testing/testing_api_cmd_reserve_close.c        |  16 +-
 src/testing/testing_api_cmd_reserve_history.c      |  11 +-
 src/testing/testing_api_cmd_reserve_open.c         |   4 +-
 src/testing/testing_api_cmd_reserve_purse.c        |   4 +-
 src/testing/testing_api_cmd_reserve_status.c       |  11 +-
 src/testing/testing_api_cmd_transfer_get.c         |  11 +-
 38 files changed, 576 insertions(+), 549 deletions(-)

diff --git a/contrib/gana b/contrib/gana
index 5f377301..3e5591a7 160000
--- a/contrib/gana
+++ b/contrib/gana
@@ -1 +1 @@
-Subproject commit 5f377301db4d94c485422ecda277fe850e29504a
+Subproject commit 3e5591a7e3fd93ba46fc2b538c63f0c16336283d
diff --git a/src/include/taler_exchange_service.h 
b/src/include/taler_exchange_service.h
index 9cb5f083..bc6a230b 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -604,8 +604,9 @@ TALER_EXCHANGE_keys_decref (struct TALER_EXCHANGE_Keys 
*keys);
  * @param last_denom_new new last denomination time.
  */
 void
-TALER_EXCHANGE_set_last_denom (struct TALER_EXCHANGE_Handle *exchange,
-                               struct GNUNET_TIME_Timestamp last_denom_new);
+TALER_EXCHANGE_set_last_denom (
+  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_TIME_Timestamp last_denom_new);
 
 
 /**
@@ -653,10 +654,11 @@ enum TALER_EXCHANGE_CheckKeysFlags
  * @return until when the existing response is current, 0 if we are 
re-downloading now
  */
 struct GNUNET_TIME_Timestamp
-TALER_EXCHANGE_check_keys_current (struct TALER_EXCHANGE_Handle *exchange,
-                                   enum TALER_EXCHANGE_CheckKeysFlags flags,
-                                   TALER_EXCHANGE_CertificationCallback cb,
-                                   void *cb_cls);
+TALER_EXCHANGE_check_keys_current (
+  struct TALER_EXCHANGE_Handle *exchange,
+  enum TALER_EXCHANGE_CheckKeysFlags flags,
+  TALER_EXCHANGE_CertificationCallback cb,
+  void *cb_cls);
 
 
 /**
@@ -669,6 +671,16 @@ json_t *
 TALER_EXCHANGE_get_keys_raw (struct TALER_EXCHANGE_Handle *exchange);
 
 
+/**
+ * Obtain the keys from the exchange in the raw JSON format.
+ *
+ * @param keys the keys structure
+ * @return the keys in raw JSON
+ */
+json_t *
+TALER_EXCHANGE_keys_to_json (struct TALER_EXCHANGE_Keys *keys);
+
+
 /**
  * Test if the given @a pub is a the current signing key from the exchange
  * according to @a keys.
@@ -1055,9 +1067,10 @@ struct TALER_EXCHANGE_WireHandle;
  * @return a handle for this request
  */
 struct TALER_EXCHANGE_WireHandle *
-TALER_EXCHANGE_wire (struct TALER_EXCHANGE_Handle *exchange,
-                     TALER_EXCHANGE_WireCallback wire_cb,
-                     void *wire_cb_cls);
+TALER_EXCHANGE_wire (
+  struct TALER_EXCHANGE_Handle *exchange,
+  TALER_EXCHANGE_WireCallback wire_cb,
+  void *wire_cb_cls);
 
 
 /**
@@ -1377,7 +1390,9 @@ typedef void
  * finished processing the /keys reply).  If this check fails, we do
  * NOT initiate the transaction with the exchange and instead return NULL.
  *
- * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param ctx curl context
+ * @param url exchange base URL
+ * @param keys exchange keys
  * @param amount the amount to be refunded; must be larger than the refund fee
  *        (as that fee is still being subtracted), and smaller than the amount
  *        (with deposit fee) of the original deposit contribution of this coin
@@ -1395,7 +1410,9 @@ typedef void
  */
 struct TALER_EXCHANGE_RefundHandle *
 TALER_EXCHANGE_refund (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
   const struct TALER_Amount *amount,
   const struct TALER_PrivateContractHashP *h_contract_terms,
   const struct TALER_CoinSpendPublicKeyP *coin_pub,
@@ -1504,7 +1521,8 @@ struct TALER_EXCHANGE_NonceKey
 /**
  * Get a set of CS R values using a /csr-melt request.
  *
- * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param ctx curl context
+ * @param url exchange base URL
  * @param rms master key used for the derivation of the CS values
  * @param nks_len length of the @a nks array
  * @param nks array of denominations and nonces
@@ -1515,12 +1533,14 @@ struct TALER_EXCHANGE_NonceKey
  *         In this case, the callback is not called.
  */
 struct TALER_EXCHANGE_CsRMeltHandle *
-TALER_EXCHANGE_csr_melt (struct TALER_EXCHANGE_Handle *exchange,
-                         const struct TALER_RefreshMasterSecretP *rms,
-                         unsigned int nks_len,
-                         struct TALER_EXCHANGE_NonceKey *nks,
-                         TALER_EXCHANGE_CsRMeltCallback res_cb,
-                         void *res_cb_cls);
+TALER_EXCHANGE_csr_melt (
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  const struct TALER_RefreshMasterSecretP *rms,
+  unsigned int nks_len,
+  struct TALER_EXCHANGE_NonceKey *nks,
+  TALER_EXCHANGE_CsRMeltCallback res_cb,
+  void *res_cb_cls);
 
 
 /**
@@ -1608,11 +1628,12 @@ typedef void
  *         In this case, the callback is not called.
  */
 struct TALER_EXCHANGE_CsRWithdrawHandle *
-TALER_EXCHANGE_csr_withdraw (struct TALER_EXCHANGE_Handle *exchange,
-                             const struct TALER_EXCHANGE_DenomPublicKey *pk,
-                             const struct TALER_CsNonce *nonce,
-                             TALER_EXCHANGE_CsRWithdrawCallback res_cb,
-                             void *res_cb_cls);
+TALER_EXCHANGE_csr_withdraw (
+  struct TALER_EXCHANGE_Handle *exchange,
+  const struct TALER_EXCHANGE_DenomPublicKey *pk,
+  const struct TALER_CsNonce *nonce,
+  TALER_EXCHANGE_CsRWithdrawCallback res_cb,
+  void *res_cb_cls);
 
 
 /**
@@ -2132,7 +2153,9 @@ typedef void
 /**
  * Submit a request to obtain the reserve status.
  *
- * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param ctx curl context
+ * @param url exchange base URL
+ * @param keys exchange keys
  * @param reserve_priv private key of the reserve to inspect
  * @param cb the callback to call when a reply for this request is available
  * @param cb_cls closure for the above callback
@@ -2141,7 +2164,9 @@ typedef void
  */
 struct TALER_EXCHANGE_ReservesStatusHandle *
 TALER_EXCHANGE_reserves_status (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
   const struct TALER_ReservePrivateKeyP *reserve_priv,
   TALER_EXCHANGE_ReservesStatusCallback cb,
   void *cb_cls);
@@ -2250,7 +2275,9 @@ typedef void
 /**
  * Submit a request to obtain the reserve history.
  *
- * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param ctx curl context
+ * @param url exchange base URL
+ * @param keys exchange keys
  * @param reserve_priv private key of the reserve to inspect
  * @param cb the callback to call when a reply for this request is available
  * @param cb_cls closure for the above callback
@@ -2259,7 +2286,9 @@ typedef void
  */
 struct TALER_EXCHANGE_ReservesHistoryHandle *
 TALER_EXCHANGE_reserves_history (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
   const struct TALER_ReservePrivateKeyP *reserve_priv,
   TALER_EXCHANGE_ReservesHistoryCallback cb,
   void *cb_cls);
@@ -2649,11 +2678,12 @@ struct TALER_EXCHANGE_Withdraw2Handle;
  *         In this case, the callback is not called.
  */
 struct TALER_EXCHANGE_Withdraw2Handle *
-TALER_EXCHANGE_withdraw2 (struct TALER_EXCHANGE_Handle *exchange,
-                          const struct TALER_PlanchetDetail *pd,
-                          const struct TALER_ReservePrivateKeyP *reserve_priv,
-                          TALER_EXCHANGE_Withdraw2Callback res_cb,
-                          void *res_cb_cls);
+TALER_EXCHANGE_withdraw2 (
+  struct TALER_EXCHANGE_Handle *exchange,
+  const struct TALER_PlanchetDetail *pd,
+  const struct TALER_ReservePrivateKeyP *reserve_priv,
+  TALER_EXCHANGE_Withdraw2Callback res_cb,
+  void *res_cb_cls);
 
 
 /**
@@ -2911,7 +2941,9 @@ typedef void
  * argument @a rd should be committed to persistent storage
  * prior to calling this function.
  *
- * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param ctx curl context
+ * @param url exchange base URL
+ * @param keys exchange keys
  * @param rms the fresh secret that defines the refresh operation
  * @param rd the refresh data specifying the characteristics of the operation
  * @param melt_cb the callback to call with the result
@@ -2920,11 +2952,14 @@ typedef void
  *         In this case, neither callback will be called.
  */
 struct TALER_EXCHANGE_MeltHandle *
-TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange,
-                     const struct TALER_RefreshMasterSecretP *rms,
-                     const struct TALER_EXCHANGE_RefreshData *rd,
-                     TALER_EXCHANGE_MeltCallback melt_cb,
-                     void *melt_cb_cls);
+TALER_EXCHANGE_melt (
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
+  const struct TALER_RefreshMasterSecretP *rms,
+  const struct TALER_EXCHANGE_RefreshData *rd,
+  TALER_EXCHANGE_MeltCallback melt_cb,
+  void *melt_cb_cls);
 
 
 /**
@@ -3044,7 +3079,9 @@ struct TALER_EXCHANGE_RefreshesRevealHandle;
  * arguments should have been committed to persistent storage
  * prior to calling this function.
  *
- * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param ctx curl context
+ * @param url exchange base URL
+ * @param keys exchange keys
  * @param rms the fresh secret that defines the refresh operation
  * @param rd the refresh data that characterizes the refresh operation
  * @param num_coins number of fresh coins to be created, length of the @a 
exchange_vals array, must match value in @a rd
@@ -3059,7 +3096,8 @@ struct TALER_EXCHANGE_RefreshesRevealHandle;
  */
 struct TALER_EXCHANGE_RefreshesRevealHandle *
 TALER_EXCHANGE_refreshes_reveal (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
   const struct TALER_RefreshMasterSecretP *rms,
   const struct TALER_EXCHANGE_RefreshData *rd,
   unsigned int num_coins,
@@ -3311,7 +3349,9 @@ typedef void
  * Query the exchange about which transactions were combined
  * to create a wire transfer.
  *
- * @param exchange exchange to query
+ * @param ctx curl context
+ * @param url exchange base URL
+ * @param keys exchange keys
  * @param wtid raw wire transfer identifier to get information about
  * @param cb callback to call
  * @param cb_cls closure for @a cb
@@ -3319,7 +3359,9 @@ typedef void
  */
 struct TALER_EXCHANGE_TransfersGetHandle *
 TALER_EXCHANGE_transfers_get (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
   const struct TALER_WireTransferIdentifierRawP *wtid,
   TALER_EXCHANGE_TransfersGetCallback cb,
   void *cb_cls);
@@ -3449,7 +3491,9 @@ typedef void
  * which aggregate wire transfer the deposit operation identified by @a 
coin_pub,
  * @a merchant_priv and @a h_contract_terms contributed to.
  *
- * @param exchange the exchange to query
+ * @param ctx curl context
+ * @param url exchange base URL
+ * @param keys exchange keys
  * @param merchant_priv the merchant's private key
  * @param h_wire hash of merchant's wire transfer details
  * @param h_contract_terms hash of the proposal data
@@ -3461,7 +3505,9 @@ typedef void
  */
 struct TALER_EXCHANGE_DepositGetHandle *
 TALER_EXCHANGE_deposits_get (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
   const struct TALER_MerchantPrivateKeyP *merchant_priv,
   const struct TALER_MerchantWireHashP *h_wire,
   const struct TALER_PrivateContractHashP *h_contract_terms,
@@ -3504,7 +3550,7 @@ TALER_EXCHANGE_verify_coin_history (
  * Parse history given in JSON format and return it in binary
  * format.
  *
- * @param exchange connection to the exchange we can use
+ * @param keys exchange keys
  * @param history JSON array with the history
  * @param reserve_pub public key of the reserve to inspect
  * @param currency currency we expect the balance to be in
@@ -3519,7 +3565,7 @@ TALER_EXCHANGE_verify_coin_history (
  */
 enum GNUNET_GenericReturnValue
 TALER_EXCHANGE_parse_reserve_history (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct TALER_EXCHANGE_Keys *keys,
   const json_t *history,
   const struct TALER_ReservePublicKeyP *reserve_pub,
   const char *currency,
@@ -3601,7 +3647,9 @@ typedef void
  * the emergency recoup protocol for a given denomination.  The value
  * of the coin will be refunded to the original customer (without fees).
  *
- * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param ctx curl context
+ * @param url exchange base URL
+ * @param keys exchange keys
  * @param pk kind of coin to pay back
  * @param denom_sig signature over the coin by the exchange using @a pk
  * @param exchange_vals contribution from the exchange on the withdraw
@@ -3613,13 +3661,16 @@ typedef void
  *         In this case, the callback is not called.
  */
 struct TALER_EXCHANGE_RecoupHandle *
-TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,
-                       const struct TALER_EXCHANGE_DenomPublicKey *pk,
-                       const struct TALER_DenominationSignature *denom_sig,
-                       const struct TALER_ExchangeWithdrawValues 
*exchange_vals,
-                       const struct TALER_PlanchetMasterSecretP *ps,
-                       TALER_EXCHANGE_RecoupResultCallback recoup_cb,
-                       void *recoup_cb_cls);
+TALER_EXCHANGE_recoup (
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
+  const struct TALER_EXCHANGE_DenomPublicKey *pk,
+  const struct TALER_DenominationSignature *denom_sig,
+  const struct TALER_ExchangeWithdrawValues *exchange_vals,
+  const struct TALER_PlanchetMasterSecretP *ps,
+  TALER_EXCHANGE_RecoupResultCallback recoup_cb,
+  void *recoup_cb_cls);
 
 
 /**
@@ -3692,7 +3743,9 @@ typedef void
  * revoked coin was refreshed from. The original coin is then
  * considered a zombie.
  *
- * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param ctx curl context
+ * @param url exchange base URL
+ * @param keys exchange keys
  * @param pk kind of coin to pay back
  * @param denom_sig signature over the coin by the exchange using @a pk
  * @param exchange_vals contribution from the exchange on the withdraw
@@ -3707,7 +3760,9 @@ typedef void
  */
 struct TALER_EXCHANGE_RecoupRefreshHandle *
 TALER_EXCHANGE_recoup_refresh (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
   const struct TALER_EXCHANGE_DenomPublicKey *pk,
   const struct TALER_DenominationSignature *denom_sig,
   const struct TALER_ExchangeWithdrawValues *exchange_vals,
@@ -4258,10 +4313,11 @@ struct TALER_EXCHANGE_ManagementGetKeysHandle;
  * @return the request handle; NULL upon error
  */
 struct TALER_EXCHANGE_ManagementGetKeysHandle *
-TALER_EXCHANGE_get_management_keys (struct GNUNET_CURL_Context *ctx,
-                                    const char *url,
-                                    TALER_EXCHANGE_ManagementGetKeysCallback 
cb,
-                                    void *cb_cls);
+TALER_EXCHANGE_get_management_keys (
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  TALER_EXCHANGE_ManagementGetKeysCallback cb,
+  void *cb_cls);
 
 
 /**
@@ -5787,7 +5843,9 @@ struct TALER_EXCHANGE_PurseGetHandle;
 /**
  * Request information about a purse from the exchange.
  *
- * @param exchange exchange handle
+ * @param ctx curl context
+ * @param url exchange base URL
+ * @param keys exchange keys
  * @param purse_pub public key of the purse
  * @param timeout how long to wait for a change to happen
  * @param wait_for_merge true to wait for a merge event, otherwise wait for a 
deposit event
@@ -5797,7 +5855,9 @@ struct TALER_EXCHANGE_PurseGetHandle;
  */
 struct TALER_EXCHANGE_PurseGetHandle *
 TALER_EXCHANGE_purse_get (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
   const struct TALER_PurseContractPublicKeyP *purse_pub,
   struct GNUNET_TIME_Relative timeout,
   bool wait_for_merge,
@@ -5911,7 +5971,9 @@ struct TALER_EXCHANGE_PurseDeposit
  * Inform the exchange that a purse should be created
  * and coins deposited into it.
  *
- * @param exchange the exchange to interact with
+ * @param ctx curl context
+ * @param url exchange base URL
+ * @param keys exchange keys
  * @param purse_priv private key of the purse
  * @param merge_priv the merge credential
  * @param contract_priv key needed to obtain and decrypt the contract
@@ -5927,7 +5989,9 @@ struct TALER_EXCHANGE_PurseDeposit
  */
 struct TALER_EXCHANGE_PurseCreateDepositHandle *
 TALER_EXCHANGE_purse_create_with_deposit (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
   const struct TALER_PurseContractPrivateKeyP *purse_priv,
   const struct TALER_PurseMergePrivateKeyP *merge_priv,
   const struct TALER_ContractDiffiePrivateP *contract_priv,
@@ -6091,7 +6155,9 @@ struct TALER_EXCHANGE_AccountMergeHandle;
  * Inform the exchange that a purse should be merged
  * with a reserve.
  *
- * @param exchange the exchange hosting the purse
+ * @param ctx curl context
+ * @param url exchange base URL
+ * @param keys exchange keys
  * @param reserve_exchange_url base URL of the exchange with the reserve
  * @param reserve_priv private key of the reserve to merge into
  * @param purse_pub public key of the purse to merge
@@ -6107,7 +6173,9 @@ struct TALER_EXCHANGE_AccountMergeHandle;
  */
 struct TALER_EXCHANGE_AccountMergeHandle *
 TALER_EXCHANGE_account_merge (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
   const char *reserve_exchange_url,
   const struct TALER_ReservePrivateKeyP *reserve_priv,
   const struct TALER_PurseContractPublicKeyP *purse_pub,
@@ -6199,7 +6267,9 @@ struct TALER_EXCHANGE_PurseCreateMergeHandle;
  * Inform the exchange that a purse should be created
  * and merged with a reserve.
  *
- * @param exchange the exchange hosting the reserve
+ * @param ctx curl context
+ * @param url exchange base URL
+ * @param keys exchange keys
  * @param reserve_priv private key of the reserve
  * @param purse_priv private key of the purse
  * @param merge_priv private key of the merge capability
@@ -6214,7 +6284,9 @@ struct TALER_EXCHANGE_PurseCreateMergeHandle;
  */
 struct TALER_EXCHANGE_PurseCreateMergeHandle *
 TALER_EXCHANGE_purse_create_with_merge (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
   const struct TALER_ReservePrivateKeyP *reserve_priv,
   const struct TALER_PurseContractPrivateKeyP *purse_priv,
   const struct TALER_PurseMergePrivateKeyP *merge_priv,
@@ -6306,7 +6378,9 @@ struct TALER_EXCHANGE_PurseDepositHandle;
  * Inform the exchange that a deposit should be made into
  * a purse.
  *
- * @param exchange the exchange that issued the coins
+ * @param ctx curl context
+ * @param url exchange base URL
+ * @param keys exchange keys
  * @param purse_exchange_url base URL of the exchange hosting the purse
  * @param purse_pub public key of the purse to merge
  * @param min_age minimum age we need to prove for the purse
@@ -6318,7 +6392,9 @@ struct TALER_EXCHANGE_PurseDepositHandle;
  */
 struct TALER_EXCHANGE_PurseDepositHandle *
 TALER_EXCHANGE_purse_deposit (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
   const char *purse_exchange_url,
   const struct TALER_PurseContractPublicKeyP *purse_pub,
   uint8_t min_age,
@@ -6442,7 +6518,9 @@ typedef void
 /**
  * Submit a request to open a reserve.
  *
- * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param ctx curl context
+ * @param url exchange base URL
+ * @param keys exchange keys
  * @param reserve_priv private key of the reserve to open
  * @param reserve_contribution amount to pay from the reserve's balance for 
the operation
  * @param coin_payments_length length of the @a coin_payments array
@@ -6456,7 +6534,9 @@ typedef void
  */
 struct TALER_EXCHANGE_ReservesOpenHandle *
 TALER_EXCHANGE_reserves_open (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
   const struct TALER_ReservePrivateKeyP *reserve_priv,
   const struct TALER_Amount *reserve_contribution,
   unsigned int coin_payments_length,
@@ -6760,7 +6840,8 @@ typedef void
 /**
  * Submit a request to close a reserve.
  *
- * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param ctx curl context
+ * @param url exchange base URL
  * @param reserve_priv private key of the reserve to close
  * @param target_payto_uri where to send the payment, NULL to send to reserve 
origin
  * @param cb the callback to call when a reply for this request is available
@@ -6770,7 +6851,8 @@ typedef void
  */
 struct TALER_EXCHANGE_ReservesCloseHandle *
 TALER_EXCHANGE_reserves_close (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
   const struct TALER_ReservePrivateKeyP *reserve_priv,
   const char *target_payto_uri,
   TALER_EXCHANGE_ReservesCloseCallback cb,
diff --git a/src/lib/exchange_api_batch_withdraw2.c 
b/src/lib/exchange_api_batch_withdraw2.c
index 04c2c010..6dd421ce 100644
--- a/src/lib/exchange_api_batch_withdraw2.c
+++ b/src/lib/exchange_api_batch_withdraw2.c
@@ -218,14 +218,15 @@ reserve_batch_withdraw_payment_required (
     }
 
     if (GNUNET_OK !=
-        TALER_EXCHANGE_parse_reserve_history (wh->exchange,
-                                              history,
-                                              &wh->reserve_pub,
-                                              balance.currency,
-                                              &total_in_from_history,
-                                              &total_out_from_history,
-                                              len,
-                                              rhistory))
+        TALER_EXCHANGE_parse_reserve_history (
+          TALER_EXCHANGE_get_keys (wh->exchange),
+          history,
+          &wh->reserve_pub,
+          balance.currency,
+          &total_in_from_history,
+          &total_out_from_history,
+          len,
+          rhistory))
     {
       GNUNET_break_op (0);
       TALER_EXCHANGE_free_reserve_history (rhistory,
diff --git a/src/lib/exchange_api_common.c b/src/lib/exchange_api_common.c
index 8bbc6c47..f43673d7 100644
--- a/src/lib/exchange_api_common.c
+++ b/src/lib/exchange_api_common.c
@@ -34,9 +34,9 @@ struct HistoryParseContext
 {
 
   /**
-   * Exchange we use.
+   * Keys of the exchange we use.
    */
-  struct TALER_EXCHANGE_Handle *exchange;
+  struct TALER_EXCHANGE_Keys *keys;
 
   /**
    * Our reserve public key.
@@ -187,7 +187,7 @@ parse_withdraw (struct TALER_EXCHANGE_ReserveHistoryEntry 
*rh,
     const struct TALER_EXCHANGE_Keys *key_state;
     const struct TALER_EXCHANGE_DenomPublicKey *dki;
 
-    key_state = TALER_EXCHANGE_get_keys (uc->exchange);
+    key_state = uc->keys;
     dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state,
                                                        &h_denom_pub);
     if ( (GNUNET_YES !=
@@ -275,7 +275,7 @@ parse_recoup (struct TALER_EXCHANGE_ReserveHistoryEntry *rh,
     GNUNET_break_op (0);
     return GNUNET_SYSERR;
   }
-  key_state = TALER_EXCHANGE_get_keys (uc->exchange);
+  key_state = uc->keys;
   if (GNUNET_OK !=
       TALER_EXCHANGE_test_signing_key (key_state,
                                        &rh->details.
@@ -349,7 +349,7 @@ parse_closing (struct TALER_EXCHANGE_ReserveHistoryEntry 
*rh,
     GNUNET_break_op (0);
     return GNUNET_SYSERR;
   }
-  key_state = TALER_EXCHANGE_get_keys (uc->exchange);
+  key_state = uc->keys;
   if (GNUNET_OK !=
       TALER_EXCHANGE_test_signing_key (
         key_state,
@@ -647,7 +647,7 @@ parse_close (struct TALER_EXCHANGE_ReserveHistoryEntry *rh,
 
 enum GNUNET_GenericReturnValue
 TALER_EXCHANGE_parse_reserve_history (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct TALER_EXCHANGE_Keys *keys,
   const json_t *history,
   const struct TALER_ReservePublicKeyP *reserve_pub,
   const char *currency,
@@ -673,7 +673,7 @@ TALER_EXCHANGE_parse_reserve_history (
   };
   struct GNUNET_HashCode uuid[history_length];
   struct HistoryParseContext uc = {
-    .exchange = exchange,
+    .keys = keys,
     .reserve_pub = reserve_pub,
     .uuids = uuid,
     .total_in = total_in,
diff --git a/src/lib/exchange_api_csr_melt.c b/src/lib/exchange_api_csr_melt.c
index 67b1a9b7..da6c392a 100644
--- a/src/lib/exchange_api_csr_melt.c
+++ b/src/lib/exchange_api_csr_melt.c
@@ -38,10 +38,6 @@
  */
 struct TALER_EXCHANGE_CsRMeltHandle
 {
-  /**
-   * The connection to exchange this request handle will use
-   */
-  struct TALER_EXCHANGE_Handle *exchange;
 
   /**
    * Function to call with the result.
@@ -220,12 +216,14 @@ handle_csr_finished (void *cls,
 
 
 struct TALER_EXCHANGE_CsRMeltHandle *
-TALER_EXCHANGE_csr_melt (struct TALER_EXCHANGE_Handle *exchange,
-                         const struct TALER_RefreshMasterSecretP *rms,
-                         unsigned int nks_len,
-                         struct TALER_EXCHANGE_NonceKey *nks,
-                         TALER_EXCHANGE_CsRMeltCallback res_cb,
-                         void *res_cb_cls)
+TALER_EXCHANGE_csr_melt (
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  const struct TALER_RefreshMasterSecretP *rms,
+  unsigned int nks_len,
+  struct TALER_EXCHANGE_NonceKey *nks,
+  TALER_EXCHANGE_CsRMeltCallback res_cb,
+  void *res_cb_cls)
 {
   struct TALER_EXCHANGE_CsRMeltHandle *csrh;
   json_t *csr_arr;
@@ -242,7 +240,6 @@ TALER_EXCHANGE_csr_melt (struct TALER_EXCHANGE_Handle 
*exchange,
       return NULL;
     }
   csrh = GNUNET_new (struct TALER_EXCHANGE_CsRMeltHandle);
-  csrh->exchange = exchange;
   csrh->cb = res_cb;
   csrh->cb_cls = res_cb_cls;
   csr_arr = json_array ();
@@ -262,8 +259,9 @@ TALER_EXCHANGE_csr_melt (struct TALER_EXCHANGE_Handle 
*exchange,
                    json_array_append_new (csr_arr,
                                           csr_obj));
   }
-  csrh->url = TEAH_path_to_url (exchange,
-                                "/csr-melt");
+  csrh->url = TALER_url_join (url,
+                              "csr-melt",
+                              NULL);
   if (NULL == csrh->url)
   {
     json_decref (csr_arr);
@@ -272,7 +270,6 @@ TALER_EXCHANGE_csr_melt (struct TALER_EXCHANGE_Handle 
*exchange,
   }
   {
     CURL *eh;
-    struct GNUNET_CURL_Context *ctx;
     json_t *req;
 
     req = GNUNET_JSON_PACK (
@@ -280,7 +277,6 @@ TALER_EXCHANGE_csr_melt (struct TALER_EXCHANGE_Handle 
*exchange,
                                   rms),
       GNUNET_JSON_pack_array_steal ("nks",
                                     csr_arr));
-    ctx = TEAH_handle_to_context (exchange);
     eh = TALER_EXCHANGE_curl_easy_get_ (csrh->url);
     if ( (NULL == eh) ||
          (GNUNET_OK !=
diff --git a/src/lib/exchange_api_deposits_get.c 
b/src/lib/exchange_api_deposits_get.c
index 9ec25e45..8b145dab 100644
--- a/src/lib/exchange_api_deposits_get.c
+++ b/src/lib/exchange_api_deposits_get.c
@@ -39,9 +39,9 @@ struct TALER_EXCHANGE_DepositGetHandle
 {
 
   /**
-   * The connection to exchange this request handle will use
+   * The keys of the this request handle will use
    */
-  struct TALER_EXCHANGE_Handle *exchange;
+  struct TALER_EXCHANGE_Keys *keys;
 
   /**
    * The url for this request.
@@ -131,7 +131,7 @@ handle_deposit_wtid_finished (void *cls,
       };
       const struct TALER_EXCHANGE_Keys *key_state;
 
-      key_state = TALER_EXCHANGE_get_keys (dwh->exchange);
+      key_state = dwh->keys;
       GNUNET_assert (NULL != key_state);
       if (GNUNET_OK !=
           GNUNET_JSON_parse (j,
@@ -255,7 +255,9 @@ handle_deposit_wtid_finished (void *cls,
 
 struct TALER_EXCHANGE_DepositGetHandle *
 TALER_EXCHANGE_deposits_get (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
   const struct TALER_MerchantPrivateKeyP *merchant_priv,
   const struct TALER_MerchantWireHashP *h_wire,
   const struct TALER_PrivateContractHashP *h_contract_terms,
@@ -267,7 +269,6 @@ TALER_EXCHANGE_deposits_get (
   struct TALER_MerchantPublicKeyP merchant;
   struct TALER_MerchantSignatureP merchant_sig;
   struct TALER_EXCHANGE_DepositGetHandle *dwh;
-  struct GNUNET_CURL_Context *ctx;
   CURL *eh;
   char arg_str[(sizeof (struct TALER_CoinSpendPublicKeyP)
                 + sizeof (struct TALER_MerchantWireHashP)
@@ -275,12 +276,6 @@ TALER_EXCHANGE_deposits_get (
                 + sizeof (struct TALER_PrivateContractHashP)
                 + sizeof (struct TALER_MerchantSignatureP)) * 2 + 48];
 
-  if (GNUNET_YES !=
-      TEAH_handle_is_ready (exchange))
-  {
-    GNUNET_break (0);
-    return NULL;
-  }
   GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv->eddsa_priv,
                                       &merchant.eddsa_pub);
   TALER_merchant_deposit_sign (h_contract_terms,
@@ -339,7 +334,7 @@ TALER_EXCHANGE_deposits_get (
 
     GNUNET_snprintf (arg_str,
                      sizeof (arg_str),
-                     "/deposits/%s/%s/%s/%s?merchant_sig=%s%s%s",
+                     "deposits/%s/%s/%s/%s?merchant_sig=%s%s%s",
                      whash_str,
                      mpub_str,
                      chash_str,
@@ -352,11 +347,11 @@ TALER_EXCHANGE_deposits_get (
   }
 
   dwh = GNUNET_new (struct TALER_EXCHANGE_DepositGetHandle);
-  dwh->exchange = exchange;
   dwh->cb = cb;
   dwh->cb_cls = cb_cls;
-  dwh->url = TEAH_path_to_url (exchange,
-                               arg_str);
+  dwh->url = TALER_url_join (url,
+                             arg_str,
+                             NULL);
   if (NULL == dwh->url)
   {
     GNUNET_free (dwh);
@@ -365,7 +360,6 @@ TALER_EXCHANGE_deposits_get (
   dwh->h_wire = *h_wire;
   dwh->h_contract_terms = *h_contract_terms;
   dwh->coin_pub = *coin_pub;
-
   eh = TALER_EXCHANGE_curl_easy_get_ (dwh->url);
   if (NULL == eh)
   {
@@ -374,11 +368,11 @@ TALER_EXCHANGE_deposits_get (
     GNUNET_free (dwh);
     return NULL;
   }
-  ctx = TEAH_handle_to_context (exchange);
   dwh->job = GNUNET_CURL_job_add (ctx,
                                   eh,
                                   &handle_deposit_wtid_finished,
                                   dwh);
+  dwh->keys = TALER_EXCHANGE_keys_incref (keys);
   return dwh;
 }
 
@@ -393,6 +387,7 @@ TALER_EXCHANGE_deposits_get_cancel (struct 
TALER_EXCHANGE_DepositGetHandle *dwh)
   }
   GNUNET_free (dwh->url);
   TALER_curl_easy_post_finished (&dwh->ctx);
+  TALER_EXCHANGE_keys_decref (dwh->keys);
   GNUNET_free (dwh);
 }
 
diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c
index 7e302112..fe73f050 100644
--- a/src/lib/exchange_api_handle.c
+++ b/src/lib/exchange_api_handle.c
@@ -2239,6 +2239,20 @@ TALER_EXCHANGE_get_keys_raw (struct 
TALER_EXCHANGE_Handle *exchange)
 }
 
 
+/**
+ * Obtain the keys from the exchange in the raw JSON format.
+ *
+ * @param keys the keys structure
+ * @return the keys in raw JSON
+ */
+json_t *
+TALER_EXCHANGE_keys_to_json (struct TALER_EXCHANGE_Keys *keys)
+{
+  // FIXME!
+  return NULL;
+}
+
+
 struct TALER_EXCHANGE_Keys *
 TALER_EXCHANGE_keys_incref (struct TALER_EXCHANGE_Keys *keys)
 {
diff --git a/src/lib/exchange_api_melt.c b/src/lib/exchange_api_melt.c
index 3a8144a3..1da4184d 100644
--- a/src/lib/exchange_api_melt.c
+++ b/src/lib/exchange_api_melt.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2015-2022 Taler Systems SA
+  Copyright (C) 2015-2023 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU General Public License as published by the Free Software
@@ -41,15 +41,25 @@ struct TALER_EXCHANGE_MeltHandle
 {
 
   /**
-   * The connection to exchange this request handle will use
+   * The keys of the this request handle will use
    */
-  struct TALER_EXCHANGE_Handle *exchange;
+  struct TALER_EXCHANGE_Keys *keys;
 
   /**
    * The url for this request.
    */
   char *url;
 
+  /**
+   * The exchange base url.
+   */
+  char *exchange_url;
+
+  /**
+   * Curl context.
+   */
+  struct GNUNET_CURL_Context *cctx;
+
   /**
    * Context for #TEH_curl_easy_post(). Keeps the data that must
    * persist for Curl to make the upload.
@@ -159,7 +169,7 @@ verify_melt_signature_ok (struct TALER_EXCHANGE_MeltHandle 
*mh,
     return GNUNET_SYSERR;
   }
   /* check that exchange signing key is permitted */
-  key_state = TALER_EXCHANGE_get_keys (mh->exchange);
+  key_state = mh->keys;
   if (GNUNET_OK !=
       TALER_EXCHANGE_test_signing_key (key_state,
                                        exchange_pub))
@@ -211,7 +221,7 @@ handle_melt_finished (void *cls,
   const struct TALER_EXCHANGE_Keys *keys;
 
   mh->job = NULL;
-  keys = TALER_EXCHANGE_get_keys (mh->exchange);
+  keys = mh->keys;
   switch (response_code)
   {
   case 0:
@@ -309,7 +319,6 @@ start_melt (struct TALER_EXCHANGE_MeltHandle *mh)
   const struct TALER_EXCHANGE_Keys *key_state;
   json_t *melt_obj;
   CURL *eh;
-  struct GNUNET_CURL_Context *ctx;
   char arg_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2 + 32];
   struct TALER_DenominationHashP h_denom_pub;
   struct TALER_ExchangeWithdrawValues alg_values[mh->rd->fresh_pks_len];
@@ -371,19 +380,19 @@ start_melt (struct TALER_EXCHANGE_MeltHandle *mh)
     *end = '\0';
     GNUNET_snprintf (arg_str,
                      sizeof (arg_str),
-                     "/coins/%s/melt",
+                     "coins/%s/melt",
                      pub_str);
   }
 
-  ctx = TEAH_handle_to_context (mh->exchange);
-  key_state = TALER_EXCHANGE_get_keys (mh->exchange);
+  key_state = mh->keys;
   mh->dki = TALER_EXCHANGE_get_denomination_key (key_state,
                                                  &mh->md.melted_coin.pub_key);
 
   /* and now we can at last begin the actual request handling */
 
-  mh->url = TEAH_path_to_url (mh->exchange,
-                              arg_str);
+  mh->url = TALER_url_join (mh->exchange_url,
+                            arg_str,
+                            NULL);
   if (NULL == mh->url)
   {
     json_decref (melt_obj);
@@ -403,7 +412,7 @@ start_melt (struct TALER_EXCHANGE_MeltHandle *mh)
     return GNUNET_SYSERR;
   }
   json_decref (melt_obj);
-  mh->job = GNUNET_CURL_job_add2 (ctx,
+  mh->job = GNUNET_CURL_job_add2 (mh->cctx,
                                   eh,
                                   mh->ctx.headers,
                                   &handle_melt_finished,
@@ -496,11 +505,14 @@ csr_cb (void *cls,
 
 
 struct TALER_EXCHANGE_MeltHandle *
-TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange,
-                     const struct TALER_RefreshMasterSecretP *rms,
-                     const struct TALER_EXCHANGE_RefreshData *rd,
-                     TALER_EXCHANGE_MeltCallback melt_cb,
-                     void *melt_cb_cls)
+TALER_EXCHANGE_melt (
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
+  const struct TALER_RefreshMasterSecretP *rms,
+  const struct TALER_EXCHANGE_RefreshData *rd,
+  TALER_EXCHANGE_MeltCallback melt_cb,
+  void *melt_cb_cls)
 {
   struct TALER_EXCHANGE_NonceKey nks[GNUNET_NZL (rd->fresh_pks_len)];
   unsigned int nks_off = 0;
@@ -511,11 +523,10 @@ TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle 
*exchange,
     GNUNET_break (0);
     return NULL;
   }
-  GNUNET_assert (GNUNET_YES ==
-                 TEAH_handle_is_ready (exchange));
   mh = GNUNET_new (struct TALER_EXCHANGE_MeltHandle);
   mh->noreveal_index = TALER_CNC_KAPPA; /* invalid value */
-  mh->exchange = exchange;
+  mh->cctx = ctx;
+  mh->exchange_url = GNUNET_strdup (url);
   mh->rd = rd;
   mh->rms = *rms;
   mh->melt_cb = melt_cb;
@@ -545,9 +556,11 @@ TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle 
*exchange,
       break;
     }
   }
+  mh->keys = TALER_EXCHANGE_keys_incref (keys);
   if (0 != nks_off)
   {
-    mh->csr = TALER_EXCHANGE_csr_melt (exchange,
+    mh->csr = TALER_EXCHANGE_csr_melt (ctx,
+                                       url,
                                        rms,
                                        nks_off,
                                        nks,
@@ -588,7 +601,9 @@ TALER_EXCHANGE_melt_cancel (struct 
TALER_EXCHANGE_MeltHandle *mh)
   TALER_EXCHANGE_free_melt_data_ (&mh->md); /* does not free 'md' itself */
   GNUNET_free (mh->mbds);
   GNUNET_free (mh->url);
+  GNUNET_free (mh->exchange_url);
   TALER_curl_easy_post_finished (&mh->ctx);
+  TALER_EXCHANGE_keys_decref (mh->keys);
   GNUNET_free (mh);
 }
 
diff --git a/src/lib/exchange_api_purse_create_with_deposit.c 
b/src/lib/exchange_api_purse_create_with_deposit.c
index a2618d63..af05bf92 100644
--- a/src/lib/exchange_api_purse_create_with_deposit.c
+++ b/src/lib/exchange_api_purse_create_with_deposit.c
@@ -1,6 +1,6 @@
 /*
    This file is part of TALER
-   Copyright (C) 2022 Taler Systems SA
+   Copyright (C) 2022-2023 Taler Systems SA
 
    TALER is free software; you can redistribute it and/or modify it under the
    terms of the GNU General Public License as published by the Free Software
@@ -73,15 +73,20 @@ struct TALER_EXCHANGE_PurseCreateDepositHandle
 {
 
   /**
-   * The connection to exchange this request handle will use
+   * The keys of the exchange this request handle will use
    */
-  struct TALER_EXCHANGE_Handle *exchange;
+  struct TALER_EXCHANGE_Keys *keys;
 
   /**
    * The url for this request.
    */
   char *url;
 
+  /**
+   * The base URL of the exchange.
+   */
+  char *exchange_url;
+
   /**
    * Context for #TEH_curl_easy_post(). Keeps the data that must
    * persist for Curl to make the upload.
@@ -170,10 +175,9 @@ handle_purse_create_deposit_finished (void *cls,
     .hr.reply = j,
     .hr.http_status = (unsigned int) response_code
   };
-  const struct TALER_EXCHANGE_Keys *keys;
+  const struct TALER_EXCHANGE_Keys *keys = pch->keys;
 
   pch->job = NULL;
-  keys = TALER_EXCHANGE_get_keys (pch->exchange);
   switch (response_code)
   {
   case 0:
@@ -181,7 +185,6 @@ handle_purse_create_deposit_finished (void *cls,
     break;
   case MHD_HTTP_OK:
     {
-      const struct TALER_EXCHANGE_Keys *key_state;
       struct GNUNET_TIME_Timestamp etime;
       struct TALER_Amount total_deposited;
       struct TALER_ExchangeSignatureP exchange_sig;
@@ -209,9 +212,8 @@ handle_purse_create_deposit_finished (void *cls,
         dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
         break;
       }
-      key_state = TALER_EXCHANGE_get_keys (pch->exchange);
       if (GNUNET_OK !=
-          TALER_EXCHANGE_test_signing_key (key_state,
+          TALER_EXCHANGE_test_signing_key (keys,
                                            &exchange_pub))
       {
         GNUNET_break_op (0);
@@ -387,7 +389,7 @@ handle_purse_create_deposit_finished (void *cls,
           if (GNUNET_OK !=
               TALER_EXCHANGE_check_purse_coin_conflict_ (
                 &pch->purse_pub,
-                pch->exchange->url,
+                pch->exchange_url,
                 j,
                 &h_denom_pub,
                 &phac,
@@ -496,7 +498,9 @@ handle_purse_create_deposit_finished (void *cls,
 
 struct TALER_EXCHANGE_PurseCreateDepositHandle *
 TALER_EXCHANGE_purse_create_with_deposit (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
   const struct TALER_PurseContractPrivateKeyP *purse_priv,
   const struct TALER_PurseMergePrivateKeyP *merge_priv,
   const struct TALER_ContractDiffiePrivateP *contract_priv,
@@ -508,16 +512,13 @@ TALER_EXCHANGE_purse_create_with_deposit (
   void *cb_cls)
 {
   struct TALER_EXCHANGE_PurseCreateDepositHandle *pch;
-  struct GNUNET_CURL_Context *ctx;
   json_t *create_obj;
   json_t *deposit_arr;
   CURL *eh;
   char arg_str[sizeof (pch->purse_pub) * 2 + 32];
-  char *url;
   uint32_t min_age = 0;
 
   pch = GNUNET_new (struct TALER_EXCHANGE_PurseCreateDepositHandle);
-  pch->exchange = exchange;
   pch->cb = cb;
   pch->cb_cls = cb_cls;
   {
@@ -542,8 +543,6 @@ TALER_EXCHANGE_purse_create_with_deposit (
       return NULL;
     }
   }
-  GNUNET_assert (GNUNET_YES ==
-                 TEAH_handle_is_ready (exchange));
   if (GNUNET_OK !=
       TALER_JSON_contract_hash (contract_terms,
                                 &pch->h_contract_terms))
@@ -565,13 +564,14 @@ TALER_EXCHANGE_purse_create_with_deposit (
     *end = '\0';
     GNUNET_snprintf (arg_str,
                      sizeof (arg_str),
-                     "/purses/%s/create",
+                     "purses/%s/create",
                      pub_str);
   }
   GNUNET_CRYPTO_eddsa_key_get_public (&merge_priv->eddsa_priv,
                                       &pch->merge_pub.eddsa_pub);
-  pch->url = TEAH_path_to_url (exchange,
-                               arg_str);
+  pch->url = TALER_url_join (url,
+                             arg_str,
+                             NULL);
   if (NULL == pch->url)
   {
     GNUNET_break (0);
@@ -583,8 +583,6 @@ TALER_EXCHANGE_purse_create_with_deposit (
                                     struct Deposit);
   deposit_arr = json_array ();
   GNUNET_assert (NULL != deposit_arr);
-  url = TEAH_path_to_url (exchange,
-                          "/");
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "Signing with URL `%s'\n",
               url);
@@ -610,7 +608,6 @@ TALER_EXCHANGE_purse_create_with_deposit (
       {
         GNUNET_break (0);
         json_decref (deposit_arr);
-        GNUNET_free (url);
         GNUNET_free (pch);
         return NULL;
       }
@@ -648,7 +645,6 @@ TALER_EXCHANGE_purse_create_with_deposit (
                    json_array_append_new (deposit_arr,
                                           jdeposit));
   }
-  GNUNET_free (url);
   TALER_wallet_purse_create_sign (pch->purse_expiration,
                                   &pch->h_contract_terms,
                                   &pch->merge_pub,
@@ -714,7 +710,8 @@ TALER_EXCHANGE_purse_create_with_deposit (
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "URL for purse create with deposit: `%s'\n",
               pch->url);
-  ctx = TEAH_handle_to_context (exchange);
+  pch->keys = TALER_EXCHANGE_keys_incref (keys);
+  pch->exchange_url = GNUNET_strdup (url);
   pch->job = GNUNET_CURL_job_add2 (ctx,
                                    eh,
                                    pch->ctx.headers,
@@ -734,8 +731,10 @@ TALER_EXCHANGE_purse_create_with_deposit_cancel (
     pch->job = NULL;
   }
   GNUNET_free (pch->econtract.econtract);
+  GNUNET_free (pch->exchange_url);
   GNUNET_free (pch->url);
   GNUNET_free (pch->deposits);
+  TALER_EXCHANGE_keys_decref (pch->keys);
   TALER_curl_easy_post_finished (&pch->ctx);
   GNUNET_free (pch);
 }
diff --git a/src/lib/exchange_api_purse_create_with_merge.c 
b/src/lib/exchange_api_purse_create_with_merge.c
index 460239fc..0c887834 100644
--- a/src/lib/exchange_api_purse_create_with_merge.c
+++ b/src/lib/exchange_api_purse_create_with_merge.c
@@ -1,6 +1,6 @@
 /*
    This file is part of TALER
-   Copyright (C) 2022 Taler Systems SA
+   Copyright (C) 2022-2023 Taler Systems SA
 
    TALER is free software; you can redistribute it and/or modify it under the
    terms of the GNU General Public License as published by the Free Software
@@ -41,15 +41,20 @@ struct TALER_EXCHANGE_PurseCreateMergeHandle
 {
 
   /**
-   * The connection to exchange this request handle will use
+   * The keys of the exchange this request handle will use
    */
-  struct TALER_EXCHANGE_Handle *exchange;
+  struct TALER_EXCHANGE_Keys *keys;
 
   /**
    * The url for this request.
    */
   char *url;
 
+  /**
+   * The exchange base URL.
+   */
+  char *exchange_url;
+
   /**
    * Context for #TEH_curl_easy_post(). Keeps the data that must
    * persist for Curl to make the upload.
@@ -157,7 +162,6 @@ handle_purse_create_with_merge_finished (void *cls,
     break;
   case MHD_HTTP_OK:
     {
-      const struct TALER_EXCHANGE_Keys *key_state;
       struct GNUNET_TIME_Timestamp etime;
       struct TALER_Amount total_deposited;
       struct TALER_ExchangeSignatureP exchange_sig;
@@ -184,9 +188,8 @@ handle_purse_create_with_merge_finished (void *cls,
         dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
         break;
       }
-      key_state = TALER_EXCHANGE_get_keys (pcm->exchange);
       if (GNUNET_OK !=
-          TALER_EXCHANGE_test_signing_key (key_state,
+          TALER_EXCHANGE_test_signing_key (pcm->keys,
                                            &exchange_pub))
       {
         GNUNET_break_op (0);
@@ -253,7 +256,7 @@ handle_purse_create_with_merge_finished (void *cls,
             &pcm->merge_sig,
             &pcm->merge_pub,
             &pcm->purse_pub,
-            pcm->exchange->url,
+            pcm->exchange_url,
             j))
       {
         GNUNET_break_op (0);
@@ -340,7 +343,9 @@ handle_purse_create_with_merge_finished (void *cls,
 
 struct TALER_EXCHANGE_PurseCreateMergeHandle *
 TALER_EXCHANGE_purse_create_with_merge (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
   const struct TALER_ReservePrivateKeyP *reserve_priv,
   const struct TALER_PurseContractPrivateKeyP *purse_priv,
   const struct TALER_PurseMergePrivateKeyP *merge_priv,
@@ -353,7 +358,6 @@ TALER_EXCHANGE_purse_create_with_merge (
   void *cb_cls)
 {
   struct TALER_EXCHANGE_PurseCreateMergeHandle *pcm;
-  struct GNUNET_CURL_Context *ctx;
   json_t *create_with_merge_obj;
   CURL *eh;
   char arg_str[sizeof (pcm->reserve_pub) * 2 + 32];
@@ -362,7 +366,6 @@ TALER_EXCHANGE_purse_create_with_merge (
   enum TALER_WalletAccountMergeFlags flags;
 
   pcm = GNUNET_new (struct TALER_EXCHANGE_PurseCreateMergeHandle);
-  pcm->exchange = exchange;
   pcm->cb = cb;
   pcm->cb_cls = cb_cls;
   if (GNUNET_OK !=
@@ -409,7 +412,7 @@ TALER_EXCHANGE_purse_create_with_merge (
     const struct TALER_EXCHANGE_GlobalFee *gf;
 
     gf = TALER_EXCHANGE_get_global_fee (
-      TALER_EXCHANGE_get_keys (exchange),
+      keys,
       GNUNET_TIME_timestamp_get ());
     purse_fee = gf->fees.purse;
     flags = TALER_WAMF_MODE_CREATE_WITH_PURSE_FEE;
@@ -422,8 +425,6 @@ TALER_EXCHANGE_purse_create_with_merge (
     flags = TALER_WAMF_MODE_CREATE_FROM_PURSE_QUOTA;
   }
 
-  GNUNET_assert (GNUNET_YES ==
-                 TEAH_handle_is_ready (exchange));
   {
     char pub_str[sizeof (pcm->reserve_pub) * 2];
     char *end;
@@ -436,11 +437,12 @@ TALER_EXCHANGE_purse_create_with_merge (
     *end = '\0';
     GNUNET_snprintf (arg_str,
                      sizeof (arg_str),
-                     "/reserves/%s/purse",
+                     "reserves/%s/purse",
                      pub_str);
   }
-  pcm->url = TEAH_path_to_url (exchange,
-                               arg_str);
+  pcm->url = TALER_url_join (url,
+                             arg_str,
+                             NULL);
   if (NULL == pcm->url)
   {
     GNUNET_break (0);
@@ -457,7 +459,7 @@ TALER_EXCHANGE_purse_create_with_merge (
   {
     char *payto_uri;
 
-    payto_uri = TALER_reserve_make_payto (exchange->url,
+    payto_uri = TALER_reserve_make_payto (url,
                                           &pcm->reserve_pub);
     TALER_wallet_purse_merge_sign (payto_uri,
                                    merge_timestamp,
@@ -546,7 +548,8 @@ TALER_EXCHANGE_purse_create_with_merge (
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "URL for purse create_with_merge: `%s'\n",
               pcm->url);
-  ctx = TEAH_handle_to_context (exchange);
+  pcm->keys = TALER_EXCHANGE_keys_incref (keys);
+  pcm->exchange_url = GNUNET_strdup (url);
   pcm->job = GNUNET_CURL_job_add2 (ctx,
                                    eh,
                                    pcm->ctx.headers,
@@ -566,7 +569,9 @@ TALER_EXCHANGE_purse_create_with_merge_cancel (
     pcm->job = NULL;
   }
   GNUNET_free (pcm->url);
+  GNUNET_free (pcm->exchange_url);
   TALER_curl_easy_post_finished (&pcm->ctx);
+  TALER_EXCHANGE_keys_decref (pcm->keys);
   GNUNET_free (pcm->econtract.econtract);
   GNUNET_free (pcm);
 }
diff --git a/src/lib/exchange_api_purse_deposit.c 
b/src/lib/exchange_api_purse_deposit.c
index f88d2329..e1d38d16 100644
--- a/src/lib/exchange_api_purse_deposit.c
+++ b/src/lib/exchange_api_purse_deposit.c
@@ -1,6 +1,6 @@
 /*
    This file is part of TALER
-   Copyright (C) 2022 Taler Systems SA
+   Copyright (C) 2022-2023 Taler Systems SA
 
    TALER is free software; you can redistribute it and/or modify it under the
    terms of the GNU General Public License as published by the Free Software
@@ -73,9 +73,9 @@ struct TALER_EXCHANGE_PurseDepositHandle
 {
 
   /**
-   * The connection to exchange this request handle will use
+   * The keys of the exchange this request handle will use
    */
-  struct TALER_EXCHANGE_Handle *exchange;
+  struct TALER_EXCHANGE_Keys *keys;
 
   /**
    * The url for this request.
@@ -144,10 +144,9 @@ handle_purse_deposit_finished (void *cls,
     .hr.reply = j,
     .hr.http_status = (unsigned int) response_code
   };
-  const struct TALER_EXCHANGE_Keys *keys;
+  const struct TALER_EXCHANGE_Keys *keys = pch->keys;
 
   pch->job = NULL;
-  keys = TALER_EXCHANGE_get_keys (pch->exchange);
   switch (response_code)
   {
   case 0:
@@ -447,7 +446,9 @@ handle_purse_deposit_finished (void *cls,
 
 struct TALER_EXCHANGE_PurseDepositHandle *
 TALER_EXCHANGE_purse_deposit (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
   const char *purse_exchange_url,
   const struct TALER_PurseContractPublicKeyP *purse_pub,
   uint8_t min_age,
@@ -457,7 +458,6 @@ TALER_EXCHANGE_purse_deposit (
   void *cb_cls)
 {
   struct TALER_EXCHANGE_PurseDepositHandle *pch;
-  struct GNUNET_CURL_Context *ctx;
   json_t *create_obj;
   json_t *deposit_arr;
   CURL *eh;
@@ -470,11 +470,8 @@ TALER_EXCHANGE_purse_deposit (
     GNUNET_break (0);
     return NULL;
   }
-  GNUNET_assert (GNUNET_YES ==
-                 TEAH_handle_is_ready (exchange));
   pch = GNUNET_new (struct TALER_EXCHANGE_PurseDepositHandle);
   pch->purse_pub = *purse_pub;
-  pch->exchange = exchange;
   pch->cb = cb;
   pch->cb_cls = cb_cls;
   {
@@ -489,11 +486,12 @@ TALER_EXCHANGE_purse_deposit (
     *end = '\0';
     GNUNET_snprintf (arg_str,
                      sizeof (arg_str),
-                     "/purses/%s/deposit",
+                     "purses/%s/deposit",
                      pub_str);
   }
-  pch->url = TEAH_path_to_url (exchange,
-                               arg_str);
+  pch->url = TALER_url_join (url,
+                             arg_str,
+                             NULL);
   if (NULL == pch->url)
   {
     GNUNET_break (0);
@@ -502,8 +500,7 @@ TALER_EXCHANGE_purse_deposit (
   }
   deposit_arr = json_array ();
   GNUNET_assert (NULL != deposit_arr);
-  pch->base_url = TEAH_path_to_url (exchange,
-                                    "/");
+  pch->base_url = GNUNET_strdup (url);
   pch->num_deposits = num_deposits;
   pch->coins = GNUNET_new_array (num_deposits,
                                  struct Coin);
@@ -594,7 +591,7 @@ TALER_EXCHANGE_purse_deposit (
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "URL for purse deposit: `%s'\n",
               pch->url);
-  ctx = TEAH_handle_to_context (exchange);
+  pch->keys = TALER_EXCHANGE_keys_incref (keys);
   pch->job = GNUNET_CURL_job_add2 (ctx,
                                    eh,
                                    pch->ctx.headers,
@@ -616,6 +613,7 @@ TALER_EXCHANGE_purse_deposit_cancel (
   GNUNET_free (pch->base_url);
   GNUNET_free (pch->url);
   GNUNET_free (pch->coins);
+  TALER_EXCHANGE_keys_decref (pch->keys);
   TALER_curl_easy_post_finished (&pch->ctx);
   GNUNET_free (pch);
 }
diff --git a/src/lib/exchange_api_purse_merge.c 
b/src/lib/exchange_api_purse_merge.c
index 6e1995e0..8fd95251 100644
--- a/src/lib/exchange_api_purse_merge.c
+++ b/src/lib/exchange_api_purse_merge.c
@@ -1,6 +1,6 @@
 /*
    This file is part of TALER
-   Copyright (C) 2022 Taler Systems SA
+   Copyright (C) 2022-2023 Taler Systems SA
 
    TALER is free software; you can redistribute it and/or modify it under the
    terms of the GNU General Public License as published by the Free Software
@@ -41,9 +41,9 @@ struct TALER_EXCHANGE_AccountMergeHandle
 {
 
   /**
-   * The connection to exchange this request handle will use
+   * The keys of the exchange this request handle will use
    */
-  struct TALER_EXCHANGE_Handle *exchange;
+  struct TALER_EXCHANGE_Keys *keys;
 
   /**
    * The url for this request.
@@ -148,7 +148,6 @@ handle_purse_merge_finished (void *cls,
     break;
   case MHD_HTTP_OK:
     {
-      const struct TALER_EXCHANGE_Keys *key_state;
       struct TALER_Amount total_deposited;
       struct GNUNET_JSON_Specification spec[] = {
         GNUNET_JSON_spec_fixed_auto ("exchange_sig",
@@ -173,9 +172,8 @@ handle_purse_merge_finished (void *cls,
         dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
         break;
       }
-      key_state = TALER_EXCHANGE_get_keys (pch->exchange);
       if (GNUNET_OK !=
-          TALER_EXCHANGE_test_signing_key (key_state,
+          TALER_EXCHANGE_test_signing_key (pch->keys,
                                            &dr.details.ok.exchange_pub))
       {
         GNUNET_break_op (0);
@@ -302,7 +300,9 @@ handle_purse_merge_finished (void *cls,
 
 struct TALER_EXCHANGE_AccountMergeHandle *
 TALER_EXCHANGE_account_merge (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
   const char *reserve_exchange_url,
   const struct TALER_ReservePrivateKeyP *reserve_priv,
   const struct TALER_PurseContractPublicKeyP *purse_pub,
@@ -316,14 +316,12 @@ TALER_EXCHANGE_account_merge (
   void *cb_cls)
 {
   struct TALER_EXCHANGE_AccountMergeHandle *pch;
-  struct GNUNET_CURL_Context *ctx;
   json_t *merge_obj;
   CURL *eh;
   char arg_str[sizeof (pch->purse_pub) * 2 + 32];
   char *reserve_url;
 
   pch = GNUNET_new (struct TALER_EXCHANGE_AccountMergeHandle);
-  pch->exchange = exchange;
   pch->merge_priv = *merge_priv;
   pch->cb = cb;
   pch->cb_cls = cb_cls;
@@ -332,14 +330,12 @@ TALER_EXCHANGE_account_merge (
   pch->purse_expiration = purse_expiration;
   pch->purse_value_after_fees = *purse_value_after_fees;
   if (NULL == reserve_exchange_url)
-    pch->provider_url = GNUNET_strdup (exchange->url);
+    pch->provider_url = GNUNET_strdup (url);
   else
     pch->provider_url = GNUNET_strdup (reserve_exchange_url);
   GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv,
                                       &pch->reserve_pub.eddsa_pub);
 
-  GNUNET_assert (GNUNET_YES ==
-                 TEAH_handle_is_ready (exchange));
   {
     char pub_str[sizeof (*purse_pub) * 2];
     char *end;
@@ -352,7 +348,7 @@ TALER_EXCHANGE_account_merge (
     *end = '\0';
     GNUNET_snprintf (arg_str,
                      sizeof (arg_str),
-                     "/purses/%s/merge",
+                     "purses/%s/merge",
                      pub_str);
   }
   reserve_url = TALER_reserve_make_payto (pch->provider_url,
@@ -364,8 +360,9 @@ TALER_EXCHANGE_account_merge (
     GNUNET_free (pch);
     return NULL;
   }
-  pch->url = TEAH_path_to_url (exchange,
-                               arg_str);
+  pch->url = TALER_url_join (url,
+                             arg_str,
+                             NULL);
   if (NULL == pch->url)
   {
     GNUNET_break (0);
@@ -426,7 +423,7 @@ TALER_EXCHANGE_account_merge (
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "URL for purse merge: `%s'\n",
               pch->url);
-  ctx = TEAH_handle_to_context (exchange);
+  pch->keys = TALER_EXCHANGE_keys_incref (keys);
   pch->job = GNUNET_CURL_job_add2 (ctx,
                                    eh,
                                    pch->ctx.headers,
@@ -448,6 +445,7 @@ TALER_EXCHANGE_account_merge_cancel (
   GNUNET_free (pch->url);
   GNUNET_free (pch->provider_url);
   TALER_curl_easy_post_finished (&pch->ctx);
+  TALER_EXCHANGE_keys_decref (pch->keys);
   GNUNET_free (pch);
 }
 
diff --git a/src/lib/exchange_api_purses_get.c 
b/src/lib/exchange_api_purses_get.c
index 4c2fdd79..7a6b2707 100644
--- a/src/lib/exchange_api_purses_get.c
+++ b/src/lib/exchange_api_purses_get.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2022 Taler Systems SA
+  Copyright (C) 2022-2023 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU General Public License as published by the Free Software
@@ -39,9 +39,9 @@ struct TALER_EXCHANGE_PurseGetHandle
 {
 
   /**
-   * The connection to exchange this request handle will use
+   * The keys of the exchange this request handle will use
    */
-  struct TALER_EXCHANGE_Handle *exchange;
+  struct TALER_EXCHANGE_Keys *keys;
 
   /**
    * The url for this request.
@@ -117,7 +117,6 @@ handle_purse_get_finished (void *cls,
                                      &exchange_sig),
         GNUNET_JSON_spec_end ()
       };
-      const struct TALER_EXCHANGE_Keys *key_state;
 
       if (GNUNET_OK !=
           GNUNET_JSON_parse (j,
@@ -130,9 +129,8 @@ handle_purse_get_finished (void *cls,
         break;
       }
 
-      key_state = TALER_EXCHANGE_get_keys (pgh->exchange);
       if (GNUNET_OK !=
-          TALER_EXCHANGE_test_signing_key (key_state,
+          TALER_EXCHANGE_test_signing_key (pgh->keys,
                                            &exchange_pub))
       {
         GNUNET_break_op (0);
@@ -207,7 +205,9 @@ handle_purse_get_finished (void *cls,
 
 struct TALER_EXCHANGE_PurseGetHandle *
 TALER_EXCHANGE_purse_get (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
   const struct TALER_PurseContractPublicKeyP *purse_pub,
   struct GNUNET_TIME_Relative timeout,
   bool wait_for_merge,
@@ -218,14 +218,7 @@ TALER_EXCHANGE_purse_get (
   CURL *eh;
   char arg_str[sizeof (*purse_pub) * 2 + 64];
 
-  if (GNUNET_YES !=
-      TEAH_handle_is_ready (exchange))
-  {
-    GNUNET_break (0);
-    return NULL;
-  }
   pgh = GNUNET_new (struct TALER_EXCHANGE_PurseGetHandle);
-  pgh->exchange = exchange;
   pgh->cb = cb;
   pgh->cb_cls = cb_cls;
   {
@@ -247,19 +240,20 @@ TALER_EXCHANGE_purse_get (
     if (GNUNET_TIME_relative_is_zero (timeout))
       GNUNET_snprintf (arg_str,
                        sizeof (arg_str),
-                       "/purses/%s/%s",
+                       "purses/%s/%s",
                        cpub_str,
                        wait_for_merge ? "merge" : "deposit");
     else
       GNUNET_snprintf (arg_str,
                        sizeof (arg_str),
-                       "/purses/%s/%s?timeout_ms=%s",
+                       "purses/%s/%s?timeout_ms=%s",
                        cpub_str,
                        wait_for_merge ? "merge" : "deposit",
                        timeout_str);
   }
-  pgh->url = TEAH_path_to_url (exchange,
-                               arg_str);
+  pgh->url = TALER_url_join (url,
+                             arg_str,
+                             NULL);
   if (NULL == pgh->url)
   {
     GNUNET_free (pgh);
@@ -273,10 +267,11 @@ TALER_EXCHANGE_purse_get (
     GNUNET_free (pgh);
     return NULL;
   }
-  pgh->job = GNUNET_CURL_job_add (TEAH_handle_to_context (exchange),
+  pgh->job = GNUNET_CURL_job_add (ctx,
                                   eh,
                                   &handle_purse_get_finished,
                                   pgh);
+  pgh->keys = TALER_EXCHANGE_keys_incref (keys);
   return pgh;
 }
 
@@ -291,6 +286,7 @@ TALER_EXCHANGE_purse_get_cancel (
     pgh->job = NULL;
   }
   GNUNET_free (pgh->url);
+  TALER_EXCHANGE_keys_decref (pgh->keys);
   GNUNET_free (pgh);
 }
 
diff --git a/src/lib/exchange_api_recoup.c b/src/lib/exchange_api_recoup.c
index b89bda8b..e7daff16 100644
--- a/src/lib/exchange_api_recoup.c
+++ b/src/lib/exchange_api_recoup.c
@@ -40,9 +40,9 @@ struct TALER_EXCHANGE_RecoupHandle
 {
 
   /**
-   * The connection to exchange this request handle will use
+   * The keys of the exchange this request handle will use
    */
-  struct TALER_EXCHANGE_Handle *exchange;
+  struct TALER_EXCHANGE_Keys *keys;
 
   /**
    * The url for this request.
@@ -143,10 +143,8 @@ handle_recoup_finished (void *cls,
     .hr.reply = j,
     .hr.http_status = (unsigned int) response_code
   };
-  const struct TALER_EXCHANGE_Keys *keys;
 
   ph->job = NULL;
-  keys = TALER_EXCHANGE_get_keys (ph->exchange);
   switch (response_code)
   {
   case 0:
@@ -177,7 +175,7 @@ handle_recoup_finished (void *cls,
       rr.hr.ec = TALER_JSON_get_error_code (j);
       rr.hr.hint = TALER_JSON_get_error_hint (j);
       if (GNUNET_OK !=
-          TALER_EXCHANGE_get_min_denomination_ (keys,
+          TALER_EXCHANGE_get_min_denomination_ (ph->keys,
                                                 &min_key))
       {
         GNUNET_break (0);
@@ -187,7 +185,7 @@ handle_recoup_finished (void *cls,
       }
       if (GNUNET_OK !=
           TALER_EXCHANGE_check_coin_conflict_ (
-            keys,
+            ph->keys,
             j,
             &ph->pk,
             &ph->coin_pub,
@@ -244,16 +242,18 @@ handle_recoup_finished (void *cls,
 
 
 struct TALER_EXCHANGE_RecoupHandle *
-TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,
-                       const struct TALER_EXCHANGE_DenomPublicKey *pk,
-                       const struct TALER_DenominationSignature *denom_sig,
-                       const struct TALER_ExchangeWithdrawValues 
*exchange_vals,
-                       const struct TALER_PlanchetMasterSecretP *ps,
-                       TALER_EXCHANGE_RecoupResultCallback recoup_cb,
-                       void *recoup_cb_cls)
+TALER_EXCHANGE_recoup (
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
+  const struct TALER_EXCHANGE_DenomPublicKey *pk,
+  const struct TALER_DenominationSignature *denom_sig,
+  const struct TALER_ExchangeWithdrawValues *exchange_vals,
+  const struct TALER_PlanchetMasterSecretP *ps,
+  TALER_EXCHANGE_RecoupResultCallback recoup_cb,
+  void *recoup_cb_cls)
 {
   struct TALER_EXCHANGE_RecoupHandle *ph;
-  struct GNUNET_CURL_Context *ctx;
   struct TALER_DenominationHashP h_denom_pub;
   json_t *recoup_obj;
   CURL *eh;
@@ -261,8 +261,6 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle 
*exchange,
   struct TALER_CoinSpendPrivateKeyP coin_priv;
   union TALER_DenominationBlindingKeyP bks;
 
-  GNUNET_assert (GNUNET_YES ==
-                 TEAH_handle_is_ready (exchange));
   ph = GNUNET_new (struct TALER_EXCHANGE_RecoupHandle);
   TALER_planchet_setup_coin_priv (ps,
                                   exchange_vals,
@@ -319,19 +317,19 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle 
*exchange,
     *end = '\0';
     GNUNET_snprintf (arg_str,
                      sizeof (arg_str),
-                     "/coins/%s/recoup",
+                     "coins/%s/recoup",
                      pub_str);
   }
 
-  ph->exchange = exchange;
   ph->pk = *pk;
   memset (&ph->pk.key,
           0,
           sizeof (ph->pk.key)); /* zero out, as lifetime cannot be warranted */
   ph->cb = recoup_cb;
   ph->cb_cls = recoup_cb_cls;
-  ph->url = TEAH_path_to_url (exchange,
-                              arg_str);
+  ph->url = TALER_url_join (url,
+                            arg_str,
+                            NULL);
   if (NULL == ph->url)
   {
     json_decref (recoup_obj);
@@ -357,7 +355,7 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle 
*exchange,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "URL for recoup: `%s'\n",
               ph->url);
-  ctx = TEAH_handle_to_context (exchange);
+  ph->keys = TALER_EXCHANGE_keys_incref (keys);
   ph->job = GNUNET_CURL_job_add2 (ctx,
                                   eh,
                                   ph->ctx.headers,
@@ -377,6 +375,7 @@ TALER_EXCHANGE_recoup_cancel (struct 
TALER_EXCHANGE_RecoupHandle *ph)
   }
   GNUNET_free (ph->url);
   TALER_curl_easy_post_finished (&ph->ctx);
+  TALER_EXCHANGE_keys_decref (ph->keys);
   GNUNET_free (ph);
 }
 
diff --git a/src/lib/exchange_api_recoup_refresh.c 
b/src/lib/exchange_api_recoup_refresh.c
index 7b42aa7e..f5745deb 100644
--- a/src/lib/exchange_api_recoup_refresh.c
+++ b/src/lib/exchange_api_recoup_refresh.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2017-2022 Taler Systems SA
+  Copyright (C) 2017-2023 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU General Public License as published by the Free Software
@@ -40,9 +40,9 @@ struct TALER_EXCHANGE_RecoupRefreshHandle
 {
 
   /**
-   * The connection to exchange this request handle will use
+   * The keys of the exchange this request handle will use
    */
-  struct TALER_EXCHANGE_Handle *exchange;
+  struct TALER_EXCHANGE_Keys *keys;
 
   /**
    * The url for this request.
@@ -144,10 +144,8 @@ handle_recoup_refresh_finished (void *cls,
     .hr.reply = j,
     .hr.http_status = (unsigned int) response_code
   };
-  const struct TALER_EXCHANGE_Keys *keys;
 
   ph->job = NULL;
-  keys = TALER_EXCHANGE_get_keys (ph->exchange);
   switch (response_code)
   {
   case 0:
@@ -191,7 +189,7 @@ handle_recoup_refresh_finished (void *cls,
       rrr.hr.ec = TALER_JSON_get_error_code (j);
       rrr.hr.hint = TALER_JSON_get_error_hint (j);
       if (GNUNET_OK !=
-          TALER_EXCHANGE_get_min_denomination_ (keys,
+          TALER_EXCHANGE_get_min_denomination_ (ph->keys,
                                                 &min_key))
       {
         GNUNET_break (0);
@@ -201,7 +199,7 @@ handle_recoup_refresh_finished (void *cls,
       }
       if (GNUNET_OK !=
           TALER_EXCHANGE_check_coin_conflict_ (
-            keys,
+            ph->keys,
             j,
             &ph->pk,
             &ph->coin_pub,
@@ -246,7 +244,9 @@ handle_recoup_refresh_finished (void *cls,
 
 struct TALER_EXCHANGE_RecoupRefreshHandle *
 TALER_EXCHANGE_recoup_refresh (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
   const struct TALER_EXCHANGE_DenomPublicKey *pk,
   const struct TALER_DenominationSignature *denom_sig,
   const struct TALER_ExchangeWithdrawValues *exchange_vals,
@@ -257,7 +257,6 @@ TALER_EXCHANGE_recoup_refresh (
   void *recoup_cb_cls)
 {
   struct TALER_EXCHANGE_RecoupRefreshHandle *ph;
-  struct GNUNET_CURL_Context *ctx;
   struct TALER_DenominationHashP h_denom_pub;
   json_t *recoup_obj;
   CURL *eh;
@@ -266,10 +265,7 @@ TALER_EXCHANGE_recoup_refresh (
   union TALER_DenominationBlindingKeyP bks;
 
   GNUNET_assert (NULL != recoup_cb);
-  GNUNET_assert (GNUNET_YES ==
-                 TEAH_handle_is_ready (exchange));
   ph = GNUNET_new (struct TALER_EXCHANGE_RecoupRefreshHandle);
-  ph->exchange = exchange;
   ph->pk = *pk;
   memset (&ph->pk.key,
           0,
@@ -333,12 +329,13 @@ TALER_EXCHANGE_recoup_refresh (
     *end = '\0';
     GNUNET_snprintf (arg_str,
                      sizeof (arg_str),
-                     "/coins/%s/recoup-refresh",
+                     "coins/%s/recoup-refresh",
                      pub_str);
   }
 
-  ph->url = TEAH_path_to_url (exchange,
-                              arg_str);
+  ph->url = TALER_url_join (url,
+                            arg_str,
+                            NULL);
   if (NULL == ph->url)
   {
     json_decref (recoup_obj);
@@ -364,7 +361,7 @@ TALER_EXCHANGE_recoup_refresh (
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "URL for recoup-refresh: `%s'\n",
               ph->url);
-  ctx = TEAH_handle_to_context (exchange);
+  ph->keys = TALER_EXCHANGE_keys_incref (keys);
   ph->job = GNUNET_CURL_job_add2 (ctx,
                                   eh,
                                   ph->ctx.headers,
@@ -385,6 +382,7 @@ TALER_EXCHANGE_recoup_refresh_cancel (
   }
   GNUNET_free (ph->url);
   TALER_curl_easy_post_finished (&ph->ctx);
+  TALER_EXCHANGE_keys_decref (ph->keys);
   GNUNET_free (ph);
 }
 
diff --git a/src/lib/exchange_api_refreshes_reveal.c 
b/src/lib/exchange_api_refreshes_reveal.c
index 50de7681..9b6f9b19 100644
--- a/src/lib/exchange_api_refreshes_reveal.c
+++ b/src/lib/exchange_api_refreshes_reveal.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2015-2022 Taler Systems SA
+  Copyright (C) 2015-2023 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU General Public License as published by the Free Software
@@ -39,11 +39,6 @@
 struct TALER_EXCHANGE_RefreshesRevealHandle
 {
 
-  /**
-   * The connection to exchange this request handle will use
-   */
-  struct TALER_EXCHANGE_Handle *exchange;
-
   /**
    * The url for this request.
    */
@@ -310,7 +305,8 @@ handle_refresh_reveal_finished (void *cls,
 
 struct TALER_EXCHANGE_RefreshesRevealHandle *
 TALER_EXCHANGE_refreshes_reveal (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
   const struct TALER_RefreshMasterSecretP *rms,
   const struct TALER_EXCHANGE_RefreshData *rd,
   unsigned int num_coins,
@@ -327,7 +323,6 @@ TALER_EXCHANGE_refreshes_reveal (
   json_t *link_sigs;
   json_t *old_age_commitment = NULL;
   CURL *eh;
-  struct GNUNET_CURL_Context *ctx;
   struct MeltData md;
   char arg_str[sizeof (struct TALER_RefreshCommitmentP) * 2 + 32];
   bool send_rms = false;
@@ -342,12 +337,6 @@ TALER_EXCHANGE_refreshes_reveal (
     GNUNET_break (0);
     return NULL;
   }
-  if (GNUNET_YES !=
-      TEAH_handle_is_ready (exchange))
-  {
-    GNUNET_break (0);
-    return NULL;
-  }
   if (GNUNET_OK !=
       TALER_EXCHANGE_get_melt_data_ (rms,
                                      rd,
@@ -467,22 +456,22 @@ TALER_EXCHANGE_refreshes_reveal (
     *end = '\0';
     GNUNET_snprintf (arg_str,
                      sizeof (arg_str),
-                     "/refreshes/%s/reveal",
+                     "refreshes/%s/reveal",
                      pub_str);
   }
   /* finally, we can actually issue the request */
   rrh = GNUNET_new (struct TALER_EXCHANGE_RefreshesRevealHandle);
-  rrh->exchange = exchange;
   rrh->noreveal_index = noreveal_index;
   rrh->reveal_cb = reveal_cb;
   rrh->reveal_cb_cls = reveal_cb_cls;
   rrh->md = md;
-  rrh->alg_values = GNUNET_memdup (alg_values,
-                                   md.num_fresh_coins
-                                   * sizeof (struct
-                                             TALER_ExchangeWithdrawValues));
-  rrh->url = TEAH_path_to_url (rrh->exchange,
-                               arg_str);
+  rrh->alg_values
+    = GNUNET_memdup (alg_values,
+                     md.num_fresh_coins
+                     * sizeof (struct TALER_ExchangeWithdrawValues));
+  rrh->url = TALER_url_join (url,
+                             arg_str,
+                             NULL);
   if (NULL == rrh->url)
   {
     json_decref (reveal_obj);
@@ -510,7 +499,6 @@ TALER_EXCHANGE_refreshes_reveal (
     return NULL;
   }
   json_decref (reveal_obj);
-  ctx = TEAH_handle_to_context (rrh->exchange);
   rrh->job = GNUNET_CURL_job_add2 (ctx,
                                    eh,
                                    rrh->ctx.headers,
diff --git a/src/lib/exchange_api_refund.c b/src/lib/exchange_api_refund.c
index 35524ca4..83f9612d 100644
--- a/src/lib/exchange_api_refund.c
+++ b/src/lib/exchange_api_refund.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014-2022 Taler Systems SA
+  Copyright (C) 2014-2023 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU General Public License as published by the Free Software
@@ -39,9 +39,9 @@ struct TALER_EXCHANGE_RefundHandle
 {
 
   /**
-   * The connection to exchange this request handle will use
+   * The keys of the exchange this request handle will use
    */
-  struct TALER_EXCHANGE_Handle *exchange;
+  struct TALER_EXCHANGE_Keys *keys;
 
   /**
    * The url for this request.
@@ -117,7 +117,6 @@ verify_refund_signature_ok (struct 
TALER_EXCHANGE_RefundHandle *rh,
                             struct TALER_ExchangePublicKeyP *exchange_pub,
                             struct TALER_ExchangeSignatureP *exchange_sig)
 {
-  const struct TALER_EXCHANGE_Keys *key_state;
   struct GNUNET_JSON_Specification spec[] = {
     GNUNET_JSON_spec_fixed_auto ("exchange_sig",
                                  exchange_sig),
@@ -134,9 +133,8 @@ verify_refund_signature_ok (struct 
TALER_EXCHANGE_RefundHandle *rh,
     GNUNET_break_op (0);
     return GNUNET_SYSERR;
   }
-  key_state = TALER_EXCHANGE_get_keys (rh->exchange);
   if (GNUNET_OK !=
-      TALER_EXCHANGE_test_signing_key (key_state,
+      TALER_EXCHANGE_test_signing_key (rh->keys,
                                        exchange_pub))
   {
     GNUNET_break_op (0);
@@ -672,7 +670,9 @@ handle_refund_finished (void *cls,
 
 struct TALER_EXCHANGE_RefundHandle *
 TALER_EXCHANGE_refund (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
   const struct TALER_Amount *amount,
   const struct TALER_PrivateContractHashP *h_contract_terms,
   const struct TALER_CoinSpendPublicKeyP *coin_pub,
@@ -684,13 +684,10 @@ TALER_EXCHANGE_refund (
   struct TALER_MerchantPublicKeyP merchant_pub;
   struct TALER_MerchantSignatureP merchant_sig;
   struct TALER_EXCHANGE_RefundHandle *rh;
-  struct GNUNET_CURL_Context *ctx;
   json_t *refund_obj;
   CURL *eh;
   char arg_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2 + 32];
 
-  GNUNET_assert (GNUNET_YES ==
-                 TEAH_handle_is_ready (exchange));
   GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv->eddsa_priv,
                                       &merchant_pub.eddsa_pub);
   TALER_merchant_refund_sign (coin_pub,
@@ -711,7 +708,7 @@ TALER_EXCHANGE_refund (
     *end = '\0';
     GNUNET_snprintf (arg_str,
                      sizeof (arg_str),
-                     "/coins/%s/refund",
+                     "coins/%s/refund",
                      pub_str);
   }
   refund_obj = GNUNET_JSON_PACK (
@@ -726,11 +723,11 @@ TALER_EXCHANGE_refund (
     GNUNET_JSON_pack_data_auto ("merchant_sig",
                                 &merchant_sig));
   rh = GNUNET_new (struct TALER_EXCHANGE_RefundHandle);
-  rh->exchange = exchange;
   rh->cb = cb;
   rh->cb_cls = cb_cls;
-  rh->url = TEAH_path_to_url (exchange,
-                              arg_str);
+  rh->url = TALER_url_join (url,
+                            arg_str,
+                            NULL);
   if (NULL == rh->url)
   {
     json_decref (refund_obj);
@@ -761,7 +758,7 @@ TALER_EXCHANGE_refund (
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "URL for refund: `%s'\n",
               rh->url);
-  ctx = TEAH_handle_to_context (exchange);
+  rh->keys = TALER_EXCHANGE_keys_incref (keys);
   rh->job = GNUNET_CURL_job_add2 (ctx,
                                   eh,
                                   rh->ctx.headers,
@@ -781,6 +778,7 @@ TALER_EXCHANGE_refund_cancel (struct 
TALER_EXCHANGE_RefundHandle *refund)
   }
   GNUNET_free (refund->url);
   TALER_curl_easy_post_finished (&refund->ctx);
+  TALER_EXCHANGE_keys_decref (refund->keys);
   GNUNET_free (refund);
 }
 
diff --git a/src/lib/exchange_api_reserves_close.c 
b/src/lib/exchange_api_reserves_close.c
index 278d1310..a3769a22 100644
--- a/src/lib/exchange_api_reserves_close.c
+++ b/src/lib/exchange_api_reserves_close.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014-2022 Taler Systems SA
+  Copyright (C) 2014-2023 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU General Public License as published by the Free Software
@@ -38,11 +38,6 @@
 struct TALER_EXCHANGE_ReservesCloseHandle
 {
 
-  /**
-   * The connection to exchange this request handle will use
-   */
-  struct TALER_EXCHANGE_Handle *exchange;
-
   /**
    * The url for this request.
    */
@@ -269,26 +264,19 @@ handle_reserves_close_finished (void *cls,
 
 struct TALER_EXCHANGE_ReservesCloseHandle *
 TALER_EXCHANGE_reserves_close (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
   const struct TALER_ReservePrivateKeyP *reserve_priv,
   const char *target_payto_uri,
   TALER_EXCHANGE_ReservesCloseCallback cb,
   void *cb_cls)
 {
   struct TALER_EXCHANGE_ReservesCloseHandle *rch;
-  struct GNUNET_CURL_Context *ctx;
   CURL *eh;
   char arg_str[sizeof (struct TALER_ReservePublicKeyP) * 2 + 32];
   struct TALER_PaytoHashP h_payto;
 
-  if (GNUNET_YES !=
-      TEAH_handle_is_ready (exchange))
-  {
-    GNUNET_break (0);
-    return NULL;
-  }
   rch = GNUNET_new (struct TALER_EXCHANGE_ReservesCloseHandle);
-  rch->exchange = exchange;
   rch->cb = cb;
   rch->cb_cls = cb_cls;
   rch->ts = GNUNET_TIME_timestamp_get ();
@@ -306,11 +294,12 @@ TALER_EXCHANGE_reserves_close (
     *end = '\0';
     GNUNET_snprintf (arg_str,
                      sizeof (arg_str),
-                     "/reserves/%s/close",
+                     "reserves/%s/close",
                      pub_str);
   }
-  rch->url = TEAH_path_to_url (exchange,
-                               arg_str);
+  rch->url = TALER_url_join (url,
+                             arg_str,
+                             NULL);
   if (NULL == rch->url)
   {
     GNUNET_free (rch);
@@ -357,7 +346,6 @@ TALER_EXCHANGE_reserves_close (
     }
     json_decref (close_obj);
   }
-  ctx = TEAH_handle_to_context (exchange);
   rch->job = GNUNET_CURL_job_add2 (ctx,
                                    eh,
                                    rch->post_ctx.headers,
diff --git a/src/lib/exchange_api_reserves_history.c 
b/src/lib/exchange_api_reserves_history.c
index ccc11a27..a48e0c08 100644
--- a/src/lib/exchange_api_reserves_history.c
+++ b/src/lib/exchange_api_reserves_history.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014-2022 Taler Systems SA
+  Copyright (C) 2014-2023 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU General Public License as published by the Free Software
@@ -39,9 +39,9 @@ struct TALER_EXCHANGE_ReservesHistoryHandle
 {
 
   /**
-   * The connection to exchange this request handle will use
+   * The keys of the exchange this request handle will use
    */
-  struct TALER_EXCHANGE_Handle *exchange;
+  struct TALER_EXCHANGE_Keys *keys;
 
   /**
    * The url for this request.
@@ -131,7 +131,7 @@ handle_reserves_history_ok (struct 
TALER_EXCHANGE_ReservesHistoryHandle *rsh,
     rhistory = GNUNET_new_array (len,
                                  struct TALER_EXCHANGE_ReserveHistoryEntry);
     if (GNUNET_OK !=
-        TALER_EXCHANGE_parse_reserve_history (rsh->exchange,
+        TALER_EXCHANGE_parse_reserve_history (rsh->keys,
                                               history,
                                               &rsh->reserve_pub,
                                               rs.details.ok.balance.currency,
@@ -250,26 +250,19 @@ handle_reserves_history_finished (void *cls,
 
 struct TALER_EXCHANGE_ReservesHistoryHandle *
 TALER_EXCHANGE_reserves_history (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
   const struct TALER_ReservePrivateKeyP *reserve_priv,
   TALER_EXCHANGE_ReservesHistoryCallback cb,
   void *cb_cls)
 {
   struct TALER_EXCHANGE_ReservesHistoryHandle *rsh;
-  struct GNUNET_CURL_Context *ctx;
   CURL *eh;
   char arg_str[sizeof (struct TALER_ReservePublicKeyP) * 2 + 32];
-  const struct TALER_EXCHANGE_Keys *keys;
   const struct TALER_EXCHANGE_GlobalFee *gf;
 
-  if (GNUNET_YES !=
-      TEAH_handle_is_ready (exchange))
-  {
-    GNUNET_break (0);
-    return NULL;
-  }
   rsh = GNUNET_new (struct TALER_EXCHANGE_ReservesHistoryHandle);
-  rsh->exchange = exchange;
   rsh->cb = cb;
   rsh->cb_cls = cb_cls;
   rsh->ts = GNUNET_TIME_timestamp_get ();
@@ -287,11 +280,12 @@ TALER_EXCHANGE_reserves_history (
     *end = '\0';
     GNUNET_snprintf (arg_str,
                      sizeof (arg_str),
-                     "/reserves/%s/history",
+                     "reserves/%s/history",
                      pub_str);
   }
-  rsh->url = TEAH_path_to_url (exchange,
-                               arg_str);
+  rsh->url = TALER_url_join (url,
+                             arg_str,
+                             NULL);
   if (NULL == rsh->url)
   {
     GNUNET_free (rsh);
@@ -305,15 +299,6 @@ TALER_EXCHANGE_reserves_history (
     GNUNET_free (rsh);
     return NULL;
   }
-  keys = TALER_EXCHANGE_get_keys (exchange);
-  if (NULL == keys)
-  {
-    GNUNET_break (0);
-    curl_easy_cleanup (eh);
-    GNUNET_free (rsh->url);
-    GNUNET_free (rsh);
-    return NULL;
-  }
   gf = TALER_EXCHANGE_get_global_fee (keys,
                                       rsh->ts);
   if (NULL == gf)
@@ -349,7 +334,7 @@ TALER_EXCHANGE_reserves_history (
     }
     json_decref (history_obj);
   }
-  ctx = TEAH_handle_to_context (exchange);
+  rsh->keys = TALER_EXCHANGE_keys_incref (keys);
   rsh->job = GNUNET_CURL_job_add2 (ctx,
                                    eh,
                                    rsh->post_ctx.headers,
@@ -370,6 +355,7 @@ TALER_EXCHANGE_reserves_history_cancel (
   }
   TALER_curl_easy_post_finished (&rsh->post_ctx);
   GNUNET_free (rsh->url);
+  TALER_EXCHANGE_keys_decref (rsh->keys);
   GNUNET_free (rsh);
 }
 
diff --git a/src/lib/exchange_api_reserves_open.c 
b/src/lib/exchange_api_reserves_open.c
index 2b7ef0d9..b28333d5 100644
--- a/src/lib/exchange_api_reserves_open.c
+++ b/src/lib/exchange_api_reserves_open.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014-2022 Taler Systems SA
+  Copyright (C) 2014-2023 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU General Public License as published by the Free Software
@@ -67,9 +67,9 @@ struct TALER_EXCHANGE_ReservesOpenHandle
 {
 
   /**
-   * The connection to exchange this request handle will use
+   * The keys of the exchange this request handle will use
    */
-  struct TALER_EXCHANGE_Handle *exchange;
+  struct TALER_EXCHANGE_Keys *keys;
 
   /**
    * The url for this request.
@@ -321,7 +321,6 @@ handle_reserves_open_finished (void *cls,
     break;
   case MHD_HTTP_CONFLICT:
     {
-      const struct TALER_EXCHANGE_Keys *keys;
       const struct CoinData *cd = NULL;
       struct TALER_CoinSpendPublicKeyP coin_pub;
       const struct TALER_EXCHANGE_DenomPublicKey *dk;
@@ -331,8 +330,6 @@ handle_reserves_open_finished (void *cls,
         GNUNET_JSON_spec_end ()
       };
 
-      keys = TALER_EXCHANGE_get_keys (roh->exchange);
-      GNUNET_assert (NULL != keys);
       if (GNUNET_OK !=
           GNUNET_JSON_parse (j,
                              spec,
@@ -362,7 +359,7 @@ handle_reserves_open_finished (void *cls,
         rs.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
         break;
       }
-      dk = TALER_EXCHANGE_get_denomination_key_by_hash (keys,
+      dk = TALER_EXCHANGE_get_denomination_key_by_hash (roh->keys,
                                                         &cd->h_denom_pub);
       if (NULL == dk)
       {
@@ -372,7 +369,7 @@ handle_reserves_open_finished (void *cls,
         break;
       }
       if (GNUNET_OK !=
-          TALER_EXCHANGE_check_coin_conflict_ (keys,
+          TALER_EXCHANGE_check_coin_conflict_ (roh->keys,
                                                j,
                                                dk,
                                                &coin_pub,
@@ -427,7 +424,9 @@ handle_reserves_open_finished (void *cls,
 
 struct TALER_EXCHANGE_ReservesOpenHandle *
 TALER_EXCHANGE_reserves_open (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
   const struct TALER_ReservePrivateKeyP *reserve_priv,
   const struct TALER_Amount *reserve_contribution,
   unsigned int coin_payments_length,
@@ -438,20 +437,11 @@ TALER_EXCHANGE_reserves_open (
   void *cb_cls)
 {
   struct TALER_EXCHANGE_ReservesOpenHandle *roh;
-  struct GNUNET_CURL_Context *ctx;
   CURL *eh;
   char arg_str[sizeof (struct TALER_ReservePublicKeyP) * 2 + 32];
-  const struct TALER_EXCHANGE_Keys *keys;
   json_t *cpa;
 
-  if (GNUNET_YES !=
-      TEAH_handle_is_ready (exchange))
-  {
-    GNUNET_break (0);
-    return NULL;
-  }
   roh = GNUNET_new (struct TALER_EXCHANGE_ReservesOpenHandle);
-  roh->exchange = exchange;
   roh->cb = cb;
   roh->cb_cls = cb_cls;
   roh->ts = GNUNET_TIME_timestamp_get ();
@@ -469,11 +459,12 @@ TALER_EXCHANGE_reserves_open (
     *end = '\0';
     GNUNET_snprintf (arg_str,
                      sizeof (arg_str),
-                     "/reserves/%s/open",
+                     "reserves/%s/open",
                      pub_str);
   }
-  roh->url = TEAH_path_to_url (exchange,
-                               arg_str);
+  roh->url = TALER_url_join (url,
+                             arg_str,
+                             NULL);
   if (NULL == roh->url)
   {
     GNUNET_free (roh);
@@ -487,15 +478,6 @@ TALER_EXCHANGE_reserves_open (
     GNUNET_free (roh);
     return NULL;
   }
-  keys = TALER_EXCHANGE_get_keys (exchange);
-  if (NULL == keys)
-  {
-    GNUNET_break (0);
-    curl_easy_cleanup (eh);
-    GNUNET_free (roh->url);
-    GNUNET_free (roh);
-    return NULL;
-  }
   TALER_wallet_reserve_open_sign (reserve_contribution,
                                   roh->ts,
                                   expiration_time,
@@ -578,7 +560,7 @@ TALER_EXCHANGE_reserves_open (
     }
     json_decref (open_obj);
   }
-  ctx = TEAH_handle_to_context (exchange);
+  roh->keys = TALER_EXCHANGE_keys_incref (keys);
   roh->job = GNUNET_CURL_job_add2 (ctx,
                                    eh,
                                    roh->post_ctx.headers,
@@ -600,6 +582,7 @@ TALER_EXCHANGE_reserves_open_cancel (
   TALER_curl_easy_post_finished (&roh->post_ctx);
   GNUNET_free (roh->coins);
   GNUNET_free (roh->url);
+  TALER_EXCHANGE_keys_decref (roh->keys);
   GNUNET_free (roh);
 }
 
diff --git a/src/lib/exchange_api_reserves_status.c 
b/src/lib/exchange_api_reserves_status.c
index 57fb0427..9f98b7f8 100644
--- a/src/lib/exchange_api_reserves_status.c
+++ b/src/lib/exchange_api_reserves_status.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014-2022 Taler Systems SA
+  Copyright (C) 2014-2023 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU General Public License as published by the Free Software
@@ -39,9 +39,9 @@ struct TALER_EXCHANGE_ReservesStatusHandle
 {
 
   /**
-   * The connection to exchange this request handle will use
+   * The keys of the exchange this request handle will use
    */
-  struct TALER_EXCHANGE_Handle *exchange;
+  struct TALER_EXCHANGE_Keys *keys;
 
   /**
    * The url for this request.
@@ -119,7 +119,7 @@ handle_reserves_status_ok (struct 
TALER_EXCHANGE_ReservesStatusHandle *rsh,
     rhistory = GNUNET_new_array (len,
                                  struct TALER_EXCHANGE_ReserveHistoryEntry);
     if (GNUNET_OK !=
-        TALER_EXCHANGE_parse_reserve_history (rsh->exchange,
+        TALER_EXCHANGE_parse_reserve_history (rsh->keys,
                                               history,
                                               &rsh->reserve_pub,
                                               rs.details.ok.balance.currency,
@@ -233,27 +233,21 @@ handle_reserves_status_finished (void *cls,
 
 struct TALER_EXCHANGE_ReservesStatusHandle *
 TALER_EXCHANGE_reserves_status (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
   const struct TALER_ReservePrivateKeyP *reserve_priv,
   TALER_EXCHANGE_ReservesStatusCallback cb,
   void *cb_cls)
 {
   struct TALER_EXCHANGE_ReservesStatusHandle *rsh;
-  struct GNUNET_CURL_Context *ctx;
   CURL *eh;
   char arg_str[sizeof (struct TALER_ReservePublicKeyP) * 2 + 32];
   struct TALER_ReserveSignatureP reserve_sig;
   struct GNUNET_TIME_Timestamp ts
     = GNUNET_TIME_timestamp_get ();
 
-  if (GNUNET_YES !=
-      TEAH_handle_is_ready (exchange))
-  {
-    GNUNET_break (0);
-    return NULL;
-  }
   rsh = GNUNET_new (struct TALER_EXCHANGE_ReservesStatusHandle);
-  rsh->exchange = exchange;
   rsh->cb = cb;
   rsh->cb_cls = cb_cls;
   GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv,
@@ -270,11 +264,12 @@ TALER_EXCHANGE_reserves_status (
     *end = '\0';
     GNUNET_snprintf (arg_str,
                      sizeof (arg_str),
-                     "/reserves/%s/status",
+                     "reserves/%s/status",
                      pub_str);
   }
-  rsh->url = TEAH_path_to_url (exchange,
-                               arg_str);
+  rsh->url = TALER_url_join (url,
+                             arg_str,
+                             NULL);
   if (NULL == rsh->url)
   {
     GNUNET_free (rsh);
@@ -312,7 +307,7 @@ TALER_EXCHANGE_reserves_status (
     }
     json_decref (status_obj);
   }
-  ctx = TEAH_handle_to_context (exchange);
+  rsh->keys = TALER_EXCHANGE_keys_incref (keys);
   rsh->job = GNUNET_CURL_job_add2 (ctx,
                                    eh,
                                    rsh->post_ctx.headers,
@@ -333,6 +328,7 @@ TALER_EXCHANGE_reserves_status_cancel (
   }
   TALER_curl_easy_post_finished (&rsh->post_ctx);
   GNUNET_free (rsh->url);
+  TALER_EXCHANGE_keys_decref (rsh->keys);
   GNUNET_free (rsh);
 }
 
diff --git a/src/lib/exchange_api_transfers_get.c 
b/src/lib/exchange_api_transfers_get.c
index 3a5a64fd..14cf51ff 100644
--- a/src/lib/exchange_api_transfers_get.c
+++ b/src/lib/exchange_api_transfers_get.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014-2021 Taler Systems SA
+  Copyright (C) 2014-2023 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU General Public License as published by the Free Software
@@ -38,9 +38,9 @@ struct TALER_EXCHANGE_TransfersGetHandle
 {
 
   /**
-   * The connection to exchange this request handle will use
+   * The keys of the exchange this request handle will use
    */
-  struct TALER_EXCHANGE_Handle *exchange;
+  struct TALER_EXCHANGE_Keys *keys;
 
   /**
    * The url for this request.
@@ -130,7 +130,7 @@ check_transfers_get_response_ok (
   }
   if (GNUNET_OK !=
       TALER_EXCHANGE_test_signing_key (
-        TALER_EXCHANGE_get_keys (wdh->exchange),
+        wdh->keys,
         &td->exchange_pub))
   {
     GNUNET_break_op (0);
@@ -320,25 +320,18 @@ handle_transfers_get_finished (void *cls,
 
 struct TALER_EXCHANGE_TransfersGetHandle *
 TALER_EXCHANGE_transfers_get (
-  struct TALER_EXCHANGE_Handle *exchange,
+  struct GNUNET_CURL_Context *ctx,
+  const char *url,
+  struct TALER_EXCHANGE_Keys *keys,
   const struct TALER_WireTransferIdentifierRawP *wtid,
   TALER_EXCHANGE_TransfersGetCallback cb,
   void *cb_cls)
 {
   struct TALER_EXCHANGE_TransfersGetHandle *wdh;
-  struct GNUNET_CURL_Context *ctx;
   CURL *eh;
   char arg_str[sizeof (struct TALER_WireTransferIdentifierRawP) * 2 + 32];
 
-  if (GNUNET_YES !=
-      TEAH_handle_is_ready (exchange))
-  {
-    GNUNET_break (0);
-    return NULL;
-  }
-
   wdh = GNUNET_new (struct TALER_EXCHANGE_TransfersGetHandle);
-  wdh->exchange = exchange;
   wdh->cb = cb;
   wdh->cb_cls = cb_cls;
 
@@ -354,11 +347,12 @@ TALER_EXCHANGE_transfers_get (
     *end = '\0';
     GNUNET_snprintf (arg_str,
                      sizeof (arg_str),
-                     "/transfers/%s",
+                     "transfers/%s",
                      wtid_str);
   }
-  wdh->url = TEAH_path_to_url (wdh->exchange,
-                               arg_str);
+  wdh->url = TALER_url_join (url,
+                             arg_str,
+                             NULL);
   if (NULL == wdh->url)
   {
     GNUNET_free (wdh);
@@ -372,7 +366,7 @@ TALER_EXCHANGE_transfers_get (
     GNUNET_free (wdh);
     return NULL;
   }
-  ctx = TEAH_handle_to_context (exchange);
+  wdh->keys = TALER_EXCHANGE_keys_incref (keys);
   wdh->job = GNUNET_CURL_job_add_with_ct_json (ctx,
                                                eh,
                                                &handle_transfers_get_finished,
@@ -397,6 +391,7 @@ TALER_EXCHANGE_transfers_get_cancel (
     wdh->job = NULL;
   }
   GNUNET_free (wdh->url);
+  TALER_EXCHANGE_keys_decref (wdh->keys);
   GNUNET_free (wdh);
 }
 
diff --git a/src/lib/exchange_api_withdraw2.c b/src/lib/exchange_api_withdraw2.c
index bf2bd023..daac429c 100644
--- a/src/lib/exchange_api_withdraw2.c
+++ b/src/lib/exchange_api_withdraw2.c
@@ -192,7 +192,8 @@ reserve_withdraw_payment_required (
     }
 
     if (GNUNET_OK !=
-        TALER_EXCHANGE_parse_reserve_history (wh->exchange,
+        TALER_EXCHANGE_parse_reserve_history (TALER_EXCHANGE_get_keys (
+                                                wh->exchange),
                                               history,
                                               &wh->reserve_pub,
                                               balance.currency,
diff --git a/src/testing/testing_api_cmd_deposits_get.c 
b/src/testing/testing_api_cmd_deposits_get.c
index 972a85b7..165af9b1 100644
--- a/src/testing/testing_api_cmd_deposits_get.c
+++ b/src/testing/testing_api_cmd_deposits_get.c
@@ -198,12 +198,8 @@ track_transaction_run (void *cls,
   struct TALER_MerchantWireHashP h_wire_details;
   struct TALER_PrivateContractHashP h_contract_terms;
   const struct TALER_MerchantPrivateKeyP *merchant_priv;
-  struct TALER_EXCHANGE_Handle *exchange
-    = TALER_TESTING_get_exchange (is);
 
   tts->cmd = cmd;
-  if (NULL == exchange)
-    return;
   tts->is = is;
   transaction_cmd
     = TALER_TESTING_interpreter_lookup_command (tts->is,
@@ -275,14 +271,17 @@ track_transaction_run (void *cls,
     return;
   }
 
-  tts->tth = TALER_EXCHANGE_deposits_get (exchange,
-                                          merchant_priv,
-                                          &h_wire_details,
-                                          &h_contract_terms,
-                                          &coin_pub,
-                                          GNUNET_TIME_UNIT_ZERO,
-                                          &deposit_wtid_cb,
-                                          tts);
+  tts->tth = TALER_EXCHANGE_deposits_get (
+    TALER_TESTING_interpreter_get_context (is),
+    TALER_TESTING_get_exchange_url (is),
+    TALER_TESTING_get_keys (is),
+    merchant_priv,
+    &h_wire_details,
+    &h_contract_terms,
+    &coin_pub,
+    GNUNET_TIME_UNIT_ZERO,
+    &deposit_wtid_cb,
+    tts);
   GNUNET_assert (NULL != tts->tth);
 }
 
diff --git a/src/testing/testing_api_cmd_purse_create_deposit.c 
b/src/testing/testing_api_cmd_purse_create_deposit.c
index 2f13849d..36dbfbff 100644
--- a/src/testing/testing_api_cmd_purse_create_deposit.c
+++ b/src/testing/testing_api_cmd_purse_create_deposit.c
@@ -189,12 +189,8 @@ deposit_run (void *cls,
 {
   struct PurseCreateDepositState *ds = cls;
   struct TALER_EXCHANGE_PurseDeposit deposits[ds->num_coin_references];
-  struct TALER_EXCHANGE_Handle *exchange
-    = TALER_TESTING_get_exchange (is);
 
   (void) cmd;
-  if (NULL == exchange)
-    return;
   ds->is = is;
   for (unsigned int i = 0; i<ds->num_coin_references; i++)
   {
@@ -259,7 +255,9 @@ deposit_run (void *cls,
                    "pay_deadline",
                    GNUNET_JSON_from_timestamp (ds->purse_expiration)));
   ds->dh = TALER_EXCHANGE_purse_create_with_deposit (
-    exchange,
+    TALER_TESTING_interpreter_get_context (is),
+    TALER_TESTING_get_exchange_url (is),
+    TALER_TESTING_get_keys (is),
     &ds->purse_priv,
     &ds->merge_priv,
     &ds->contract_priv,
diff --git a/src/testing/testing_api_cmd_purse_deposit.c 
b/src/testing/testing_api_cmd_purse_deposit.c
index fb1d5155..8bddc53a 100644
--- a/src/testing/testing_api_cmd_purse_deposit.c
+++ b/src/testing/testing_api_cmd_purse_deposit.c
@@ -259,11 +259,7 @@ deposit_run (void *cls,
   struct TALER_EXCHANGE_PurseDeposit deposits[ds->num_coin_references];
   const struct TALER_PurseContractPublicKeyP *purse_pub;
   const struct TALER_TESTING_Command *purse_cmd;
-  struct TALER_EXCHANGE_Handle *exchange
-    = TALER_TESTING_get_exchange (is);
 
-  if (NULL == exchange)
-    return;
   (void) cmd;
   ds->is = is;
   purse_cmd = TALER_TESTING_interpreter_lookup_command (is,
@@ -321,7 +317,9 @@ deposit_run (void *cls,
   }
 
   ds->dh = TALER_EXCHANGE_purse_deposit (
-    exchange,
+    TALER_TESTING_interpreter_get_context (is),
+    TALER_TESTING_get_exchange_url (is),
+    TALER_TESTING_get_keys (is),
     NULL, /* FIXME #7271: WADs support: purse exchange URL */
     &ds->purse_pub,
     ds->min_age,
diff --git a/src/testing/testing_api_cmd_purse_get.c 
b/src/testing/testing_api_cmd_purse_get.c
index 235ae63c..d5246660 100644
--- a/src/testing/testing_api_cmd_purse_get.c
+++ b/src/testing/testing_api_cmd_purse_get.c
@@ -183,11 +183,7 @@ status_run (void *cls,
 {
   struct StatusState *ss = cls;
   const struct TALER_TESTING_Command *create_purse;
-  struct TALER_EXCHANGE_Handle *exchange
-    = TALER_TESTING_get_exchange (is);
 
-  if (NULL == exchange)
-    return;
   ss->is = is;
   create_purse
     = TALER_TESTING_interpreter_lookup_command (is,
@@ -202,12 +198,15 @@ status_run (void *cls,
     TALER_TESTING_interpreter_fail (is);
     return;
   }
-  ss->pgh = TALER_EXCHANGE_purse_get (exchange,
-                                      ss->purse_pub,
-                                      ss->timeout,
-                                      ss->wait_for_merge,
-                                      &purse_status_cb,
-                                      ss);
+  ss->pgh = TALER_EXCHANGE_purse_get (
+    TALER_TESTING_interpreter_get_context (is),
+    TALER_TESTING_get_exchange_url (is),
+    TALER_TESTING_get_keys (is),
+    ss->purse_pub,
+    ss->timeout,
+    ss->wait_for_merge,
+    &purse_status_cb,
+    ss);
   if (! GNUNET_TIME_relative_is_zero (ss->timeout))
   {
     TALER_TESTING_interpreter_next (is);
diff --git a/src/testing/testing_api_cmd_purse_merge.c 
b/src/testing/testing_api_cmd_purse_merge.c
index 8f4f6b3c..503ef162 100644
--- a/src/testing/testing_api_cmd_purse_merge.c
+++ b/src/testing/testing_api_cmd_purse_merge.c
@@ -201,12 +201,8 @@ merge_run (void *cls,
   const struct TALER_PurseMergePrivateKeyP *merge_priv;
   const json_t *ct;
   const struct TALER_TESTING_Command *ref;
-  struct TALER_EXCHANGE_Handle *exchange
-    = TALER_TESTING_get_exchange (is);
 
   (void) cmd;
-  if (NULL == exchange)
-    return;
   ds->is = is;
   ref = TALER_TESTING_interpreter_lookup_command (ds->is,
                                                   ds->merge_ref);
@@ -322,7 +318,9 @@ merge_run (void *cls,
                                       &ds->merge_pub.eddsa_pub);
   ds->merge_timestamp = GNUNET_TIME_timestamp_get ();
   ds->dh = TALER_EXCHANGE_account_merge (
-    exchange,
+    TALER_TESTING_interpreter_get_context (is),
+    TALER_TESTING_get_exchange_url (is),
+    TALER_TESTING_get_keys (is),
     NULL, /* no wad */
     &ds->reserve_priv,
     &ds->purse_pub,
diff --git a/src/testing/testing_api_cmd_recoup.c 
b/src/testing/testing_api_cmd_recoup.c
index 9483b158..263a3303 100644
--- a/src/testing/testing_api_cmd_recoup.c
+++ b/src/testing/testing_api_cmd_recoup.c
@@ -182,11 +182,7 @@ recoup_run (void *cls,
   char *cref;
   unsigned int idx;
   const struct TALER_ExchangeWithdrawValues *ewv;
-  struct TALER_EXCHANGE_Handle *exchange
-    = TALER_TESTING_get_exchange (is);
 
-  if (NULL == exchange)
-    return;
   ps->is = is;
   if (GNUNET_OK !=
       TALER_TESTING_parse_coin_reference (
@@ -259,13 +255,16 @@ recoup_run (void *cls,
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "Trying to recoup denomination '%s'\n",
               TALER_B2S (&denom_pub->h_key));
-  ps->ph = TALER_EXCHANGE_recoup (exchange,
-                                  denom_pub,
-                                  coin_sig,
-                                  ewv,
-                                  planchet,
-                                  &recoup_cb,
-                                  ps);
+  ps->ph = TALER_EXCHANGE_recoup (
+    TALER_TESTING_interpreter_get_context (is),
+    TALER_TESTING_get_exchange_url (is),
+    TALER_TESTING_get_keys (is),
+    denom_pub,
+    coin_sig,
+    ewv,
+    planchet,
+    &recoup_cb,
+    ps);
   GNUNET_assert (NULL != ps->ph);
 }
 
diff --git a/src/testing/testing_api_cmd_recoup_refresh.c 
b/src/testing/testing_api_cmd_recoup_refresh.c
index 1c7456c7..7de5b96d 100644
--- a/src/testing/testing_api_cmd_recoup_refresh.c
+++ b/src/testing/testing_api_cmd_recoup_refresh.c
@@ -184,11 +184,7 @@ recoup_refresh_run (void *cls,
   const struct TALER_ExchangeWithdrawValues *ewv;
   char *cref;
   unsigned int idx;
-  struct TALER_EXCHANGE_Handle *exchange
-    = TALER_TESTING_get_exchange (is);
 
-  if (NULL == exchange)
-    return;
   rrs->is = is;
   if (GNUNET_OK !=
       TALER_TESTING_parse_coin_reference (
@@ -273,15 +269,18 @@ recoup_refresh_run (void *cls,
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "Trying to recoup_refresh denomination '%s'\n",
               TALER_B2S (&denom_pub->h_key));
-  rrs->ph = TALER_EXCHANGE_recoup_refresh (exchange,
-                                           denom_pub,
-                                           coin_sig,
-                                           ewv,
-                                           rplanchet,
-                                           planchet,
-                                           idx,
-                                           &recoup_refresh_cb,
-                                           rrs);
+  rrs->ph = TALER_EXCHANGE_recoup_refresh (
+    TALER_TESTING_interpreter_get_context (is),
+    TALER_TESTING_get_exchange_url (is),
+    TALER_TESTING_get_keys (is),
+    denom_pub,
+    coin_sig,
+    ewv,
+    rplanchet,
+    planchet,
+    idx,
+    &recoup_refresh_cb,
+    rrs);
   GNUNET_assert (NULL != rrs->ph);
 }
 
diff --git a/src/testing/testing_api_cmd_refresh.c 
b/src/testing/testing_api_cmd_refresh.c
index 3b420ac6..dfaf31fd 100644
--- a/src/testing/testing_api_cmd_refresh.c
+++ b/src/testing/testing_api_cmd_refresh.c
@@ -496,12 +496,8 @@ refresh_reveal_run (void *cls,
   struct RefreshRevealState *rrs = cls;
   struct RefreshMeltState *rms;
   const struct TALER_TESTING_Command *melt_cmd;
-  struct TALER_EXCHANGE_Handle *exchange
-    = TALER_TESTING_get_exchange (is);
 
   rrs->cmd = cmd;
-  if (NULL == exchange)
-    return;
   rrs->is = is;
   melt_cmd = TALER_TESTING_interpreter_lookup_command (is,
                                                        rrs->melt_reference);
@@ -518,14 +514,16 @@ refresh_reveal_run (void *cls,
 
     for (unsigned int i = 0; i<rms->num_fresh_coins; i++)
       alg_values[i] = rms->mbds[i].alg_value;
-    rrs->rrh = TALER_EXCHANGE_refreshes_reveal (exchange,
-                                                &rms->rms,
-                                                &rms->refresh_data,
-                                                rms->num_fresh_coins,
-                                                alg_values,
-                                                rms->noreveal_index,
-                                                &reveal_cb,
-                                                rrs);
+    rrs->rrh = TALER_EXCHANGE_refreshes_reveal (
+      TALER_TESTING_interpreter_get_context (is),
+      TALER_TESTING_get_exchange_url (is),
+      &rms->rms,
+      &rms->refresh_data,
+      rms->num_fresh_coins,
+      alg_values,
+      rms->noreveal_index,
+      &reveal_cb,
+      rrs);
   }
   if (NULL == rrs->rrh)
   {
@@ -913,12 +911,8 @@ melt_cb (void *cls,
 {
   struct RefreshMeltState *rms = cls;
   const struct TALER_EXCHANGE_HttpResponse *hr = &mr->hr;
-  struct TALER_EXCHANGE_Handle *exchange
-    = TALER_TESTING_get_exchange (rms->is);
 
   rms->rmh = NULL;
-  if (NULL == exchange)
-    return;
   if (rms->expected_response_code != hr->http_status)
   {
     if (0 != rms->do_retry)
@@ -978,11 +972,14 @@ melt_cb (void *cls,
   {
     TALER_LOG_DEBUG ("Doubling the melt (%s)\n",
                      rms->cmd->label);
-    rms->rmh = TALER_EXCHANGE_melt (exchange,
-                                    &rms->rms,
-                                    &rms->refresh_data,
-                                    &melt_cb,
-                                    rms);
+    rms->rmh = TALER_EXCHANGE_melt (
+      TALER_TESTING_interpreter_get_context (rms->is),
+      TALER_TESTING_get_exchange_url (rms->is),
+      TALER_TESTING_get_keys (rms->is),
+      &rms->rms,
+      &rms->refresh_data,
+      &melt_cb,
+      rms);
     rms->double_melt = false;
     return;
   }
@@ -1154,11 +1151,14 @@ melt_run (void *cls,
     GNUNET_assert (age_restricted ==
                    (NULL != age_commitment_proof));
 
-    rms->rmh = TALER_EXCHANGE_melt (exchange,
-                                    &rms->rms,
-                                    &rms->refresh_data,
-                                    &melt_cb,
-                                    rms);
+    rms->rmh = TALER_EXCHANGE_melt (
+      TALER_TESTING_interpreter_get_context (is),
+      TALER_TESTING_get_exchange_url (is),
+      TALER_TESTING_get_keys (is),
+      &rms->rms,
+      &rms->refresh_data,
+      &melt_cb,
+      rms);
 
     if (NULL == rms->rmh)
     {
diff --git a/src/testing/testing_api_cmd_refund.c 
b/src/testing/testing_api_cmd_refund.c
index a3ebd2e8..b8ce85f9 100644
--- a/src/testing/testing_api_cmd_refund.c
+++ b/src/testing/testing_api_cmd_refund.c
@@ -53,11 +53,6 @@ struct RefundState
    */
   uint64_t refund_transaction_id;
 
-  /**
-   * Connection to the exchange.
-   */
-  struct TALER_EXCHANGE_Handle *exchange;
-
   /**
    * Handle to the refund operation.
    */
@@ -116,9 +111,6 @@ refund_run (void *cls,
   const struct TALER_MerchantPrivateKeyP *merchant_priv;
   const struct TALER_TESTING_Command *coin_cmd;
 
-  rs->exchange = TALER_TESTING_get_exchange (is);
-  if (NULL == rs->exchange)
-    return;
   rs->is = is;
   if (GNUNET_OK !=
       TALER_string_to_amount (rs->refund_amount,
@@ -172,14 +164,17 @@ refund_run (void *cls,
     TALER_TESTING_interpreter_fail (is);
     return;
   }
-  rs->rh = TALER_EXCHANGE_refund (rs->exchange,
-                                  &refund_amount,
-                                  &h_contract_terms,
-                                  &coin,
-                                  rs->refund_transaction_id,
-                                  merchant_priv,
-                                  &refund_cb,
-                                  rs);
+  rs->rh = TALER_EXCHANGE_refund (
+    TALER_TESTING_interpreter_get_context (is),
+    TALER_TESTING_get_exchange_url (is),
+    TALER_TESTING_get_keys (is),
+    &refund_amount,
+    &h_contract_terms,
+    &coin,
+    rs->refund_transaction_id,
+    merchant_priv,
+    &refund_cb,
+    rs);
   GNUNET_assert (NULL != rs->rh);
 }
 
diff --git a/src/testing/testing_api_cmd_reserve_close.c 
b/src/testing/testing_api_cmd_reserve_close.c
index b2929f16..8e272f54 100644
--- a/src/testing/testing_api_cmd_reserve_close.c
+++ b/src/testing/testing_api_cmd_reserve_close.c
@@ -142,11 +142,7 @@ close_run (void *cls,
 {
   struct CloseState *ss = cls;
   const struct TALER_TESTING_Command *create_reserve;
-  struct TALER_EXCHANGE_Handle *exchange
-    = TALER_TESTING_get_exchange (is);
 
-  if (NULL == exchange)
-    return;
   ss->is = is;
   create_reserve
     = TALER_TESTING_interpreter_lookup_command (is,
@@ -169,11 +165,13 @@ close_run (void *cls,
   }
   GNUNET_CRYPTO_eddsa_key_get_public (&ss->reserve_priv->eddsa_priv,
                                       &ss->reserve_pub.eddsa_pub);
-  ss->rsh = TALER_EXCHANGE_reserves_close (exchange,
-                                           ss->reserve_priv,
-                                           ss->target_account,
-                                           &reserve_close_cb,
-                                           ss);
+  ss->rsh = TALER_EXCHANGE_reserves_close (
+    TALER_TESTING_interpreter_get_context (is),
+    TALER_TESTING_get_exchange_url (is),
+    ss->reserve_priv,
+    ss->target_account,
+    &reserve_close_cb,
+    ss);
 }
 
 
diff --git a/src/testing/testing_api_cmd_reserve_history.c 
b/src/testing/testing_api_cmd_reserve_history.c
index e9cc11a6..6e68bbe2 100644
--- a/src/testing/testing_api_cmd_reserve_history.c
+++ b/src/testing/testing_api_cmd_reserve_history.c
@@ -369,10 +369,13 @@ history_run (void *cls,
   }
   GNUNET_CRYPTO_eddsa_key_get_public (&ss->reserve_priv->eddsa_priv,
                                       &ss->reserve_pub.eddsa_pub);
-  ss->rsh = TALER_EXCHANGE_reserves_history (exchange,
-                                             ss->reserve_priv,
-                                             &reserve_history_cb,
-                                             ss);
+  ss->rsh = TALER_EXCHANGE_reserves_history (
+    TALER_TESTING_interpreter_get_context (is),
+    TALER_TESTING_get_exchange_url (is),
+    TALER_TESTING_get_keys (is),
+    ss->reserve_priv,
+    &reserve_history_cb,
+    ss);
 }
 
 
diff --git a/src/testing/testing_api_cmd_reserve_open.c 
b/src/testing/testing_api_cmd_reserve_open.c
index 6a6247b8..a78662c3 100644
--- a/src/testing/testing_api_cmd_reserve_open.c
+++ b/src/testing/testing_api_cmd_reserve_open.c
@@ -256,7 +256,9 @@ open_run (void *cls,
     cpi->h_denom_pub = denom_pub->h_key;
   }
   ss->rsh = TALER_EXCHANGE_reserves_open (
-    exchange,
+    TALER_TESTING_interpreter_get_context (is),
+    TALER_TESTING_get_exchange_url (is),
+    TALER_TESTING_get_keys (is),
     ss->reserve_priv,
     &ss->reserve_pay,
     ss->cpl,
diff --git a/src/testing/testing_api_cmd_reserve_purse.c 
b/src/testing/testing_api_cmd_reserve_purse.c
index 79530803..7a356c23 100644
--- a/src/testing/testing_api_cmd_reserve_purse.c
+++ b/src/testing/testing_api_cmd_reserve_purse.c
@@ -245,7 +245,9 @@ purse_run (void *cls,
                    GNUNET_JSON_from_timestamp (ds->purse_expiration)));
   ds->merge_timestamp = GNUNET_TIME_timestamp_get ();
   ds->dh = TALER_EXCHANGE_purse_create_with_merge (
-    exchange,
+    TALER_TESTING_interpreter_get_context (is),
+    TALER_TESTING_get_exchange_url (is),
+    TALER_TESTING_get_keys (is),
     &ds->reserve_priv,
     &ds->purse_priv,
     &ds->merge_priv,
diff --git a/src/testing/testing_api_cmd_reserve_status.c 
b/src/testing/testing_api_cmd_reserve_status.c
index 7e7b45cd..2da1bf74 100644
--- a/src/testing/testing_api_cmd_reserve_status.c
+++ b/src/testing/testing_api_cmd_reserve_status.c
@@ -341,10 +341,13 @@ status_run (void *cls,
   }
   GNUNET_CRYPTO_eddsa_key_get_public (&ss->reserve_priv->eddsa_priv,
                                       &ss->reserve_pub.eddsa_pub);
-  ss->rsh = TALER_EXCHANGE_reserves_status (exchange,
-                                            ss->reserve_priv,
-                                            &reserve_status_cb,
-                                            ss);
+  ss->rsh = TALER_EXCHANGE_reserves_status (
+    TALER_TESTING_interpreter_get_context (is),
+    TALER_TESTING_get_exchange_url (is),
+    TALER_TESTING_get_keys (is),
+    ss->reserve_priv,
+    &reserve_status_cb,
+    ss);
 }
 
 
diff --git a/src/testing/testing_api_cmd_transfer_get.c 
b/src/testing/testing_api_cmd_transfer_get.c
index 10fe48c2..37fe736b 100644
--- a/src/testing/testing_api_cmd_transfer_get.c
+++ b/src/testing/testing_api_cmd_transfer_get.c
@@ -345,10 +345,13 @@ track_transfer_run (void *cls,
     }
     GNUNET_assert (NULL != wtid_ptr);
   }
-  tts->tth = TALER_EXCHANGE_transfers_get (exchange,
-                                           wtid_ptr,
-                                           &track_transfer_cb,
-                                           tts);
+  tts->tth = TALER_EXCHANGE_transfers_get (
+    TALER_TESTING_interpreter_get_context (is),
+    TALER_TESTING_get_exchange_url (is),
+    TALER_TESTING_get_keys (is),
+    wtid_ptr,
+    &track_transfer_cb,
+    tts);
   GNUNET_assert (NULL != tts->tth);
 }
 

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]