exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

do_recoup.sql (4242B)


      1 --
      2 -- This file is part of TALER
      3 -- Copyright (C) 2014--2022 Taler Systems SA
      4 --
      5 -- TALER is free software; you can redistribute it and/or modify it under the
      6 -- terms of the GNU General Public License as published by the Free Software
      7 -- Foundation; either version 3, or (at your option) any later version.
      8 --
      9 -- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10 -- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11 -- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
     12 --
     13 -- You should have received a copy of the GNU General Public License along with
     14 -- TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 --
     16 
     17 -- When parameter names have changed, we can not REPLACE
     18 -- but need to drop first
     19 DROP FUNCTION IF EXISTS exchange_do_recoup_to_reserve;
     20 
     21 CREATE FUNCTION exchange_do_recoup_to_reserve(
     22   IN in_reserve_pub BYTEA,
     23   IN in_withdraw_id INT8,
     24   IN in_coin_index INT4,
     25   IN in_coin_blind BYTEA,
     26   IN in_coin_pub BYTEA,
     27   IN in_known_coin_id INT8,
     28   IN in_coin_sig BYTEA,
     29   IN in_reserve_gc INT8,
     30   IN in_reserve_expiration INT8,
     31   IN in_recoup_timestamp INT8,
     32   OUT out_recoup_ok BOOLEAN,
     33   OUT out_internal_failure BOOLEAN,
     34   OUT out_recoup_timestamp INT8,
     35   OUT out_recoup_amount taler_amount)
     36 LANGUAGE plpgsql
     37 AS $$
     38 DECLARE
     39   tmp taler_amount; -- amount recouped
     40   balance taler_amount; -- current balance of the reserve
     41   new_balance taler_amount; -- new balance of the reserve
     42   reserve RECORD;
     43   rval RECORD;
     44 BEGIN
     45 -- Shards: SELECT known_coins (by coin_pub)
     46 --         SELECT recoup      (by coin_pub)
     47 --         UPDATE known_coins (by coin_pub)
     48 --         UPDATE reserves (by reserve_pub)
     49 --         INSERT recoup      (by coin_pub)
     50 
     51 out_internal_failure=FALSE;
     52 
     53 
     54 -- Check remaining balance of the coin.
     55 SELECT
     56    remaining
     57  INTO
     58    rval
     59 FROM exchange.known_coins
     60   WHERE coin_pub=in_coin_pub;
     61 
     62 IF NOT FOUND
     63 THEN
     64   out_internal_failure=TRUE;
     65   out_recoup_ok=FALSE;
     66   RETURN;
     67 END IF;
     68 
     69 tmp := rval.remaining;
     70 
     71 IF tmp.val + tmp.frac = 0
     72 THEN
     73   -- Check for idempotency: only a recoup for this very
     74   -- withdraw operation and position counts, a recoup of the same
     75   -- coin for another operation means the coin has nothing left.
     76   -- The coin may have been credited again (by a refund) and
     77   -- recouped again since, so report the latest recoup.
     78   SELECT
     79      recoup_timestamp
     80     ,amount
     81   INTO
     82     rval
     83     FROM exchange.recoup
     84     WHERE coin_pub=in_coin_pub
     85       AND withdraw_id=in_withdraw_id
     86       AND coin_index=in_coin_index
     87     ORDER BY recoup_uuid DESC
     88     LIMIT 1;
     89 
     90   out_recoup_ok=FOUND;
     91   IF FOUND
     92   THEN
     93     out_recoup_timestamp=rval.recoup_timestamp;
     94     out_recoup_amount=rval.amount;
     95   END IF;
     96   RETURN;
     97 END IF;
     98 
     99 
    100 -- Update balance of the coin.
    101 UPDATE known_coins
    102   SET
    103      remaining.val = 0
    104     ,remaining.frac = 0
    105   WHERE coin_pub=in_coin_pub;
    106 
    107 -- Get current balance
    108 SELECT current_balance
    109   INTO reserve
    110   FROM reserves
    111  WHERE reserve_pub=in_reserve_pub;
    112 
    113 balance = reserve.current_balance;
    114 new_balance.frac=balance.frac+tmp.frac
    115    - CASE
    116      WHEN balance.frac+tmp.frac >= 100000000
    117      THEN 100000000
    118      ELSE 0
    119      END;
    120 
    121 new_balance.val=balance.val+tmp.val
    122    + CASE
    123      WHEN balance.frac+tmp.frac >= 100000000
    124      THEN 1
    125      ELSE 0
    126      END;
    127 
    128 -- Credit the reserve and update reserve timers.
    129 UPDATE reserves
    130   SET
    131     current_balance = new_balance,
    132     gc_date=GREATEST(gc_date, in_reserve_gc),
    133     expiration_date=GREATEST(expiration_date, in_reserve_expiration)
    134   WHERE reserve_pub=in_reserve_pub;
    135 
    136 
    137 IF NOT FOUND
    138 THEN
    139   RAISE NOTICE 'failed to increase reserve balance from recoup';
    140   out_recoup_ok=TRUE;
    141   out_internal_failure=TRUE;
    142   RETURN;
    143 END IF;
    144 
    145 
    146 INSERT INTO exchange.recoup
    147   (coin_pub
    148   ,coin_sig
    149   ,coin_blind
    150   ,amount
    151   ,recoup_timestamp
    152   ,withdraw_id
    153   ,coin_index
    154   )
    155 VALUES
    156   (in_coin_pub
    157   ,in_coin_sig
    158   ,in_coin_blind
    159   ,tmp
    160   ,in_recoup_timestamp
    161   ,in_withdraw_id
    162   ,in_coin_index);
    163 
    164 -- Normal end, everything is fine.
    165 out_recoup_ok=TRUE;
    166 out_recoup_timestamp=in_recoup_timestamp;
    167 out_recoup_amount=tmp;
    168 
    169 END $$;
    170 
    171 -- COMMENT ON FUNCTION exchange_do_recoup_to_reserve(INT8, INT4, BYTEA, BOOLEAN, BOOLEAN)
    172 --  IS 'Executes a recoup of a coin that was withdrawn from a reserve';