1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
|
--
-- This file is part of TALER
-- Copyright (C) 2024 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
-- Foundation; either version 3, or (at your option) any later version.
--
-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along with
-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
--
CREATE OR REPLACE FUNCTION merchant_do_insert_transfer_details (
IN in_instance_id TEXT,
IN in_exchange_url TEXT,
IN in_payto_uri TEXT,
IN in_wtid BYTEA,
IN in_execution_time INT8,
IN in_exchange_pub BYTEA,
IN in_exchange_sig BYTEA,
IN in_total_amount taler_amount_currency,
IN in_wire_fee taler_amount_currency,
IN ina_coin_values taler_amount_currency[],
IN ina_deposit_fees taler_amount_currency[],
IN ina_coin_pubs BYTEA[],
IN ina_contract_terms BYTEA[],
OUT out_no_instance BOOL,
OUT out_no_account BOOL,
OUT out_no_exchange BOOL,
OUT out_duplicate BOOL,
OUT out_conflict BOOL)
LANGUAGE plpgsql
AS $$
DECLARE
my_merchant_id INT8;
my_signkey_serial INT8;
my_credit_serial INT8;
my_affected_orders RECORD;
i INT8;
curs CURSOR (arg_coin_pub BYTEA) FOR
SELECT mcon.order_serial
FROM merchant_deposits dep
-- Next 2 joins ensure transfers exist in the first place
JOIN merchant_deposit_to_transfer
USING (deposit_serial)
JOIN merchant_transfers mtrans
USING (credit_serial)
JOIN merchant_deposit_confirmations mcon
USING (deposit_confirmation_serial)
WHERE dep.coin_pub=arg_coin_pub;
ini_coin_pub BYTEA;
ini_contract_term BYTEA;
ini_coin_value taler_amount_currency;
ini_deposit_fee taler_amount_currency;
BEGIN
-- Which instance are we using?
SELECT merchant_serial
INTO my_merchant_id
FROM merchant_instances
WHERE merchant_id=in_instance_id;
IF NOT FOUND
THEN
out_no_instance=TRUE;
out_no_account=FALSE;
out_no_exchange=FALSE;
out_duplicate=FALSE;
out_conflict=FALSE;
RETURN;
END IF;
out_no_instance=FALSE;
-- Determine account that was credited.
SELECT credit_serial
INTO my_credit_serial
FROM merchant_transfers
WHERE exchange_url=in_exchange_url
AND wtid=in_wtid
AND account_serial=
(SELECT account_serial
FROM merchant_accounts
WHERE payto_uri=in_payto_uri
AND exchange_url=in_exchange_url
AND merchant_serial=my_merchant_id);
IF NOT FOUND
THEN
out_no_account=TRUE;
out_no_exchange=FALSE;
out_duplicate=FALSE;
out_conflict=FALSE;
RETURN;
END IF;
out_no_account=FALSE;
-- Find exchange sign key
SELECT signkey_serial
INTO my_signkey_serial
FROM merchant_exchange_signing_keys
WHERE exchange_pub=in_exchange_pub
ORDER BY start_date DESC
LIMIT 1;
IF NOT FOUND
THEN
out_no_exchange=TRUE;
out_conflict=FALSE;
out_duplicate=FALSE;
RETURN;
END IF;
out_no_exchange=FALSE;
-- Add signature first, check for idempotent request
INSERT INTO merchant_transfer_signatures
(credit_serial
,signkey_serial
,credit_amount
,wire_fee
,execution_time
,exchange_sig)
VALUES
(my_credit_serial
,my_signkey_serial
,in_total_amount
,in_wire_fee
,in_execution_time
,in_exchange_sig)
ON CONFLICT DO NOTHING;
IF NOT FOUND
THEN
PERFORM 1
FROM merchant_transfer_signatures
WHERE credit_serial=my_credit_serial
AND signkey_serial=my_signkey_serial
AND credit_amount=in_credit_amount
AND wire_fee=in_wire_fee
AND execution_time=in_execution_time
AND exchange_sig=in_exchange_sig;
IF FOUND
THEN
-- duplicate case
out_duplicate=TRUE;
out_conflict=FALSE;
RETURN;
END IF;
-- conflict case
out_duplicate=FALSE;
out_conflict=TRUE;
RETURN;
END IF;
out_duplicate=FALSE;
out_conflict=FALSE;
FOR i IN 1..array_length(ina_coin_pubs,1)
LOOP
ini_coin_value=ina_coin_values[i];
ini_deposit_fee=ina_deposit_fees[i];
ini_coin_pub=ina_coin_pubs[i];
ini_contract_term=ina_contract_terms[i];
INSERT INTO merchant_transfer_to_coin
(deposit_serial
,credit_serial
,offset_in_exchange_list
,exchange_deposit_value
,exchange_deposit_fee)
SELECT
dep.deposit_serial
,my_credit_serial
,i
,ini_coin_value
,ini_deposit_fee
FROM merchant_deposits dep
JOIN merchant_deposit_confirmations dcon
USING (deposit_confirmation_serial)
JOIN merchant_contract_terms cterm
USING (order_serial)
WHERE dep.coin_pub=ini_coin_pub
AND cterm.h_contract_terms=ini_contract_term
AND cterm.merchant_serial=my_merchant_id;
RAISE NOTICE 'iterating over affected orders';
OPEN curs (arg_coin_pub:=ini_coin_pub);
LOOP
FETCH NEXT FROM curs INTO my_affected_orders;
EXIT WHEN NOT FOUND;
RAISE NOTICE 'checking affected order for completion';
UPDATE merchant_contract_terms
SET wired=TRUE
WHERE order_serial IN
(SELECT order_serial
FROM merchant_deposit_confirmations dcon
WHERE
order_serial=my_affected_orders.order_serial
AND NOT EXISTS
(SELECT 1
FROM merchant_deposit_confirmations dcon
JOIN merchant_deposits dep
USING (deposit_confirmation_serial)
JOIN merchant_deposit_to_transfer
USING (deposit_serial)
JOIN merchant_transfers mtrans
USING (credit_serial)
WHERE dcon.order_serial=my_affected_orders.order_serial
AND NOT mtrans.confirmed));
END LOOP; -- END curs LOOP
CLOSE curs;
END LOOP; -- END FOR loop
END $$;
|