exchange

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

exchange_do_reserve_open.sql (5946B)


      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 CREATE OR REPLACE FUNCTION exchange_do_reserve_open(
     18   IN in_reserve_pub BYTEA,
     19   IN in_total_paid taler_amount,
     20   IN in_reserve_payment taler_amount,
     21   IN in_min_purse_limit INT4,
     22   IN in_default_purse_limit INT4,
     23   IN in_reserve_sig BYTEA,
     24   IN in_desired_expiration INT8,
     25   IN in_reserve_gc_delay INT8,
     26   IN in_now INT8,
     27   IN in_open_fee taler_amount,
     28   OUT out_open_cost taler_amount,
     29   OUT out_final_expiration INT8,
     30   OUT out_no_reserve BOOLEAN,
     31   OUT out_no_funds BOOLEAN,
     32   OUT out_reserve_balance taler_amount)
     33 LANGUAGE plpgsql
     34 AS $$
     35 DECLARE
     36   my_balance taler_amount;
     37   my_cost taler_amount;
     38   my_cost_tmp INT8;
     39   my_years_tmp INT4;
     40   my_years INT4;
     41   my_needs_update BOOL;
     42   my_expiration_date INT8;
     43   reserve RECORD;
     44 BEGIN
     45 
     46 SELECT current_balance
     47       ,expiration_date
     48       ,purses_allowed
     49   INTO reserve
     50   FROM reserves
     51  WHERE reserve_pub=in_reserve_pub;
     52 
     53 IF NOT FOUND
     54 THEN
     55   RAISE NOTICE 'reserve not found';
     56   out_no_reserve = TRUE;
     57   out_no_funds = TRUE;
     58   out_reserve_balance.val = 0;
     59   out_reserve_balance.frac = 0;
     60   out_open_cost.val = 0;
     61   out_open_cost.frac = 0;
     62   out_final_expiration = 0;
     63   RETURN;
     64 END IF;
     65 
     66 out_no_reserve = FALSE;
     67 out_reserve_balance = reserve.current_balance;
     68 
     69 -- Do not allow expiration time to start in the past already
     70 IF (reserve.expiration_date < in_now)
     71 THEN
     72   my_expiration_date = in_now;
     73 ELSE
     74   my_expiration_date = reserve.expiration_date;
     75 END IF;
     76 
     77 my_cost.val = 0;
     78 my_cost.frac = 0;
     79 my_needs_update = FALSE;
     80 my_years = 0;
     81 
     82 -- Compute years based on desired expiration time
     83 IF (my_expiration_date < in_desired_expiration)
     84 THEN
     85   my_years = (31535999999999 + in_desired_expiration - my_expiration_date) / 31536000000000;
     86   reserve.purses_allowed = in_default_purse_limit;
     87   my_expiration_date = my_expiration_date + 31536000000000 * my_years;
     88 END IF;
     89 
     90 -- Increase years based on purses requested
     91 IF (reserve.purses_allowed < in_min_purse_limit)
     92 THEN
     93   my_years = (31535999999999 + in_desired_expiration - in_now) / 31536000000000;
     94   my_expiration_date = in_now + 31536000000000 * my_years;
     95   my_years_tmp = (in_min_purse_limit + in_default_purse_limit - reserve.purses_allowed - 1) / in_default_purse_limit;
     96   my_years = my_years + my_years_tmp;
     97   reserve.purses_allowed = reserve.purses_allowed + (in_default_purse_limit * my_years_tmp);
     98 END IF;
     99 
    100 
    101 -- Compute cost based on annual fees
    102 IF (my_years > 0)
    103 THEN
    104   my_cost.val = my_years * in_open_fee.val;
    105   my_cost_tmp = my_years * in_open_fee.frac / 100000000;
    106   IF (CAST (my_cost.val + my_cost_tmp AS INT8) < my_cost.val)
    107   THEN
    108     out_open_cost.val=9223372036854775807;
    109     out_open_cost.frac=2147483647;
    110     out_final_expiration=my_expiration_date;
    111     out_no_funds=FALSE;
    112     RAISE NOTICE 'arithmetic issue computing amount';
    113   RETURN;
    114   END IF;
    115   my_cost.val = CAST (my_cost.val + my_cost_tmp AS INT8);
    116   my_cost.frac = my_years * in_open_fee.frac % 100000000;
    117   my_needs_update = TRUE;
    118 END IF;
    119 
    120 -- check if we actually have something to do
    121 IF NOT my_needs_update
    122 THEN
    123   out_final_expiration = reserve.expiration_date;
    124   out_open_cost.val = 0;
    125   out_open_cost.frac = 0;
    126   out_no_funds=FALSE;
    127   RAISE NOTICE 'no change required';
    128   RETURN;
    129 END IF;
    130 
    131 -- Check payment (coins and reserve) would be sufficient.
    132 IF ( (in_total_paid.val < my_cost.val) OR
    133      ( (in_total_paid.val = my_cost.val) AND
    134        (in_total_paid.frac < my_cost.frac) ) )
    135 THEN
    136   out_open_cost.val = my_cost.val;
    137   out_open_cost.frac = my_cost.frac;
    138   out_no_funds=FALSE;
    139   -- We must return a failure, which is indicated by
    140   -- the expiration being below the desired expiration.
    141   IF (reserve.expiration_date >= in_desired_expiration)
    142   THEN
    143     -- This case is relevant especially if the purse
    144     -- count was to be increased and the payment was
    145     -- insufficient to cover this for the full period.
    146     RAISE NOTICE 'forcing low expiration time';
    147     out_final_expiration = 0;
    148   ELSE
    149     out_final_expiration = reserve.expiration_date;
    150   END IF;
    151   RAISE NOTICE 'amount paid too low';
    152   RETURN;
    153 END IF;
    154 
    155 -- Check reserve balance is sufficient.
    156 IF (out_reserve_balance.val > in_reserve_payment.val)
    157 THEN
    158   IF (out_reserve_balance.frac >= in_reserve_payment.frac)
    159   THEN
    160     my_balance.val=out_reserve_balance.val - in_reserve_payment.val;
    161     my_balance.frac=out_reserve_balance.frac - in_reserve_payment.frac;
    162   ELSE
    163     my_balance.val=out_reserve_balance.val - in_reserve_payment.val - 1;
    164     my_balance.frac=out_reserve_balance.frac + 100000000 - in_reserve_payment.frac;
    165   END IF;
    166 ELSE
    167   IF (out_reserve_balance.val = in_reserve_payment.val) AND (out_reserve_balance.frac >= in_reserve_payment.frac)
    168   THEN
    169     my_balance.val=0;
    170     my_balance.frac=out_reserve_balance.frac - in_reserve_payment.frac;
    171   ELSE
    172     out_final_expiration = reserve.expiration_date;
    173     out_open_cost.val = my_cost.val;
    174     out_open_cost.frac = my_cost.frac;
    175     out_no_funds=TRUE;
    176     RAISE NOTICE 'reserve balance too low';
    177   RETURN;
    178   END IF;
    179 END IF;
    180 
    181 UPDATE reserves SET
    182   current_balance=my_balance
    183  ,gc_date=reserve.expiration_date + in_reserve_gc_delay
    184  ,expiration_date=my_expiration_date
    185  ,purses_allowed=reserve.purses_allowed
    186 WHERE
    187  reserve_pub=in_reserve_pub;
    188 
    189 out_final_expiration=my_expiration_date;
    190 out_open_cost = my_cost;
    191 out_no_funds=FALSE;
    192 RETURN;
    193 
    194 END $$;