exchange_do_deposit.sql (6200B)
1 -- 2 -- This file is part of TALER 3 -- Copyright (C) 2014--2025 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 DROP FUNCTION IF EXISTS exchange_do_deposit; 18 CREATE FUNCTION exchange_do_deposit( 19 -- For batch_deposits 20 IN in_shard INT8, 21 IN in_merchant_pub BYTEA, 22 IN in_merchant_sig BYTEA, 23 IN in_wallet_timestamp INT8, 24 IN in_exchange_timestamp INT8, 25 IN in_refund_deadline INT8, 26 IN in_wire_deadline INT8, 27 IN in_h_contract_terms BYTEA, 28 IN in_wallet_data_hash BYTEA, -- can be NULL 29 IN in_wire_salt BYTEA, 30 IN in_wire_target_h_payto BYTEA, 31 IN in_h_normalized_payto BYTEA, 32 IN in_policy_details_serial_id INT8, -- can be NULL 33 IN in_policy_blocked BOOLEAN, 34 -- For wire_targets 35 IN in_receiver_wire_account TEXT, 36 -- For coin_deposits 37 IN ina_coin_pub BYTEA[], 38 IN ina_coin_sig BYTEA[], 39 IN ina_amount_with_fee taler_amount[], 40 IN in_total_amount taler_amount, 41 IN in_is_wallet BOOL, 42 OUT out_exchange_timestamp INT8, 43 OUT out_insufficient_balance_coin_index INT4, -- index of coin with bad balance, NULL if none 44 OUT out_conflict BOOL 45 ) 46 LANGUAGE plpgsql 47 AS $$ 48 DECLARE 49 wtsi INT8; -- wire target serial id 50 bdsi INT8; -- batch_deposits serial id 51 i INT4; 52 ini_amount_with_fee taler_amount; 53 ini_coin_pub BYTEA; 54 ini_coin_sig BYTEA; 55 BEGIN 56 -- Shards: 57 -- INSERT wire_targets (by h_payto), ON CONFLICT DO NOTHING; 58 -- INSERT batch_deposits (by shard, merchant_pub), ON CONFLICT idempotency check; 59 -- INSERT[] coin_deposits (by coin_pub), ON CONFLICT idempotency check; 60 -- UPDATE[] known_coins (by coin_pub) 61 62 63 -- Make sure the kyc_target entry exists 64 INSERT INTO kyc_targets 65 (h_normalized_payto 66 ,is_wallet 67 ) VALUES ( 68 in_h_normalized_payto 69 ,in_is_wallet 70 ) 71 ON CONFLICT DO NOTHING; 72 73 -- First, get or create the 'wtsi' 74 INSERT INTO wire_targets 75 (wire_target_h_payto 76 ,h_normalized_payto 77 ,payto_uri 78 ) VALUES ( 79 in_wire_target_h_payto 80 ,in_h_normalized_payto 81 ,in_receiver_wire_account 82 ) 83 ON CONFLICT DO NOTHING -- for CONFLICT ON (wire_target_h_payto) 84 RETURNING wire_target_serial_id 85 INTO wtsi; 86 87 IF NOT FOUND 88 THEN 89 SELECT wire_target_serial_id 90 INTO wtsi 91 FROM wire_targets 92 WHERE wire_target_h_payto=in_wire_target_h_payto; 93 END IF; 94 95 96 -- Second, create the batch_deposits entry 97 INSERT INTO batch_deposits 98 (shard 99 ,merchant_pub 100 ,merchant_sig 101 ,wallet_timestamp 102 ,exchange_timestamp 103 ,refund_deadline 104 ,wire_deadline 105 ,h_contract_terms 106 ,wallet_data_hash 107 ,wire_salt 108 ,wire_target_h_payto 109 ,policy_details_serial_id 110 ,policy_blocked 111 ,total_amount 112 ) VALUES ( 113 in_shard 114 ,in_merchant_pub 115 ,in_merchant_sig 116 ,in_wallet_timestamp 117 ,in_exchange_timestamp 118 ,in_refund_deadline 119 ,in_wire_deadline 120 ,in_h_contract_terms 121 ,in_wallet_data_hash 122 ,in_wire_salt 123 ,in_wire_target_h_payto 124 ,in_policy_details_serial_id 125 ,in_policy_blocked 126 ,in_total_amount) 127 ON CONFLICT DO NOTHING -- for CONFLICT ON (merchant_pub, h_contract_terms) 128 RETURNING 129 batch_deposit_serial_id 130 INTO 131 bdsi; 132 133 IF NOT FOUND 134 THEN 135 -- Idempotency check: see if an identical record exists. 136 -- We do select over merchant_pub, h_contract_terms and wire_target_h_payto 137 -- first to maximally increase the chance of using the existing index. 138 SELECT 139 exchange_timestamp 140 ,batch_deposit_serial_id 141 INTO 142 out_exchange_timestamp 143 ,bdsi 144 FROM batch_deposits 145 WHERE shard=in_shard 146 AND merchant_pub=in_merchant_pub 147 AND h_contract_terms=in_h_contract_terms 148 AND wire_target_h_payto=in_wire_target_h_payto 149 -- now check the rest, too 150 AND ( (wallet_data_hash=in_wallet_data_hash) OR 151 (wallet_data_hash IS NULL AND in_wallet_data_hash IS NULL) ) 152 AND wire_salt=in_wire_salt 153 AND wallet_timestamp=in_wallet_timestamp 154 AND refund_deadline=in_refund_deadline 155 AND wire_deadline=in_wire_deadline 156 AND ( (policy_details_serial_id=in_policy_details_serial_id) OR 157 (policy_details_serial_id IS NULL AND in_policy_details_serial_id IS NULL) ); 158 IF NOT FOUND 159 THEN 160 -- Deposit exists, but with *strange* differences. Not allowed. 161 out_conflict=TRUE; 162 RETURN; 163 END IF; 164 END IF; 165 166 out_conflict=FALSE; 167 168 -- Deposit each coin 169 170 FOR i IN 1..array_length(ina_coin_pub,1) 171 LOOP 172 ini_coin_pub = ina_coin_pub[i]; 173 ini_coin_sig = ina_coin_sig[i]; 174 ini_amount_with_fee = ina_amount_with_fee[i]; 175 176 INSERT INTO coin_deposits 177 (batch_deposit_serial_id 178 ,coin_pub 179 ,coin_sig 180 ,amount_with_fee 181 ) VALUES ( 182 bdsi 183 ,ini_coin_pub 184 ,ini_coin_sig 185 ,ini_amount_with_fee 186 ) 187 ON CONFLICT DO NOTHING; 188 189 IF FOUND 190 THEN 191 -- Insert did happen, update balance in known_coins! 192 193 UPDATE known_coins kc 194 SET 195 remaining.frac=(kc.remaining).frac-ini_amount_with_fee.frac 196 + CASE 197 WHEN (kc.remaining).frac < ini_amount_with_fee.frac 198 THEN 100000000 199 ELSE 0 200 END, 201 remaining.val=(kc.remaining).val-ini_amount_with_fee.val 202 - CASE 203 WHEN (kc.remaining).frac < ini_amount_with_fee.frac 204 THEN 1 205 ELSE 0 206 END 207 WHERE coin_pub=ini_coin_pub 208 AND ( ((kc.remaining).val > ini_amount_with_fee.val) OR 209 ( ((kc.remaining).frac >= ini_amount_with_fee.frac) AND 210 ((kc.remaining).val >= ini_amount_with_fee.val) ) ); 211 212 IF NOT FOUND 213 THEN 214 -- Insufficient balance. 215 -- Note: C arrays are 0 indexed, but i started at 1 216 out_insufficient_balance_coin_index=i-1; 217 RETURN; 218 END IF; 219 END IF; 220 END LOOP; -- end FOR all coins 221 222 END $$;