diff --git a/src/exchange/taler-exchange-httpd_db.c b/src/exchange/taler-exchange-httpd_db.c
index 2e8f0a02..929f3c15 100644
--- a/src/exchange/taler-exchange-httpd_db.c
+++ b/src/exchange/taler-exchange-httpd_db.c
@@ -66,7 +66,8 @@ TEH_DB_know_coin_transaction (void *cls,
   GNUNET_assert (NULL != mhd_ret);
   qs = TEH_plugin->ensure_coin_known (TEH_plugin->cls,
                                       session,
-                                      kcc->coin);
+                                      kcc->coin,
+                                      &kcc->known_coin_id);
   if (GNUNET_DB_STATUS_HARD_ERROR == qs)
   {
     *mhd_ret
diff --git a/src/exchange/taler-exchange-httpd_deposit.c b/src/exchange/taler-exchange-httpd_deposit.c
index 95143758..a17e6a18 100644
--- a/src/exchange/taler-exchange-httpd_deposit.c
+++ b/src/exchange/taler-exchange-httpd_deposit.c
@@ -121,6 +121,11 @@ struct DepositContext
    */
   struct TALER_Amount value;
 
+  /**
+   * ID of the coin in the database.
+   */
+  uint64_t coin_id;
+
 };
 
 
@@ -237,7 +242,7 @@ deposit_transaction (void *cls,
 
     qs = TEH_plugin->get_coin_transactions (TEH_plugin->cls,
                                             session,
-                                            &deposit->coin.coin_pub,
+                                            dc->coin_id,
                                             GNUNET_NO,
                                             &tl);
     if (0 > qs)
@@ -271,11 +276,11 @@ deposit_transaction (void *cls,
     {
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   "Deposited coin has insufficient funds left!\n");
-      *mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds (connection,
-                                                             TALER_EC_DEPOSIT_INSUFFICIENT_FUNDS,
-                                                             &deposit->coin.
-                                                             coin_pub,
-                                                             tl);
+      *mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds (
+        connection,
+        TALER_EC_DEPOSIT_INSUFFICIENT_FUNDS,
+        &deposit->coin.coin_pub,
+        tl);
       TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
                                               tl);
       return GNUNET_DB_STATUS_HARD_ERROR;
@@ -286,6 +291,7 @@ deposit_transaction (void *cls,
   qs = TEH_plugin->insert_deposit (TEH_plugin->cls,
                                    session,
                                    dc->exchange_timestamp,
+                                   dc->coin_id,
                                    deposit);
   if (GNUNET_DB_STATUS_HARD_ERROR == qs)
   {
@@ -511,6 +517,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
       GNUNET_JSON_parse_free (spec);
       return mhd_ret;
     }
+    dc.coin_id = kcc.known_coin_id;
   }
 
   /* check deposit signature */
diff --git a/src/exchange/taler-exchange-httpd_melt.c b/src/exchange/taler-exchange-httpd_melt.c
index 3a0195cf..e13e6775 100644
--- a/src/exchange/taler-exchange-httpd_melt.c
+++ b/src/exchange/taler-exchange-httpd_melt.c
@@ -150,6 +150,11 @@ struct MeltContext
    */
   struct TALER_Amount coin_refresh_fee;
 
+  /**
+   * Unique ID of the coin this melt is about.
+   */
+  uint64_t coin_id;
+
   /**
    * Set to #GNUNET_YES if this coin's denomination was revoked and the operation
    * is thus only allowed for zombie coins where the transaction
@@ -187,7 +192,7 @@ refresh_check_melt (struct MHD_Connection *connection,
      we might be a zombie coin */
   qs = TEH_plugin->get_coin_transactions (TEH_plugin->cls,
                                           session,
-                                          &rmc->refresh_session.coin.coin_pub,
+                                          rmc->coin_id,
                                           GNUNET_YES,
                                           &tl);
   if (0 > qs)
@@ -343,6 +348,7 @@ melt_transaction (void *cls,
   if (0 >=
       (qs = TEH_plugin->insert_melt (TEH_plugin->cls,
                                      session,
+                                     rmc->coin_id,
                                      &rmc->refresh_session)))
   {
     if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
@@ -583,6 +589,7 @@ check_for_denomination_key (struct MHD_Connection *connection,
                                 &TEH_DB_know_coin_transaction,
                                 &kcc))
       return mhd_ret;
+    rmc->coin_id = kcc.known_coin_id;
   }
 
   /* sanity-check that "total melt amount > melt fee" */
diff --git a/src/exchange/taler-exchange-httpd_recoup.c b/src/exchange/taler-exchange-httpd_recoup.c
index c1f6ff33..52a59356 100644
--- a/src/exchange/taler-exchange-httpd_recoup.c
+++ b/src/exchange/taler-exchange-httpd_recoup.c
@@ -93,6 +93,11 @@ struct RecoupContext
    */
   struct GNUNET_TIME_Absolute now;
 
+  /**
+   * Which coin is this about?
+   */
+  uint64_t coin_id;
+
   /**
    * #GNUNET_YES if the client claims the coin originated from a refresh.
    */
@@ -187,7 +192,7 @@ recoup_transaction (void *cls,
   /* Calculate remaining balance, including recoups already applied. */
   qs = TEH_plugin->get_coin_transactions (TEH_plugin->cls,
                                           session,
-                                          &pc->coin->coin_pub,
+                                          pc->coin_id,
                                           GNUNET_YES,
                                           &tl);
   if (0 > qs)
@@ -293,6 +298,7 @@ recoup_transaction (void *cls,
   {
     qs = TEH_plugin->insert_recoup_refresh_request (TEH_plugin->cls,
                                                     session,
+                                                    pc->coin_id,
                                                     pc->coin,
                                                     pc->coin_sig,
                                                     pc->coin_bks,
@@ -305,6 +311,7 @@ recoup_transaction (void *cls,
     qs = TEH_plugin->insert_recoup_request (TEH_plugin->cls,
                                             session,
                                             &pc->target.reserve_pub,
+                                            pc->coin_id,
                                             pc->coin,
                                             pc->coin_sig,
                                             pc->coin_bks,
@@ -343,12 +350,12 @@ recoup_transaction (void *cls,
  * @return MHD result code
  */
 static MHD_RESULT
-verify_and_execute_recoup (struct MHD_Connection *connection,
-                           const struct TALER_CoinPublicInfo *coin,
-                           const struct
-                           TALER_DenominationBlindingKeyP *coin_bks,
-                           const struct TALER_CoinSpendSignatureP *coin_sig,
-                           int refreshed)
+verify_and_execute_recoup (
+  struct MHD_Connection *connection,
+  const struct TALER_CoinPublicInfo *coin,
+  const struct TALER_DenominationBlindingKeyP *coin_bks,
+  const struct TALER_CoinSpendSignatureP *coin_sig,
+  int refreshed)
 {
   struct RecoupContext pc;
   const struct TALER_EXCHANGEDB_DenominationKey *dki;
@@ -464,6 +471,7 @@ verify_and_execute_recoup (struct MHD_Connection *connection,
                                 &TEH_DB_know_coin_transaction,
                                 &kcc))
       return mhd_ret;
+    pc.coin_id = kcc.known_coin_id;
   }
 
   /* Perform actual recoup transaction */
diff --git a/src/exchangedb/exchange-0001.sql b/src/exchangedb/exchange-0001.sql
index ad05e779..31c6c02d 100644
--- a/src/exchangedb/exchange-0001.sql
+++ b/src/exchangedb/exchange-0001.sql
@@ -168,9 +168,11 @@ CREATE INDEX IF NOT EXISTS reserves_out_for_get_withdraw_info
 
 
 CREATE TABLE IF NOT EXISTS known_coins
-  (coin_pub BYTEA NOT NULL PRIMARY KEY CHECK (LENGTH(coin_pub)=32)
+  (known_coin_id BIGSERIAL PRIMARY KEY
+  ,coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)
   ,denom_pub_hash BYTEA NOT NULL REFERENCES denominations (denom_pub_hash) ON DELETE CASCADE
-  ,denom_sig BYTEA NOT NULL
+  ,denom_sig BYTEA NOT NULL,
+  UNIQUE (coin_pub, denom_pub_hash)
   );
 COMMENT ON TABLE known_coins
   IS 'information about coins and their signatures, so we do not have to store the signatures more than once if a coin is involved in multiple operations';
@@ -183,7 +185,7 @@ CREATE INDEX IF NOT EXISTS known_coins_by_denomination
 CREATE TABLE IF NOT EXISTS refresh_commitments
   (melt_serial_id BIGSERIAL UNIQUE
   ,rc BYTEA PRIMARY KEY CHECK (LENGTH(rc)=64)
-  ,old_coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub) ON DELETE CASCADE
+  ,old_known_coin_id INT8 NOT NULL REFERENCES known_coins (known_coin_id) ON DELETE CASCADE
   ,old_coin_sig BYTEA NOT NULL CHECK(LENGTH(old_coin_sig)=64)
   ,amount_with_fee_val INT8 NOT NULL
   ,amount_with_fee_frac INT4 NOT NULL
@@ -192,9 +194,9 @@ CREATE TABLE IF NOT EXISTS refresh_commitments
 COMMENT ON TABLE refresh_commitments
   IS 'Commitments made when melting coins and the gamma value chosen by the exchange.';
 
-CREATE INDEX IF NOT EXISTS refresh_commitments_old_coin_pub_index
+CREATE INDEX IF NOT EXISTS refresh_commitments_old_coin_index
   ON refresh_commitments
-  (old_coin_pub);
+  (old_known_coin_id);
 
 
 CREATE TABLE IF NOT EXISTS refresh_revealed_coins
@@ -221,7 +223,7 @@ COMMENT ON COLUMN refresh_revealed_coins.h_coin_ev
 COMMENT ON COLUMN refresh_revealed_coins.ev_sig
   IS 'exchange signature over the envelope';
 
-CREATE INDEX IF NOT EXISTS refresh_revealed_coins_coin_pub_index
+CREATE INDEX IF NOT EXISTS refresh_revealed_coins_denom_index
   ON refresh_revealed_coins
   (denom_pub_hash);
 
@@ -251,7 +253,7 @@ COMMENT ON INDEX refresh_transfer_keys_coin_tpub
 
 CREATE TABLE IF NOT EXISTS deposits
   (deposit_serial_id BIGSERIAL PRIMARY KEY
-  ,coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub) ON DELETE CASCADE
+  ,known_coin_id INT8 NOT NULL REFERENCES known_coins (known_coin_id) ON DELETE CASCADE
   ,amount_with_fee_val INT8 NOT NULL
   ,amount_with_fee_frac INT4 NOT NULL
   ,wallet_timestamp INT8 NOT NULL
@@ -265,7 +267,7 @@ CREATE TABLE IF NOT EXISTS deposits
   ,wire TEXT NOT NULL
   ,tiny BOOLEAN NOT NULL DEFAULT FALSE
   ,done BOOLEAN NOT NULL DEFAULT FALSE
-  ,UNIQUE (coin_pub, merchant_pub, h_contract_terms)
+  ,UNIQUE (known_coin_id, merchant_pub, h_contract_terms)
   );
 COMMENT ON TABLE deposits
   IS 'Deposits we have received and for which we need to make (aggregate) wire transfers (and manage refunds).';
@@ -274,13 +276,13 @@ COMMENT ON COLUMN deposits.done
 COMMENT ON COLUMN deposits.tiny
   IS 'Set to TRUE if we decided that the amount is too small to ever trigger a wire transfer by itself (requires real aggregation)';
 
-CREATE INDEX IF NOT EXISTS deposits_coin_pub_merchant_contract_index
+CREATE INDEX IF NOT EXISTS deposits_coin_merchant_contract_index
   ON deposits
-  (coin_pub
+  (known_coin_id
   ,merchant_pub
   ,h_contract_terms
   );
-COMMENT ON INDEX deposits_coin_pub_merchant_contract_index
+COMMENT ON INDEX deposits_coin_merchant_contract_index
   IS 'for get_deposit_for_wtid and test_deposit_done';
 CREATE INDEX IF NOT EXISTS deposits_get_ready_index
   ON deposits
@@ -289,7 +291,7 @@ CREATE INDEX IF NOT EXISTS deposits_get_ready_index
   ,wire_deadline
   ,refund_deadline
   );
-COMMENT ON INDEX deposits_coin_pub_merchant_contract_index
+COMMENT ON INDEX deposits_get_ready_index
   IS 'for deposits_get_ready';
 CREATE INDEX IF NOT EXISTS deposits_iterate_matching_index
   ON deposits
@@ -304,23 +306,23 @@ COMMENT ON INDEX deposits_iterate_matching_index
 
 CREATE TABLE IF NOT EXISTS refunds
   (refund_serial_id BIGSERIAL UNIQUE
-  ,coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub) ON DELETE CASCADE
+  ,known_coin_id INT8 NOT NULL REFERENCES known_coins (known_coin_id) ON DELETE CASCADE
   ,merchant_pub BYTEA NOT NULL CHECK(LENGTH(merchant_pub)=32)
   ,merchant_sig BYTEA NOT NULL CHECK(LENGTH(merchant_sig)=64)
   ,h_contract_terms BYTEA NOT NULL CHECK(LENGTH(h_contract_terms)=64)
   ,rtransaction_id INT8 NOT NULL
   ,amount_with_fee_val INT8 NOT NULL
   ,amount_with_fee_frac INT4 NOT NULL
-  ,PRIMARY KEY (coin_pub, merchant_pub, h_contract_terms, rtransaction_id)
+  ,PRIMARY KEY (known_coin_id, merchant_pub, h_contract_terms, rtransaction_id)
   );
 COMMENT ON TABLE refunds
-  IS 'Data on coins that were refunded. Technically, refunds always apply against specific deposit operations involving a coin. The combination of coin_pub, merchant_pub, h_contract_terms and rtransaction_id MUST be unique, and we usually select by coin_pub so that one goes first.';
+  IS 'Data on coins that were refunded. Technically, refunds always apply against specific deposit operations involving a coin. The combination of known_coin_id, merchant_pub, h_contract_terms and rtransaction_id MUST be unique, and we usually select by known_coin_id so that one goes first.';
 COMMENT ON COLUMN refunds.rtransaction_id
   IS 'used by the merchant to make refunds unique in case the same coin for the same deposit gets a subsequent (higher) refund';
 
-CREATE INDEX IF NOT EXISTS refunds_coin_pub_index
+CREATE INDEX IF NOT EXISTS refunds_coin_index
   ON refunds
-  (coin_pub);
+  (known_coin_id);
 
 
 CREATE TABLE IF NOT EXISTS wire_out
@@ -372,7 +374,7 @@ CREATE INDEX IF NOT EXISTS wire_fee_gc_index
 
 CREATE TABLE IF NOT EXISTS recoup
   (recoup_uuid BIGSERIAL UNIQUE
-  ,coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub)
+  ,known_coin_id INT8 NOT NULL REFERENCES known_coins (known_coin_id) ON DELETE CASCADE
   ,coin_sig BYTEA NOT NULL CHECK(LENGTH(coin_sig)=64)
   ,coin_blind BYTEA NOT NULL CHECK(LENGTH(coin_blind)=32)
   ,amount_val INT8 NOT NULL
@@ -382,25 +384,25 @@ CREATE TABLE IF NOT EXISTS recoup
   );
 COMMENT ON TABLE recoup
   IS 'Information about recoups that were executed';
-COMMENT ON COLUMN recoup.coin_pub
-  IS 'Do not CASCADE ON DROP on the coin_pub, as we may keep the coin alive!';
+COMMENT ON COLUMN recoup.known_coin_id
+  IS 'Do not CASCADE ON DROP on the known_coin_id, as we may keep the coin alive!';
 
 CREATE INDEX IF NOT EXISTS recoup_by_coin_index
   ON recoup
-  (coin_pub);
+  (known_coin_id);
 CREATE INDEX IF NOT EXISTS recoup_by_h_blind_ev
   ON recoup
   (h_blind_ev);
 CREATE INDEX IF NOT EXISTS recoup_for_by_reserve
   ON recoup
-  (coin_pub
+  (known_coin_id
   ,h_blind_ev
   );
 
 
 CREATE TABLE IF NOT EXISTS recoup_refresh
   (recoup_refresh_uuid BIGSERIAL UNIQUE
-  ,coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub)
+  ,known_coin_id INT8 NOT NULL REFERENCES known_coins (known_coin_id) ON DELETE CASCADE
   ,coin_sig BYTEA NOT NULL CHECK(LENGTH(coin_sig)=64)
   ,coin_blind BYTEA NOT NULL CHECK(LENGTH(coin_blind)=32)
   ,amount_val INT8 NOT NULL
@@ -408,18 +410,18 @@ CREATE TABLE IF NOT EXISTS recoup_refresh
   ,timestamp INT8 NOT NULL
   ,h_blind_ev BYTEA NOT NULL REFERENCES refresh_revealed_coins (h_coin_ev) ON DELETE CASCADE
   );
-COMMENT ON COLUMN recoup_refresh.coin_pub
-  IS 'Do not CASCADE ON DROP on the coin_pub, as we may keep the coin alive!';
+COMMENT ON COLUMN recoup_refresh.known_coin_id
+  IS 'Do not CASCADE ON DROP on the known_coin_id, as we may keep the coin alive!';
 
 CREATE INDEX IF NOT EXISTS recoup_refresh_by_coin_index
   ON recoup_refresh
-  (coin_pub);
+  (known_coin_id);
 CREATE INDEX IF NOT EXISTS recoup_refresh_by_h_blind_ev
   ON recoup_refresh
   (h_blind_ev);
 CREATE INDEX IF NOT EXISTS recoup_refresh_for_by_reserve
   ON recoup_refresh
-  (coin_pub
+  (known_coin_id
   ,h_blind_ev
   );
 
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c
index dede901f..6e25e496 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -556,17 +556,16 @@ postgres_get_session (void *cls)
                               " FROM known_coins"
                               " WHERE denom_pub_hash=$1;",
                               1),
-      /* Used in #postgres_get_known_coin() to fetch
-         the denomination public key and signature for
-         a coin known to the exchange. */
-      GNUNET_PQ_make_prepare ("get_known_coin",
+      /* Used in #postgres_check_known_coin() to fetch
+         the known_coin_id for a coin known to the exchange. */
+      GNUNET_PQ_make_prepare ("check_known_coin",
                               "SELECT"
-                              " denom_pub_hash"
-                              ",denom_sig"
+                              " known_coin_id"
                               " FROM known_coins"
                               " WHERE coin_pub=$1"
+                              "   AND denom_pub_hash=$2"
                               " FOR UPDATE;",
-                              1),
+                              2),
       /* Used in #postgres_get_coin_denomination() to fetch
          the denomination public key hash for
          a coin known to the exchange. */
@@ -592,7 +591,8 @@ postgres_get_session (void *cls)
                               ",denom_pub_hash"
                               ",denom_sig"
                               ") VALUES "
-                              "($1,$2,$3);",
+                              "($1,$2,$3) "
+                              "RETURNING known_coin_id;",
                               3),
 
       /* Used in #postgres_insert_melt() to store
@@ -600,7 +600,7 @@ postgres_get_session (void *cls)
       GNUNET_PQ_make_prepare ("insert_melt",
                               "INSERT INTO refresh_commitments "
                               "(rc "
-                              ",old_coin_pub "
+                              ",old_known_coin_id "
                               ",old_coin_sig "
                               ",amount_with_fee_val "
                               ",amount_with_fee_frac "
@@ -615,14 +615,14 @@ postgres_get_session (void *cls)
                               " kc.denom_pub_hash"
                               ",denom.fee_refresh_val"
                               ",denom.fee_refresh_frac"
-                              ",old_coin_pub"
+                              ",kc.coin_pub AS old_coin_pub"
                               ",old_coin_sig"
                               ",amount_with_fee_val"
                               ",amount_with_fee_frac"
                               ",noreveal_index"
                               " FROM refresh_commitments"
                               "   JOIN known_coins kc"
-                              "     ON (refresh_commitments.old_coin_pub = kc.coin_pub)"
+                              "     ON (refresh_commitments.old_known_coin_id = kc.known_coin_id)"
                               "   JOIN denominations denom"
                               "     ON (kc.denom_pub_hash = denom.denom_pub_hash)"
                               " WHERE rc=$1;",
@@ -640,7 +640,7 @@ postgres_get_session (void *cls)
       GNUNET_PQ_make_prepare ("audit_get_refresh_commitments_incr",
                               "SELECT"
                               " denom.denom_pub"
-                              ",old_coin_pub"
+                              ",kc.coin_pub AS old_coin_pub"
                               ",old_coin_sig"
                               ",amount_with_fee_val"
                               ",amount_with_fee_frac"
@@ -649,7 +649,7 @@ postgres_get_session (void *cls)
                               ",rc"
                               " FROM refresh_commitments"
                               "   JOIN known_coins kc"
-                              "     ON (refresh_commitments.old_coin_pub = kc.coin_pub)"
+                              "     ON (refresh_commitments.old_known_coin_id = kc.known_coin_id)"
                               "   JOIN denominations denom"
                               "     ON (kc.denom_pub_hash = denom.denom_pub_hash)"
                               " WHERE melt_serial_id>=$1"
@@ -667,9 +667,9 @@ postgres_get_session (void *cls)
                               ",melt_serial_id"
                               " FROM refresh_commitments"
                               "    JOIN known_coins "
-                              "      ON (refresh_commitments.old_coin_pub = known_coins.coin_pub)"
+                              "      ON (refresh_commitments.old_known_coin_id = known_coins.known_coin_id)"
                               "    JOIN denominations denom USING (denom_pub_hash)"
-                              " WHERE old_coin_pub=$1;",
+                              " WHERE old_known_coin_id=$1;",
                               1),
 
       /* Store information about the desired denominations for a
@@ -727,7 +727,7 @@ postgres_get_session (void *cls)
       /* Used in #postgres_insert_refund() to store refund information */
       GNUNET_PQ_make_prepare ("insert_refund",
                               "INSERT INTO refunds "
-                              "(coin_pub "
+                              "(known_coin_id "
                               ",merchant_pub "
                               ",merchant_sig "
                               ",h_contract_terms "
@@ -750,9 +750,9 @@ postgres_get_session (void *cls)
                               ",denom.fee_refund_frac "
                               ",refund_serial_id"
                               " FROM refunds"
-                              "    JOIN known_coins USING (coin_pub)"
+                              "    JOIN known_coins USING (known_coin_id)"
                               "    JOIN denominations denom USING (denom_pub_hash)"
-                              " WHERE coin_pub=$1;",
+                              " WHERE known_coin_id=$1;",
                               1),
       /* Query the 'refunds' by coin public key, merchant_pub and contract hash */
       GNUNET_PQ_make_prepare ("get_refunds_by_coin_and_contract",
@@ -760,8 +760,7 @@ postgres_get_session (void *cls)
                               " amount_with_fee_val"
                               ",amount_with_fee_frac"
                               " FROM refunds"
-                              " WHERE"
-                              "       coin_pub=$1"
+                              " WHERE known_coin_id=$1"
                               "   AND merchant_pub=$2"
                               "   AND h_contract_terms=$3;",
                               3),
@@ -778,7 +777,7 @@ postgres_get_session (void *cls)
                               ",amount_with_fee_frac"
                               ",refund_serial_id"
                               " FROM refunds"
-                              "   JOIN known_coins kc USING (coin_pub)"
+                              "   JOIN known_coins kc USING (known_coin_id)"
                               "   JOIN denominations denom ON (kc.denom_pub_hash = denom.denom_pub_hash)"
                               " WHERE refund_serial_id>=$1"
                               " ORDER BY refund_serial_id ASC;",
@@ -793,7 +792,7 @@ postgres_get_session (void *cls)
          Used in #postgres_insert_deposit(). */
       GNUNET_PQ_make_prepare ("insert_deposit",
                               "INSERT INTO deposits "
-                              "(coin_pub"
+                              "(known_coin_id"
                               ",amount_with_fee_val"
                               ",amount_with_fee_frac"
                               ",wallet_timestamp"
@@ -824,9 +823,9 @@ postgres_get_session (void *cls)
                               ",h_contract_terms"
                               ",h_wire"
                               " FROM deposits"
-                              " JOIN known_coins USING (coin_pub)"
+                              " JOIN known_coins USING (known_coin_id)"
                               " JOIN denominations USING (denom_pub_hash)"
-                              " WHERE ((coin_pub=$1)"
+                              " WHERE ((known_coin_id=$1)"
                               "    AND (merchant_pub=$3)"
                               "    AND (h_contract_terms=$2))"
                               " FOR UPDATE;",
@@ -849,7 +848,7 @@ postgres_get_session (void *cls)
                               ",done"
                               ",deposit_serial_id"
                               " FROM deposits"
-                              "    JOIN known_coins USING (coin_pub)"
+                              "    JOIN known_coins USING (known_coin_id)"
                               "    JOIN denominations denom USING (denom_pub_hash)"
                               " WHERE ("
                               "  (deposit_serial_id>=$1)"
@@ -866,14 +865,12 @@ postgres_get_session (void *cls)
                               ",denom.fee_deposit_frac"
                               ",wire_deadline"
                               " FROM deposits"
-                              "    JOIN known_coins USING (coin_pub)"
+                              "    JOIN known_coins USING (known_coin_id)"
                               "    JOIN denominations denom USING (denom_pub_hash)"
-                              " WHERE ("
-                              "      (coin_pub=$1)"
+                              " WHERE  (coin_pub=$1)"
                               "    AND (merchant_pub=$2)"
                               "    AND (h_contract_terms=$3)"
-                              "    AND (h_wire=$4)"
-                              " );",
+                              "    AND (h_wire=$4);",
                               4),
       /* Used in #postgres_get_ready_deposit() */
       GNUNET_PQ_make_prepare ("deposits_get_ready",
@@ -887,11 +884,11 @@ postgres_get_session (void *cls)
                               ",h_contract_terms"
                               ",wire"
                               ",merchant_pub"
-                              ",coin_pub"
+                              ",coin_pub" // FIXME: probably should also return known_coin_id!
                               ",exchange_timestamp"
                               ",wallet_timestamp"
                               " FROM deposits"
-                              "    JOIN known_coins USING (coin_pub)"
+                              "    JOIN known_coins USING (known_coin_id)"
                               "    JOIN denominations denom USING (denom_pub_hash)"
                               " WHERE tiny=FALSE"
                               "    AND done=FALSE"
@@ -915,7 +912,7 @@ postgres_get_session (void *cls)
                               ",coin_pub"
                               " FROM deposits"
                               "    JOIN known_coins"
-                              "      USING (coin_pub)"
+                              "      USING (known_coin_id)"
                               "    JOIN denominations denom"
                               "      USING (denom_pub_hash)"
                               " WHERE"
@@ -943,7 +940,7 @@ postgres_get_session (void *cls)
       GNUNET_PQ_make_prepare ("test_deposit_done",
                               "SELECT done"
                               " FROM deposits"
-                              " WHERE coin_pub=$1"
+                              " WHERE known_coin_id=$1"
                               "   AND merchant_pub=$2"
                               "   AND h_contract_terms=$3"
                               "   AND h_wire=$4;",
@@ -967,10 +964,10 @@ postgres_get_session (void *cls)
                               ",deposit_serial_id"
                               " FROM deposits"
                               "    JOIN known_coins"
-                              "      USING (coin_pub)"
+                              "      USING (known_coin_id)"
                               "    JOIN denominations denom"
                               "      USING (denom_pub_hash)"
-                              " WHERE coin_pub=$1"
+                              " WHERE known_coin_id=$1"
                               " FOR UPDATE;",
                               1),
 
@@ -988,7 +985,9 @@ postgres_get_session (void *cls)
                               "       USING (rc)"
                               "     JOIN denominations denoms"
                               "       ON (rrc.denom_pub_hash = denoms.denom_pub_hash)"
-                              " WHERE old_coin_pub=$1"
+                              "     JOIN known_coins kc"
+                              "       ON (old_known_coin_id = kc.known_coin_id)"
+                              " WHERE kc.coin_pub=$1"
                               " ORDER BY tp.transfer_pub",
                               1),
       /* Used in #postgres_lookup_wire_transfer */
@@ -998,7 +997,7 @@ postgres_get_session (void *cls)
                               ",deposits.h_contract_terms"
                               ",deposits.wire"
                               ",deposits.h_wire"
-                              ",deposits.coin_pub"
+                              ",known_coins.coin_pub"
                               ",deposits.merchant_pub"
                               ",wire_out.execution_date"
                               ",deposits.amount_with_fee_val"
@@ -1010,7 +1009,7 @@ postgres_get_session (void *cls)
                               "    JOIN deposits"
                               "      USING (deposit_serial_id)"
                               "    JOIN known_coins"
-                              "      USING (coin_pub)"
+                              "      USING (known_coin_id)"
                               "    JOIN denominations denom"
                               "      USING (denom_pub_hash)"
                               "    JOIN wire_out"
@@ -1030,7 +1029,7 @@ postgres_get_session (void *cls)
                               "    JOIN aggregation_tracking"
                               "      USING (deposit_serial_id)"
                               "    JOIN known_coins"
-                              "      USING (coin_pub)"
+                              "      USING (known_coin_id)"
                               "    JOIN denominations denom"
                               "      USING (denom_pub_hash)"
                               "    JOIN wire_out"
@@ -1120,7 +1119,7 @@ postgres_get_session (void *cls)
       GNUNET_PQ_make_prepare ("deposits_get_overdue",
                               "SELECT"
                               " deposit_serial_id"
-                              ",coin_pub"
+                              ",kc.coin_pub" // FIXME: also return coin_id?
                               ",amount_with_fee_val"
                               ",amount_with_fee_frac"
                               ",wire"
@@ -1128,11 +1127,13 @@ postgres_get_session (void *cls)
                               ",tiny"
                               ",done"
                               " FROM deposits"
+                              " JOIN known_coins kc"
+                              "   USING (known_coin_id)"
                               " WHERE wire_deadline >= $1"
                               " AND wire_deadline < $2"
                               " AND NOT (EXISTS (SELECT 1"
                               "            FROM refunds"
-                              "            WHERE (refunds.coin_pub = deposits.coin_pub))"
+                              "            WHERE (refunds.known_coin_id = deposits.known_coin_id))"
                               "       OR EXISTS (SELECT 1"
                               "            FROM aggregation_tracking"
                               "            WHERE (aggregation_tracking.deposit_serial_id = deposits.deposit_serial_id)))"
@@ -1168,7 +1169,7 @@ postgres_get_session (void *cls)
          information */
       GNUNET_PQ_make_prepare ("recoup_insert",
                               "INSERT INTO recoup "
-                              "(coin_pub"
+                              "(known_coin_id"
                               ",coin_sig"
                               ",coin_blind"
                               ",amount_val"
@@ -1182,7 +1183,7 @@ postgres_get_session (void *cls)
          information */
       GNUNET_PQ_make_prepare ("recoup_refresh_insert",
                               "INSERT INTO recoup_refresh "
-                              "(coin_pub"
+                              "(known_coin_id"
                               ",coin_sig"
                               ",coin_blind"
                               ",amount_val"
@@ -1209,7 +1210,7 @@ postgres_get_session (void *cls)
                               ",amount_frac"
                               " FROM recoup"
                               "    JOIN known_coins coins"
-                              "      USING (coin_pub)"
+                              "      USING (known_coin_id)"
                               "    JOIN reserves_out ro"
                               "      USING (h_blind_ev)"
                               "    JOIN denominations denoms"
@@ -1223,9 +1224,9 @@ postgres_get_session (void *cls)
                               "SELECT"
                               " recoup_refresh_uuid"
                               ",timestamp"
-                              ",rc.old_coin_pub"
+                              ",old_coins.coin_pub AS old_coin_pub"
                               ",old_coins.denom_pub_hash AS old_denom_pub_hash"
-                              ",recoup_refresh.coin_pub"
+                              ",new_coins.coin_pub"
                               ",coin_sig"
                               ",coin_blind"
                               ",denoms.denom_pub"
@@ -1240,9 +1241,9 @@ postgres_get_session (void *cls)
                               "    INNER JOIN refresh_commitments rc"
                               "      ON (rrc.rc = rc.rc)"
                               "    INNER JOIN known_coins old_coins"
-                              "      ON (rc.old_coin_pub = old_coins.coin_pub)"
+                              "      ON (rc.old_known_coin_id = old_coins.known_coin_id)"
                               "    INNER JOIN known_coins new_coins"
-                              "      ON (new_coins.coin_pub = recoup_refresh.coin_pub)"
+                              "      ON (new_coins.known_coin_id = recoup_refresh.known_coin_id)"
                               "    INNER JOIN denominations denoms"
                               "      ON (new_coins.denom_pub_hash = denoms.denom_pub_hash)"
                               " WHERE recoup_refresh_uuid>=$1"
@@ -1279,7 +1280,7 @@ postgres_get_session (void *cls)
                               ",coins.denom_sig"
                               " FROM recoup"
                               "    JOIN known_coins coins"
-                              "      USING (coin_pub)"
+                              "      USING (known_coin_id)"
                               "    JOIN reserves_out ro"
                               "      USING (h_blind_ev)"
                               " WHERE ro.reserve_pub=$1"
@@ -1289,7 +1290,8 @@ postgres_get_session (void *cls)
          affecting old coins of refreshed coins */
       GNUNET_PQ_make_prepare ("recoup_by_old_coin",
                               "SELECT"
-                              " coin_pub"
+                              " known_coin_id"
+                              ",coins.coin_pub"
                               ",coin_sig"
                               ",coin_blind"
                               ",amount_val"
@@ -1299,14 +1301,14 @@ postgres_get_session (void *cls)
                               ",coins.denom_sig"
                               ",recoup_refresh_uuid"
                               " FROM recoup_refresh"
-                              "    JOIN known_coins coins"
-                              "      USING (coin_pub)"
+                              "   JOIN known_coins coins"
+                              "     USING (known_coin_id)"
                               " WHERE h_blind_ev IN"
                               "   (SELECT rrc.h_coin_ev"
                               "    FROM refresh_commitments"
                               "       JOIN refresh_revealed_coins rrc"
                               "           USING (rc)"
-                              "    WHERE old_coin_pub=$1)"
+                              "    WHERE old_known_coin_id=$1)"
                               " FOR UPDATE;",
                               1),
       /* Used in #postgres_get_reserve_history() */
@@ -1352,19 +1354,21 @@ postgres_get_session (void *cls)
                               " FROM recoup"
                               "    JOIN reserves_out ro"
                               "      USING (h_blind_ev)"
-                              " WHERE recoup.coin_pub=$1"
+                              " WHERE recoup.known_coin_id=$1"
                               " FOR UPDATE;",
                               1),
       /* Used in #postgres_get_coin_transactions() to obtain recoup transactions
          for a refreshed coin */
       GNUNET_PQ_make_prepare ("recoup_by_refreshed_coin",
                               "SELECT"
-                              " rc.old_coin_pub"
+                              " rc.old_known_coin_id"
+                              ",old_known.coin_pub AS old_coin_pub"
                               ",coin_sig"
                               ",coin_blind"
                               ",amount_val"
                               ",amount_frac"
                               ",timestamp"
+                              ",coins.coin_pub"
                               ",coins.denom_pub_hash"
                               ",coins.denom_sig"
                               ",recoup_refresh_uuid"
@@ -1374,8 +1378,10 @@ postgres_get_session (void *cls)
                               "    JOIN refresh_commitments rc"
                               "      ON (rrc.rc = rc.rc)"
                               "    JOIN known_coins coins"
-                              "      USING (coin_pub)"
-                              " WHERE coin_pub=$1"
+                              "      USING (known_coin_id)"
+                              "    JOIN known_coins old_known"
+                              "      ON (rc.old_known_coin_id = old_known.known_coin_id)"
+                              " WHERE recoup_refresh.known_coin_id=$1"
                               " FOR UPDATE;",
                               1),
       /* Used in #postgres_get_reserve_by_h_blind() */
@@ -1390,10 +1396,12 @@ postgres_get_session (void *cls)
       /* Used in #postgres_get_old_coin_by_h_blind() */
       GNUNET_PQ_make_prepare ("old_coin_by_h_blind",
                               "SELECT"
-                              " rcom.old_coin_pub"
+                              " kc.coin_pub" // FIXME: also return coin_id?
                               " FROM refresh_revealed_coins"
                               "   JOIN refresh_commitments rcom"
                               "      USING (rc)"
+                              "   JOIN known_coins kc"
+                              "      ON (rcom.old_known_coin_id = kc.known_coin_id)"
                               " WHERE h_coin_ev=$1"
                               " LIMIT 1"
                               " FOR UPDATE;",
@@ -2595,6 +2603,7 @@ postgres_get_reserve_history (void *cls,
 static enum GNUNET_DB_QueryStatus
 postgres_have_deposit (void *cls,
                        struct TALER_EXCHANGEDB_Session *session,
+                       uint64_t coin_id,
                        const struct TALER_EXCHANGEDB_Deposit *deposit,
                        int check_extras,
                        struct TALER_Amount *deposit_fee,
@@ -2602,7 +2611,7 @@ postgres_have_deposit (void *cls,
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (&deposit->coin.coin_pub),
+    GNUNET_PQ_query_param_uint64 (&coin_id),
     GNUNET_PQ_query_param_auto_from_type (&deposit->h_contract_terms),
     GNUNET_PQ_query_param_auto_from_type (&deposit->merchant_pub),
     GNUNET_PQ_query_param_end
@@ -2711,13 +2720,13 @@ postgres_mark_deposit_tiny (void *cls,
 static enum GNUNET_DB_QueryStatus
 postgres_test_deposit_done (void *cls,
                             struct TALER_EXCHANGEDB_Session *session,
-                            const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                            uint64_t coin_id,
                             const struct TALER_MerchantPublicKeyP *merchant_pub,
                             const struct GNUNET_HashCode *h_contract_terms,
                             const struct GNUNET_HashCode *h_wire)
 {
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (coin_pub),
+    GNUNET_PQ_query_param_uint64 (&coin_id),
     GNUNET_PQ_query_param_auto_from_type (merchant_pub),
     GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
     GNUNET_PQ_query_param_auto_from_type (h_wire),
@@ -3039,84 +3048,43 @@ postgres_iterate_matching_deposits (
 
 
 /**
- * Retrieve the record for a known coin.
+ * Check if a coin is known, and if so, return the @a known_coin_id.
  *
  * @param cls the plugin closure
  * @param session the database session handle
  * @param coin_pub the public key of the coin to search for
- * @param coin_info place holder for the returned coin information object
+ * @param denom_pub_hash hash of the denomination of the coin
+ * @param[out] known_coin_id identifier of the coin in the database
  * @return transaction status code
  */
 static enum GNUNET_DB_QueryStatus
-postgres_get_known_coin (void *cls,
-                         struct TALER_EXCHANGEDB_Session *session,
-                         const struct TALER_CoinSpendPublicKeyP *coin_pub,
-                         struct TALER_CoinPublicInfo *coin_info)
+postgres_check_known_coin (void *cls,
+                           struct TALER_EXCHANGEDB_Session *session,
+                           const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                           const struct GNUNET_HashCode *denom_pub_hash,
+                           uint64_t *known_coin_id)
 {
   struct PostgresClosure *pc = cls;
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_auto_from_type (coin_pub),
+    GNUNET_PQ_query_param_auto_from_type (denom_pub_hash),
     GNUNET_PQ_query_param_end
   };
   struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
-                                          &coin_info->denom_pub_hash),
-    GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
-                                         &coin_info->denom_sig.rsa_signature),
+    GNUNET_PQ_result_spec_uint64 ("known_coin_id",
+                                  known_coin_id),
     GNUNET_PQ_result_spec_end
   };
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Getting known coin data for coin %s\n",
               TALER_B2S (coin_pub));
-  coin_info->coin_pub = *coin_pub;
-  if (NULL == session)
-    session = postgres_get_session (pc);
-  if (NULL == session)
-    return GNUNET_DB_STATUS_HARD_ERROR;
-  return GNUNET_PQ_eval_prepared_singleton_select (session->conn,
-                                                   "get_known_coin",
-                                                   params,
-                                                   rs);
-}
-
-
-/**
- * Retrieve the denomination of a known coin.
- *
- * @param cls the plugin closure
- * @param session the database session handle
- * @param coin_pub the public key of the coin to search for
- * @param[out] denom_hash where to store the hash of the coins denomination
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_get_coin_denomination (
-  void *cls,
-  struct TALER_EXCHANGEDB_Session *session,
-  const struct TALER_CoinSpendPublicKeyP *coin_pub,
-  struct GNUNET_HashCode *denom_hash)
-{
-  struct PostgresClosure *pc = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (coin_pub),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
-                                          denom_hash),
-    GNUNET_PQ_result_spec_end
-  };
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Getting coin denomination of coin %s\n",
-              TALER_B2S (coin_pub));
   if (NULL == session)
     session = postgres_get_session (pc);
   if (NULL == session)
     return GNUNET_DB_STATUS_HARD_ERROR;
   return GNUNET_PQ_eval_prepared_singleton_select (session->conn,
-                                                   "get_coin_denomination",
+                                                   "check_known_coin",
                                                    params,
                                                    rs);
 }
@@ -3130,12 +3098,14 @@ postgres_get_coin_denomination (
  * @param cls plugin closure
  * @param session the shared database session
  * @param coin_info the public coin info
+ * @param[out] known_coin_id set to identifier of the coin in the database
  * @return query result status
  */
 static enum GNUNET_DB_QueryStatus
 insert_known_coin (void *cls,
                    struct TALER_EXCHANGEDB_Session *session,
-                   const struct TALER_CoinPublicInfo *coin_info)
+                   const struct TALER_CoinPublicInfo *coin_info,
+                   uint64_t *known_coin_id)
 {
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_auto_from_type (&coin_info->coin_pub),
@@ -3143,14 +3113,20 @@ insert_known_coin (void *cls,
     GNUNET_PQ_query_param_rsa_signature (coin_info->denom_sig.rsa_signature),
     GNUNET_PQ_query_param_end
   };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_uint64 ("known_coin_id",
+                                  known_coin_id),
+    GNUNET_PQ_result_spec_end
+  };
 
   (void) cls;
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Creating known coin %s\n",
               TALER_B2S (&coin_info->coin_pub));
-  return GNUNET_PQ_eval_prepared_non_select (session->conn,
-                                             "insert_known_coin",
-                                             params);
+  return GNUNET_PQ_eval_prepared_singleton_select (session->conn,
+                                                   "insert_known_coin",
+                                                   params,
+                                                   rs);
 }
 
 
@@ -3196,16 +3172,17 @@ postgres_count_known_coins (void *cls,
  * @param cls database connection plugin state
  * @param session database session
  * @param coin the coin that must be made known
+ * @param[out] known_coin_id set to identifier of the coin in the database
  * @return database transaction status, non-negative on success
  */
 static enum GNUNET_DB_QueryStatus
 postgres_ensure_coin_known (void *cls,
                             struct TALER_EXCHANGEDB_Session *session,
-                            const struct TALER_CoinPublicInfo *coin)
+                            const struct TALER_CoinPublicInfo *coin,
+                            uint64_t *known_coin_id)
 {
   struct PostgresClosure *pc = cls;
   enum GNUNET_DB_QueryStatus qs;
-  struct TALER_CoinPublicInfo known_coin;
 #if EXPLICIT_LOCKS
   struct GNUNET_PQ_QueryParam no_params[] = {
     GNUNET_PQ_query_param_end
@@ -3218,10 +3195,11 @@ postgres_ensure_coin_known (void *cls,
 #endif
 
   /* check if the coin is already known */
-  qs = postgres_get_known_coin (pc,
-                                session,
-                                &coin->coin_pub,
-                                &known_coin);
+  qs = postgres_check_known_coin (pc,
+                                  session,
+                                  &coin->coin_pub,
+                                  &coin->denom_pub_hash,
+                                  known_coin_id);
   if (0 > qs)
   {
     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
@@ -3229,14 +3207,14 @@ postgres_ensure_coin_known (void *cls,
   }
   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
   {
-    GNUNET_CRYPTO_rsa_signature_free (known_coin.denom_sig.rsa_signature);
     return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;   /* no change! */
   }
   GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs);
   /* if not known, insert it */
   qs = insert_known_coin (pc,
                           session,
-                          coin);
+                          coin,
+                          known_coin_id);
   if (0 >= qs)
   {
     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
@@ -3254,6 +3232,7 @@ postgres_ensure_coin_known (void *cls,
  * @param cls the `struct PostgresClosure` with the plugin-specific state
  * @param session connection to the database
  * @param exchange_timestamp time the exchange received the deposit request
+ * @param coin_id which coin is this about
  * @param deposit deposit information to store
  * @return query result status
  */
@@ -3261,10 +3240,11 @@ static enum GNUNET_DB_QueryStatus
 postgres_insert_deposit (void *cls,
                          struct TALER_EXCHANGEDB_Session *session,
                          struct GNUNET_TIME_Absolute exchange_timestamp,
+                         uint64_t coin_id,
                          const struct TALER_EXCHANGEDB_Deposit *deposit)
 {
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (&deposit->coin.coin_pub),
+    GNUNET_PQ_query_param_uint64 (&coin_id),
     TALER_PQ_query_param_amount (&deposit->amount_with_fee),
     TALER_PQ_query_param_absolute_time (&deposit->timestamp),
     TALER_PQ_query_param_absolute_time (&deposit->refund_deadline),
@@ -3301,10 +3281,11 @@ postgres_insert_deposit (void *cls,
 static enum GNUNET_DB_QueryStatus
 postgres_insert_refund (void *cls,
                         struct TALER_EXCHANGEDB_Session *session,
+                        uint64_t coin_id,
                         const struct TALER_EXCHANGEDB_Refund *refund)
 {
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (&refund->coin.coin_pub),
+    GNUNET_PQ_query_param_uint64 (&coin_id),
     GNUNET_PQ_query_param_auto_from_type (&refund->details.merchant_pub),
     GNUNET_PQ_query_param_auto_from_type (&refund->details.merchant_sig),
     GNUNET_PQ_query_param_auto_from_type (&refund->details.h_contract_terms),
@@ -3397,7 +3378,7 @@ get_refunds_cb (void *cls,
  *
  * @param cls closure of plugin
  * @param session database handle to use
- * @param coin_pub coin to get refunds for
+ * @param coin_id coin to get refunds for
  * @param merchant_pub merchant to get refunds for
  * @param h_contract contract (hash) to get refunds for
  * @param cb function to call for each refund found
@@ -3408,7 +3389,7 @@ static enum GNUNET_DB_QueryStatus
 postgres_select_refunds_by_coin (
   void *cls,
   struct TALER_EXCHANGEDB_Session *session,
-  const struct TALER_CoinSpendPublicKeyP *coin_pub,
+  uint64_t coin_id,
   const struct TALER_MerchantPublicKeyP *merchant_pub,
   const struct GNUNET_HashCode *h_contract,
   TALER_EXCHANGEDB_RefundCoinCallback cb,
@@ -3417,7 +3398,7 @@ postgres_select_refunds_by_coin (
   struct PostgresClosure *pg = cls;
   enum GNUNET_DB_QueryStatus qs;
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (coin_pub),
+    GNUNET_PQ_query_param_uint64 (&coin_id),
     GNUNET_PQ_query_param_auto_from_type (merchant_pub),
     GNUNET_PQ_query_param_auto_from_type (h_contract),
     GNUNET_PQ_query_param_end
@@ -3535,6 +3516,7 @@ postgres_get_melt_index (void *cls,
  *
  * @param cls the `struct PostgresClosure` with the plugin-specific state
  * @param session database handle to use
+ * @param coin_id which coin is the melt about
  * @param refresh_session session data to store
  * @return query status for the transaction
  */
@@ -3542,11 +3524,12 @@ static enum GNUNET_DB_QueryStatus
 postgres_insert_melt (
   void *cls,
   struct TALER_EXCHANGEDB_Session *session,
+  uint64_t coin_id,
   const struct TALER_EXCHANGEDB_Refresh *refresh_session)
 {
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_auto_from_type (&refresh_session->rc),
-    GNUNET_PQ_query_param_auto_from_type (&refresh_session->coin.coin_pub),
+    GNUNET_PQ_query_param_uint64 (&coin_id),
     GNUNET_PQ_query_param_auto_from_type (&refresh_session->coin_sig),
     TALER_PQ_query_param_amount (&refresh_session->amount_with_fee),
     GNUNET_PQ_query_param_uint32 (&refresh_session->noreveal_index),
@@ -4029,9 +4012,9 @@ struct CoinHistoryContext
   struct TALER_EXCHANGEDB_TransactionList *head;
 
   /**
-   * Public key of the coin we are building the history for.
+   * Unique ID of the coin we are building the history for.
    */
-  const struct TALER_CoinSpendPublicKeyP *coin_pub;
+  uint64_t known_coin_id;
 
   /**
    * Closure for all callbacks of this database plugin.
@@ -4281,6 +4264,8 @@ add_old_coin_recoup (void *cls,
     recoup = GNUNET_new (struct TALER_EXCHANGEDB_RecoupRefreshListEntry);
     {
       struct GNUNET_PQ_ResultSpec rs[] = {
+        GNUNET_PQ_result_spec_uint64 ("known_coin_id",
+                                      &recoup->coin_id),
         GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
                                               &recoup->coin.coin_pub),
         GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
@@ -4311,7 +4296,8 @@ add_old_coin_recoup (void *cls,
         chc->failed = true;
         return;
       }
-      recoup->old_coin_pub = *chc->coin_pub;
+      // recoup->old_coin_pub = *chc->coin_pub;
+      recoup->old_coin_id = chc->known_coin_id;
     }
     tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
     tl->next = chc->head;
@@ -4409,8 +4395,9 @@ add_coin_recoup_refresh (void *cls,
     recoup = GNUNET_new (struct TALER_EXCHANGEDB_RecoupRefreshListEntry);
     {
       struct GNUNET_PQ_ResultSpec rs[] = {
-        GNUNET_PQ_result_spec_auto_from_type ("old_coin_pub",
-                                              &recoup->old_coin_pub),
+        GNUNET_PQ_result_spec_auto_from_type ("old_known_coin_id",
+                                              &recoup->old_coin_id),
+        // GNUNET_PQ_result_spec_auto_from_type ("old_coin_pub", &recoup->old_coin_pub),
         GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
                                               &recoup->coin_sig),
         GNUNET_PQ_result_spec_auto_from_type ("coin_blind",
@@ -4419,6 +4406,8 @@ add_coin_recoup_refresh (void *cls,
                                      &recoup->value),
         TALER_PQ_result_spec_absolute_time ("timestamp",
                                             &recoup->timestamp),
+        GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
+                                              &recoup->coin.coin_pub),
         GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
                                               &recoup->coin.denom_pub_hash),
         GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
@@ -4439,7 +4428,7 @@ add_coin_recoup_refresh (void *cls,
         chc->failed = true;
         return;
       }
-      recoup->coin.coin_pub = *chc->coin_pub;
+      recoup->coin_id = chc->known_coin_id;
     }
     tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
     tl->next = chc->head;
@@ -4474,7 +4463,7 @@ struct Work
  *
  * @param cls the `struct PostgresClosure` with the plugin-specific state
  * @param session database connection
- * @param coin_pub coin to investigate
+ * @param known_coin_id which coin to investigate
  * @param include_recoup should recoup transactions be included in the @a tlp
  * @param[out] tlp set to list of transactions, NULL if coin is fresh
  * @return database transaction status
@@ -4483,7 +4472,7 @@ static enum GNUNET_DB_QueryStatus
 postgres_get_coin_transactions (
   void *cls,
   struct TALER_EXCHANGEDB_Session *session,
-  const struct TALER_CoinSpendPublicKeyP *coin_pub,
+  uint64_t known_coin_id,
   int include_recoup,
   struct TALER_EXCHANGEDB_TransactionList **tlp)
 {
@@ -4522,23 +4511,20 @@ postgres_get_coin_transactions (
     { NULL, NULL }
   };
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (coin_pub),
+    GNUNET_PQ_query_param_uint64 (&known_coin_id),
     GNUNET_PQ_query_param_end
   };
   enum GNUNET_DB_QueryStatus qs;
   const struct Work *work;
   struct CoinHistoryContext chc = {
     .head = NULL,
-    .coin_pub = coin_pub,
+    .known_coin_id = known_coin_id, // FIXME: needed where?
     .session = session,
     .pg = pg,
     .db_cls = cls
   };
 
   work = (GNUNET_YES == include_recoup) ? work_wp : work_op;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Getting transactions for coin %s\n",
-              TALER_B2S (coin_pub));
   for (unsigned int i = 0; NULL != work[i].statement; i++)
   {
     qs = GNUNET_PQ_eval_prepared_multi_select (session->conn,
@@ -6844,6 +6830,7 @@ postgres_select_reserve_closed_above_serial_id (
  * @param cls closure
  * @param session database connection
  * @param reserve_pub public key of the reserve that is being refunded
+ * @param coin_id unique identifier of the recouped coin
  * @param coin information about the coin
  * @param coin_sig signature of the coin of type #TALER_SIGNATURE_WALLET_COIN_RECOUP
  * @param coin_blind blinding key of the coin
@@ -6857,7 +6844,7 @@ postgres_insert_recoup_request (
   void *cls,
   struct TALER_EXCHANGEDB_Session *session,
   const struct TALER_ReservePublicKeyP *reserve_pub,
-  const struct TALER_CoinPublicInfo *coin,
+  uint64_t coin_id,
   const struct TALER_CoinSpendSignatureP *coin_sig,
   const struct TALER_DenominationBlindingKeyP *coin_blind,
   const struct TALER_Amount *amount,
@@ -6868,7 +6855,7 @@ postgres_insert_recoup_request (
   struct GNUNET_TIME_Absolute expiry;
   struct TALER_EXCHANGEDB_Reserve reserve;
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (&coin->coin_pub),
+    GNUNET_PQ_query_param_uint64 (&coin_id),
     GNUNET_PQ_query_param_auto_from_type (coin_sig),
     GNUNET_PQ_query_param_auto_from_type (coin_blind),
     TALER_PQ_query_param_amount (amount),
@@ -6936,7 +6923,7 @@ postgres_insert_recoup_request (
  *
  * @param cls closure
  * @param session database connection
- * @param coin public information about the refreshed coin
+ * @param coin_id unique identifier of the recoup-refreshed coin
  * @param coin_sig signature of the coin of type #TALER_SIGNATURE_WALLET_COIN_RECOUP
  * @param coin_blind blinding key of the coin
  * @param h_blind_ev blinded envelope, as calculated by the exchange
@@ -6949,7 +6936,7 @@ static enum GNUNET_DB_QueryStatus
 postgres_insert_recoup_refresh_request (
   void *cls,
   struct TALER_EXCHANGEDB_Session *session,
-  const struct TALER_CoinPublicInfo *coin,
+  uint64_t coin_id,
   const struct TALER_CoinSpendSignatureP *coin_sig,
   const struct TALER_DenominationBlindingKeyP *coin_blind,
   const struct TALER_Amount *amount,
@@ -6957,7 +6944,7 @@ postgres_insert_recoup_refresh_request (
   struct GNUNET_TIME_Absolute timestamp)
 {
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (&coin->coin_pub),
+    GNUNET_PQ_query_param_uint64 (&coin_id),
     GNUNET_PQ_query_param_auto_from_type (coin_sig),
     GNUNET_PQ_query_param_auto_from_type (coin_blind),
     TALER_PQ_query_param_amount (amount),
@@ -7339,8 +7326,7 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
   plugin->free_reserve_history = &common_free_reserve_history;
   plugin->count_known_coins = &postgres_count_known_coins;
   plugin->ensure_coin_known = &postgres_ensure_coin_known;
-  plugin->get_known_coin = &postgres_get_known_coin;
-  plugin->get_coin_denomination = &postgres_get_coin_denomination;
+  plugin->check_known_coin = &postgres_check_known_coin;
   plugin->have_deposit = &postgres_have_deposit;
   plugin->mark_deposit_tiny = &postgres_mark_deposit_tiny;
   plugin->test_deposit_done = &postgres_test_deposit_done;
diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c
index 043095e7..714aaa7d 100644
--- a/src/exchangedb/test_exchangedb.c
+++ b/src/exchangedb/test_exchangedb.c
@@ -516,6 +516,7 @@ test_melting (struct TALER_EXCHANGEDB_Session *session)
   int ret;
   enum GNUNET_DB_QueryStatus qs;
   struct GNUNET_TIME_Absolute now;
+  uint64_t coin_id;
 
   ret = GNUNET_SYSERR;
   RND_BLK (&refresh_session);
@@ -562,10 +563,12 @@ test_melting (struct TALER_EXCHANGEDB_Session *session)
   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->ensure_coin_known (plugin->cls,
                                      session,
-                                     &refresh_session.coin));
+                                     &refresh_session.coin,
+                                     &coin_id));
   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->insert_melt (plugin->cls,
                                session,
+                               coin_id,
                                &refresh_session));
   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->get_melt (plugin->cls,
@@ -581,9 +584,11 @@ test_melting (struct TALER_EXCHANGEDB_Session *session)
           TALER_amount_cmp (&fee_refresh,
                             &ret_refresh_session.melt_fee));
   FAILIF (0 !=
-          GNUNET_memcmp (&refresh_session.rc, &ret_refresh_session.session.rc));
-  FAILIF (0 != GNUNET_memcmp (&refresh_session.coin_sig,
-                              &ret_refresh_session.session.coin_sig));
+          GNUNET_memcmp (&refresh_session.rc,
+                         &ret_refresh_session.session.rc));
+  FAILIF (0 !=
+          GNUNET_memcmp (&refresh_session.coin_sig,
+                         &ret_refresh_session.session.coin_sig));
   FAILIF (NULL !=
           ret_refresh_session.session.coin.denom_sig.rsa_signature);
   FAILIF (0 != memcmp (&refresh_session.coin.coin_pub,
@@ -680,7 +685,7 @@ test_melting (struct TALER_EXCHANGEDB_Session *session)
 
     qs = plugin->get_coin_transactions (plugin->cls,
                                         session,
-                                        &refresh_session.coin.coin_pub,
+                                        coin_id,
                                         GNUNET_YES,
                                         &tl);
     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs);
@@ -1521,6 +1526,7 @@ run (void *cls)
   uint64_t rr;
   enum GNUNET_DB_QueryStatus qs;
   struct GNUNET_TIME_Absolute now;
+  uint64_t coin_id;
 
   dkp = NULL;
   rh = NULL;
@@ -1708,7 +1714,8 @@ run (void *cls)
   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->ensure_coin_known (plugin->cls,
                                      session,
-                                     &deposit.coin));
+                                     &deposit.coin,
+                                     &coin_id));
   {
     struct TALER_EXCHANGEDB_Reserve pre_reserve;
     struct TALER_EXCHANGEDB_Reserve post_reserve;
@@ -1723,7 +1730,7 @@ run (void *cls)
             plugin->insert_recoup_request (plugin->cls,
                                            session,
                                            &reserve_pub,
-                                           &deposit.coin,
+                                           coin_id,
                                            &coin_sig,
                                            &coin_blind,
                                            &value,
@@ -1883,7 +1890,8 @@ run (void *cls)
   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->ensure_coin_known (plugin->cls,
                                      session,
-                                     &deposit.coin));
+                                     &deposit.coin,
+                                     &coin_id));
   {
     struct GNUNET_TIME_Absolute now;
     struct GNUNET_TIME_Absolute r;
@@ -1895,10 +1903,12 @@ run (void *cls)
             plugin->insert_deposit (plugin->cls,
                                     session,
                                     now,
+                                    coin_id,
                                     &deposit));
     FAILIF (1 !=
             plugin->have_deposit (plugin->cls,
                                   session,
+                                  coin_id,
                                   &deposit,
                                   GNUNET_YES,
                                   &deposit_fee,
@@ -1975,7 +1985,7 @@ run (void *cls)
   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
           plugin->test_deposit_done (plugin->cls,
                                      session,
-                                     &deposit.coin.coin_pub,
+                                     coin_id,
                                      &deposit.merchant_pub,
                                      &deposit.h_contract_terms,
                                      &deposit.h_wire));
@@ -1989,7 +1999,7 @@ run (void *cls)
   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->test_deposit_done (plugin->cls,
                                      session,
-                                     &deposit.coin.coin_pub,
+                                     coin_id,
                                      &deposit.merchant_pub,
                                      &deposit.h_contract_terms,
                                      &deposit.h_wire));
@@ -2004,19 +2014,27 @@ run (void *cls)
   {
     struct GNUNET_TIME_Absolute r;
     struct TALER_Amount deposit_fee;
+    uint64_t coin_id2;
 
     FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
             plugin->have_deposit (plugin->cls,
                                   session,
+                                  coin_id,
                                   &deposit2,
                                   GNUNET_YES,
                                   &deposit_fee,
                                   &r));
     deposit2.merchant_pub = deposit.merchant_pub;
     RND_BLK (&deposit2.coin.coin_pub); /* should fail if coin is different */
+    FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+            plugin->ensure_coin_known (plugin->cls,
+                                       session,
+                                       &deposit2.coin,
+                                       &coin_id2));
     FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
             plugin->have_deposit (plugin->cls,
                                   session,
+                                  coin_id2,
                                   &deposit2,
                                   GNUNET_YES,
                                   &deposit_fee,
@@ -2042,11 +2060,12 @@ run (void *cls)
   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->insert_refund (plugin->cls,
                                  session,
+                                 coin_id,
                                  &refund));
   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->select_refunds_by_coin (plugin->cls,
                                           session,
-                                          &refund.coin.coin_pub,
+                                          coin_id,
                                           &refund.details.merchant_pub,
                                           &refund.details.h_contract_terms,
                                           &check_refund_cb,
@@ -2102,7 +2121,7 @@ run (void *cls)
           plugin->insert_recoup_request (plugin->cls,
                                          session,
                                          &reserve_pub,
-                                         &deposit.coin,
+                                         coin_id,
                                          &coin_sig,
                                          &coin_blind,
                                          &value,
@@ -2120,7 +2139,7 @@ run (void *cls)
   FAILIF (1 != auditor_row_cnt);
   qs = plugin->get_coin_transactions (plugin->cls,
                                       session,
-                                      &refund.coin.coin_pub,
+                                      coin_id,
                                       GNUNET_YES,
                                       &tl);
   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs);
diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h
index 9fb93236..c80e7e27 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -364,7 +364,12 @@ struct TALER_EXCHANGEDB_RecoupRefreshListEntry
    * Information about the coin that was paid back
    * (NOT the coin we are considering the history of!)
    */
-  struct TALER_CoinPublicInfo coin;
+  struct TALER_CoinPublicInfo coin; // FIXME: check that where 'coin' is used, 'coin_id' likely also must be used!
+
+  /**
+   * Unique ID of @e coin.
+   */
+  uint64_t coin_id;
 
   /**
    * Blinding factor supplied to prove to the exchange that
@@ -381,7 +386,12 @@ struct TALER_EXCHANGEDB_RecoupRefreshListEntry
   /**
    * Public key of the old coin that the refreshed coin was paid back to.
    */
-  struct TALER_CoinSpendPublicKeyP old_coin_pub;
+  // struct TALER_CoinSpendPublicKeyP old_coin_pub;
+
+  /**
+   * Unique ID of @e old_coin_pub.
+   */
+  uint64_t old_coin_id;
 
   /**
    * How much was the coin still worth at this time?
@@ -978,7 +988,7 @@ struct TALER_EXCHANGEDB_Session;
  * @param exchange_timestamp when did the exchange receive the deposit
  * @param wallet_timestamp when did the wallet sign the contract
  * @param merchant_pub public key of the merchant
- * @param coin_pub public key of the coin
+ * @param coin_pub public key of the coin // FIXME: not unique!
  * @param amount_with_fee amount that was deposited including fee
  * @param deposit_fee amount the exchange gets to keep as transaction fees
  * @param h_contract_terms hash of the proposal data known to merchant and customer
@@ -1029,7 +1039,7 @@ typedef void
  * @param exchange_timestamp when did the deposit happen
  * @param wallet_timestamp when did the contract happen
  * @param merchant_pub public key of the merchant
- * @param denom_pub denomination public key of @a coin_pub
+ * @param denom_pub denomination public key of @a coin_pub // FIXME: not unique!
  * @param coin_pub public key of the coin
  * @param coin_sig signature from the coin
  * @param amount_with_fee amount that was deposited including fee
@@ -1067,7 +1077,7 @@ typedef int
  *
  * @param cls closure
  * @param rowid unique serial ID for the refresh session in our DB
- * @param denom_pub denomination public key of @a coin_pub
+ * @param denom_pub denomination public key of @a coin_pub // FIXME: not unique!
  * @param coin_pub public key of the coin
  * @param coin_sig signature from the coin
  * @param amount_with_fee amount that was deposited including fee
@@ -1162,7 +1172,7 @@ typedef void
  *
  * @param cls closure
  * @param rowid unique serial ID for the refund in our DB
- * @param denom_pub denomination public key of @a coin_pub
+ * @param denom_pub denomination public key of @a coin_pub // FIXME: not unique
  * @param coin_pub public key of the coin
  * @param merchant_pub public key of the merchant
  * @param merchant_sig signature of the merchant
@@ -1281,7 +1291,7 @@ typedef void
  * @param account_details which account did the transfer go to?
  * @param exec_time execution time of the wire transfer (should be same for all callbacks with the same @e cls)
  * @param h_contract_terms which proposal was this payment about
- * @param denom_pub denomination of @a coin_pub
+ * @param denom_pub denomination of @a coin_pub // FIXME: not unique!
  * @param coin_pub which public key was this payment about
  * @param coin_value amount contributed by this coin in total (with fee)
  * @param coin_fee applicable fee for this coin
@@ -1351,7 +1361,7 @@ typedef int
  * @param timestamp when did we receive the recoup request
  * @param amount how much should be added back to the reserve
  * @param reserve_pub public key of the reserve
- * @param coin public information about the coin
+ * @param coin public information about the coin // FIXME: unique???
  * @param denom_pub denomination key of @a coin
  * @param coin_sig signature with @e coin_pub of type #TALER_SIGNATURE_WALLET_COIN_RECOUP
  * @param coin_blind blinding factor used to blind the coin
@@ -1378,7 +1388,7 @@ typedef int
  * @param rowid row identifier used to uniquely identify the recoup operation
  * @param timestamp when did we receive the recoup request
  * @param amount how much should be added back to the reserve
- * @param old_coin_pub original coin that was refreshed to create @a coin
+ * @param old_coin_pub original coin that was refreshed to create @a coin // FIXME: not unique!
  * @param old_denom_pub_hash hash of public key of @a old_coin_pub
  * @param coin public information about the coin
  * @param denom_pub denomination key of @a coin
@@ -1474,7 +1484,7 @@ typedef void
  *
  * @param cls closure
  * @param rowid deposit table row of the coin's deposit
- * @param coin_pub public key of the coin
+ * @param coin_pub public key of the coin // FIXME: not unique!
  * @param amount value of the deposit, including fee
  * @param wire where should the funds be wired, including 'url' in payto://-format
  * @param deadline what was the requested wire transfer deadline
@@ -1801,12 +1811,14 @@ struct TALER_EXCHANGEDB_Plugin
    * @param cls database connection plugin state
    * @param session database session
    * @param coin the coin that must be made known
+   * @param[out] known_coin_id set to identifier of the coin in the database
    * @return database transaction status, non-negative on success
    */
   enum GNUNET_DB_QueryStatus
   (*ensure_coin_known)(void *cls,
                        struct TALER_EXCHANGEDB_Session *session,
-                       const struct TALER_CoinPublicInfo *coin);
+                       const struct TALER_CoinPublicInfo *coin,
+                       uint64_t *known_coin_id);
 
 
   /**
@@ -1814,30 +1826,17 @@ struct TALER_EXCHANGEDB_Plugin
    *
    * @param cls database connection plugin state
    * @param session database session
-   * @param coin the coin that must be made known
-   * @return database transaction status, non-negative on success
-   */
-  enum GNUNET_DB_QueryStatus
-  (*get_known_coin)(void *cls,
-                    struct TALER_EXCHANGEDB_Session *session,
-                    const struct TALER_CoinSpendPublicKeyP *coin_pub,
-                    struct TALER_CoinPublicInfo *coin_info);
-
-
-  /**
-   * Retrieve the denomination of a known coin.
-   *
-   * @param cls the plugin closure
-   * @param session the database session handle
    * @param coin_pub the public key of the coin to search for
-   * @param[out] denom_hash where to store the hash of the coins denomination
-   * @return transaction status code
+   * @param denom_pub_hash hash of the denomination of the coin
+   * @param[out] known_coin_id identifier of the coin in the database
+   * @return database transaction status, non-negative on success
    */
   enum GNUNET_DB_QueryStatus
-  (*get_coin_denomination)(void *cls,
-                           struct TALER_EXCHANGEDB_Session *session,
-                           const struct TALER_CoinSpendPublicKeyP *coin_pub,
-                           struct GNUNET_HashCode *denom_hash);
+  (*check_known_coin)(void *cls,
+                      struct TALER_EXCHANGEDB_Session *session,
+                      const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                      const struct GNUNET_HashCode *denom_pub_hash,
+                      uint64_t *known_coin_id);
 
 
   /**
@@ -1845,6 +1844,7 @@ struct TALER_EXCHANGEDB_Plugin
    *
    * @param cls the @e cls of this struct with the plugin-specific state
    * @param session database connection
+   * @param coin_id which coin is this about
    * @param deposit deposit to search for
    * @param check_extras whether to check extra fields or not
    * @param[out] deposit_fee set to the deposit fee the exchange charged
@@ -1856,6 +1856,7 @@ struct TALER_EXCHANGEDB_Plugin
   enum GNUNET_DB_QueryStatus
   (*have_deposit)(void *cls,
                   struct TALER_EXCHANGEDB_Session *session,
+                  uint64_t coin_id,
                   const struct TALER_EXCHANGEDB_Deposit *deposit,
                   int check_extras,
                   struct TALER_Amount *deposit_fee,
@@ -1868,6 +1869,7 @@ struct TALER_EXCHANGEDB_Plugin
    * @param cls the @e cls of this struct with the plugin-specific state
    * @param session connection to the database
    * @param exchange_timestamp time the exchange received the deposit request
+   * @param coin_id which coin is this about
    * @param deposit deposit information to store
    * @return query result status
    */
@@ -1875,6 +1877,7 @@ struct TALER_EXCHANGEDB_Plugin
   (*insert_deposit)(void *cls,
                     struct TALER_EXCHANGEDB_Session *session,
                     struct GNUNET_TIME_Absolute exchange_timestamp,
+                    uint64_t coin_id,
                     const struct TALER_EXCHANGEDB_Deposit *deposit);
 
 
@@ -1883,21 +1886,23 @@ struct TALER_EXCHANGEDB_Plugin
    *
    * @param cls the @e cls of this struct with the plugin-specific state
    * @param session connection to the database
+   * @param coin_id which coin is this about
    * @param refund refund information to store
    * @return query result status
    */
   enum GNUNET_DB_QueryStatus
   (*insert_refund)(void *cls,
                    struct TALER_EXCHANGEDB_Session *session,
+                   uint64_t coin_id,
                    const struct TALER_EXCHANGEDB_Refund *refund);
 
 
   /**
-   * Select refunds by @a coin_pub, @a merchant_pub and @a h_contract.
+   * Select refunds by @a coin_id, @a merchant_pub and @a h_contract.
    *
    * @param cls closure of plugin
    * @param session database handle to use
-   * @param coin_pub coin to get refunds for
+   * @param coin_id coin to get refunds for
    * @param merchant_pub merchant to get refunds for
    * @param h_contract_pub contract (hash) to get refunds for
    * @param cb function to call for each refund found
@@ -1907,7 +1912,7 @@ struct TALER_EXCHANGEDB_Plugin
   enum GNUNET_DB_QueryStatus
   (*select_refunds_by_coin)(void *cls,
                             struct TALER_EXCHANGEDB_Session *session,
-                            const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                            uint64_t coin_id,
                             const struct TALER_MerchantPublicKeyP *merchant_pub,
                             const struct GNUNET_HashCode *h_contract,
                             TALER_EXCHANGEDB_RefundCoinCallback cb,
@@ -1936,7 +1941,7 @@ struct TALER_EXCHANGEDB_Plugin
    *
    * @param cls the @e cls of this struct with the plugin-specific state
    * @param session connection to the database
-   * @param coin_pub the coin to check for deposit
+   * @param coin_id the coin to check for deposit
    * @param merchant_pub merchant to receive the deposit
    * @param h_contract_terms contract terms of the deposit
    * @param h_wire hash of the merchant's wire details
@@ -1947,7 +1952,7 @@ struct TALER_EXCHANGEDB_Plugin
   enum GNUNET_DB_QueryStatus
   (*test_deposit_done)(void *cls,
                        struct TALER_EXCHANGEDB_Session *session,
-                       const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                       uint64_t coin_id,
                        const struct TALER_MerchantPublicKeyP *merchant_pub,
                        const struct GNUNET_HashCode *h_contract_terms,
                        const struct GNUNET_HashCode *h_wire);
@@ -2029,12 +2034,14 @@ struct TALER_EXCHANGEDB_Plugin
    *
    * @param cls the @e cls of this struct with the plugin-specific state
    * @param session database handle to use
+   * @param coin_id which coin is the melt about
    * @param refresh_session operational data to store
    * @return query status for the transaction
    */
   enum GNUNET_DB_QueryStatus
   (*insert_melt)(void *cls,
                  struct TALER_EXCHANGEDB_Session *session,
+                 uint64_t coin_id,
                  const struct TALER_EXCHANGEDB_Refresh *refresh_session);
 
 
@@ -2127,9 +2134,13 @@ struct TALER_EXCHANGEDB_Plugin
    * @e get_link_data_list() enable the owner of an old coin to determine
    * the private keys of the new coins after the melt.
    *
+   * Note that if multiple coins (of different denominations) share the
+   * same @a coin_pub, we simply return the link data associated with any of
+   * the coins.
+   *
    * @param cls the @e cls of this struct with the plugin-specific state
    * @param session database connection
-   * @param coin_pub public key of the coin
+   * @param coin_pub public key of the coin(s).
    * @param ldc function to call for each session the coin was melted into
    * @param ldc_cls closure for @a tdc
    * @return statement execution status
@@ -2148,7 +2159,7 @@ struct TALER_EXCHANGEDB_Plugin
    *
    * @param cls the @e cls of this struct with the plugin-specific state
    * @param session database connection
-   * @param coin_pub coin to investigate
+   * @param known_coin_id which coin to investigate
    * @param include_recoup include recoup transactions of the coin?
    * @param[out] tlp set to list of transactions, NULL if coin is fresh
    * @return database transaction status
@@ -2156,7 +2167,7 @@ struct TALER_EXCHANGEDB_Plugin
   enum GNUNET_DB_QueryStatus
   (*get_coin_transactions)(void *cls,
                            struct TALER_EXCHANGEDB_Session *session,
-                           const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                           uint64_t known_coin_id,
                            int include_recoup,
                            struct TALER_EXCHANGEDB_TransactionList **tlp);
 
@@ -2196,6 +2207,9 @@ struct TALER_EXCHANGEDB_Plugin
    * If we did not execute the deposit yet, return when it is supposed
    * to be executed.
    *
+   * FIXME: check it is OK to do this by coin_pub (merging results
+   * from all coins with different denominations sharing the same coin_pub).
+   *
    * @param cls closure
    * @param session database connection
    * @param h_contract_terms hash of the proposal data
@@ -2652,7 +2666,7 @@ struct TALER_EXCHANGEDB_Plugin
    * @param cls closure
    * @param session database connection
    * @param reserve_pub public key of the reserve that is being refunded
-   * @param coin public information about a coin
+   * @param coin_id unique identifier of the recouped coin
    * @param coin_sig signature of the coin of type #TALER_SIGNATURE_WALLET_COIN_RECOUP
    * @param coin_blind blinding key of the coin
    * @param h_blind_ev blinded envelope, as calculated by the exchange
@@ -2666,7 +2680,7 @@ struct TALER_EXCHANGEDB_Plugin
     void *cls,
     struct TALER_EXCHANGEDB_Session *session,
     const struct TALER_ReservePublicKeyP *reserve_pub,
-    const struct TALER_CoinPublicInfo *coin,
+    uint64_t coin_id,
     const struct TALER_CoinSpendSignatureP *coin_sig,
     const struct TALER_DenominationBlindingKeyP *coin_blind,
     const struct TALER_Amount *amount,
@@ -2680,7 +2694,7 @@ struct TALER_EXCHANGEDB_Plugin
    *
    * @param cls closure
    * @param session database connection
-   * @param coin public information about the refreshed coin
+   * @param coin_id unique identifier of the recoup-refreshed coin
    * @param coin_sig signature of the coin of type #TALER_SIGNATURE_WALLET_COIN_RECOUP
    * @param coin_blind blinding key of the coin
    * @param h_blind_ev blinded envelope, as calculated by the exchange
@@ -2693,7 +2707,7 @@ struct TALER_EXCHANGEDB_Plugin
   (*insert_recoup_refresh_request)(
     void *cls,
     struct TALER_EXCHANGEDB_Session *session,
-    const struct TALER_CoinPublicInfo *coin,
+    uint64_t coin_id,
     const struct TALER_CoinSpendSignatureP *coin_sig,
     const struct TALER_DenominationBlindingKeyP *coin_blind,
     const struct TALER_Amount *amount,
@@ -2728,6 +2742,7 @@ struct TALER_EXCHANGEDB_Plugin
    * @param[out] old_coin_pub set to information about the old coin (on success only)
    * @return transaction status code
    */
+  // FIXME: check use, likely bad: may need to return old_coin_id!
   enum GNUNET_DB_QueryStatus
   (*get_old_coin_by_h_blind)(void *cls,
                              struct TALER_EXCHANGEDB_Session *session,
