Compare commits

...

12 Commits

Author SHA1 Message Date
f969bd3c5b
Merge branch 'master' into age-withdraw 2023-07-03 16:20:44 +02:00
40629e8992
[age-withdraw] added library function for age-withdraw
- Added TALER_EXCHANGE_age_withdraw
- Also: Change TALER_EXCHANGE_batch_withdraw and related functions to
  use GNUNET_CURL_ctx, TALER_EXCHANGE_keys and const char *echange_url
2023-07-03 16:18:40 +02:00
Christian Grothoff
2d4ebd3fc3
unconfuse pay and deposit 2023-07-02 16:09:09 +02:00
Christian Grothoff
8d6bce26ad
clarify what happens on block 2023-07-02 15:22:28 +02:00
Christian Grothoff
2d5f0a87e0
fix build 2023-07-02 14:57:48 +02:00
Christian Grothoff
c6e3cba61d
edits 2023-07-02 14:52:36 +02:00
Christian Grothoff
a8b3f0eb4e
work on regulator text 2023-07-02 14:48:27 +02:00
Christian Grothoff
e961b29103
Merge branch 'master' of git+ssh://git.taler.net/exchange 2023-07-02 14:34:45 +02:00
Christian Grothoff
67262173a1
forgot to add KYB file 2023-07-02 14:34:41 +02:00
4d8d6d1222
Added \newcommand for \LAND, \TALER, \CURRENCY; inserted package for enumeration; file renders to PDF now
Signed-off-by: Stefan Kügel <skuegel@web.de>
2023-07-02 14:18:34 +02:00
Christian Grothoff
78ed6228eb
migrate Stefan's translation back into the public git 2023-07-02 11:39:54 +02:00
Christian Grothoff
57527a5e8d
dce 2023-07-01 22:06:47 +02:00
35 changed files with 1797 additions and 400 deletions

View File

@ -1,8 +1,5 @@
\section{Deposit} \label{sec:deposit} \section{Deposit} \label{sec:deposit}
% FIXME: split up between deposit to merchant
% and deposit to customer's (own) bank account!
\begin{figure}[h!] \begin{figure}[h!]
\begin{sequencediagram} \begin{sequencediagram}
\newinst{wallet}{\shortstack{Customer wallet \\ \newinst{wallet}{\shortstack{Customer wallet \\
@ -16,7 +13,7 @@
\node at (1.5,0) {\shortstack{{{\tiny Database}}}}; \node at (1.5,0) {\shortstack{{{\tiny Database}}}};
\end{tikzpicture} \end{tikzpicture}
}} }}
\newinst[2]{bank}{\shortstack{Customer bank \\ \newinst[2]{bank}{\shortstack{Retail bank \\
\\ \begin{tikzpicture} \\ \begin{tikzpicture}
\node [fill=gray!20,draw=black,thick,align=center] {Checking \\ Accounts}; \node [fill=gray!20,draw=black,thick,align=center] {Checking \\ Accounts};
\end{tikzpicture} \end{tikzpicture}
@ -41,8 +38,10 @@
\mess[0]{exchange}{{Initiate transfer}}{bank} \mess[0]{exchange}{{Initiate transfer}}{bank}
\end{sequencediagram} \end{sequencediagram}
\caption{Deposit interactions between customer, Taler exchange (payment \caption{A customer deposits the coins issued by a Taler exchange (payment
service provider) and customer's bank.} service provider) into a bank account. Even if the
bank account is owned by the same customer, the
KYC checks from Section~\ref{sec:kyc:deposit} apply.}
\label{fig:int:deposit} \label{fig:int:deposit}
\end{figure} \end{figure}

View File

@ -1,4 +1,4 @@
\section{Pay} \section{Pay} \label{sec:pay}
\begin{figure}[h!] \begin{figure}[h!]
\begin{sequencediagram} \begin{sequencediagram}
@ -29,7 +29,7 @@
\mess[0]{merchant}{Commercial offer}{wallet} \mess[0]{merchant}{Commercial offer}{wallet}
\begin{callself}{wallet}{Review offer}{} \begin{callself}{wallet}{Review offer}{}
\end{callself} \end{callself}
\mess[0]{wallet}{Send payment {(Coins)}}{merchant} \mess[0]{wallet}{Pay {(Coins)}}{merchant}
\mess[0]{merchant}{Deposit {(Coins)}}{exchange} \mess[0]{merchant}{Deposit {(Coins)}}{exchange}
\begin{sdblock}{Acceptable account?}{} \begin{sdblock}{Acceptable account?}{}
\mess[0]{exchange}{{Refuse deposit}}{merchant} \mess[0]{exchange}{{Refuse deposit}}{merchant}
@ -45,8 +45,10 @@
\end{sdblock} \end{sdblock}
\mess[0]{exchange}{{Initiate transfer}}{bank} \mess[0]{exchange}{{Initiate transfer}}{bank}
\end{sequencediagram} \end{sequencediagram}
\caption{Deposit interactions between customer, merchant, \caption{Payments from a customer to merchant result in
Taler exchange (payment service provider) and merchant bank.} depositing coins at the Taler exchange (payment service provider)
which then credits the merchant's bank account.
The KYC/AML checks are described in Section~\ref{sec:kyc:deposit}}
\label{fig:int:pay} \label{fig:int:pay}
\end{figure} \end{figure}

View File

@ -1,4 +1,4 @@
\section{Pull payment (aka invoicing)} \section{Pull payment (aka invoicing)} \label{sec:pull}
\begin{figure}[h!] \begin{figure}[h!]
\begin{sequencediagram} \begin{sequencediagram}
@ -43,7 +43,8 @@
\end{sequencediagram} \end{sequencediagram}
\caption{Interactions between wallets and Taler exchange \caption{Interactions between wallets and Taler exchange
in a pull payment.} in a pull payment. KYC/AML checks are described in
Section~\ref{sec:kyc:pull}.}
\label{fig:int:pull} \label{fig:int:pull}
\end{figure} \end{figure}

View File

@ -1,4 +1,4 @@
\section{Push payment} \section{Push payment} \label{sec:push}
\begin{figure}[h!] \begin{figure}[h!]
\begin{sequencediagram} \begin{sequencediagram}
@ -42,6 +42,7 @@
\end{sequencediagram} \end{sequencediagram}
\caption{Interactions between wallets and Taler exchange \caption{Interactions between wallets and Taler exchange
in a push payment.} in a push payment. KYC/AML checks are described
in Section~\ref{sec:kyc:push}.}
\label{fig:int:push} \label{fig:int:push}
\end{figure} \end{figure}

View File

@ -44,6 +44,6 @@
\end{sequencediagram} \end{sequencediagram}
\caption{Withdraw interactions between customer, Taler exchange (payment \caption{Withdraw interactions between customer, Taler exchange (payment
service provider) and bank. The amount of digital cash distributed is service provider) and bank. The amount of digital cash distributed is
subject to limits per origin account (see Figure~\ref{fig:kyc:withdraw}).} subject to limits per origin account (see Section~\ref{sec:kyc:withdraw}).}
\label{fig:int:withdraw} \label{fig:int:withdraw}
\end{figure} \end{figure}

View File

@ -1,4 +1,4 @@
\section{KYC: Deposit} \section{KYC: Deposit} \label{sec:kyc:deposit}
\begin{figure}[h!] \begin{figure}[h!]
\begin{center} \begin{center}
@ -14,8 +14,8 @@
] ]
\node (start) [start] {Start}; \node (start) [start] {Start};
\node (country) [decision,below=of start,text width=2.5cm] {Target account in allowed country?}; \node (country) [decision,below=of start,text width=2.5cm] {Target account in allowed country?};
\node (amount) [decision, below=of country,text width=2.5cm] {Target account received less than KYC threshold?}; \node (amount) [decision, below=of country,text width=2.5cm] {Target account received less than KYB threshold?};
\node (kyc) [process, right=of amount] {KYC process}; \node (kyc) [process, right=of amount] {KYB process};
\node (high) [decision, below=of amount,text width=2.5cm] {Target account received more than its AML threshold?}; \node (high) [decision, below=of amount,text width=2.5cm] {Target account received more than its AML threshold?};
\node (aml) [process, right=of high] {AML process}; \node (aml) [process, right=of high] {AML process};
\node (dummy) [below right=of aml] {}; \node (dummy) [below right=of aml] {};
@ -55,8 +55,8 @@
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
\caption{Regulatory process when depositing digital cash into a bank \caption{Regulatory process when depositing digital cash into a bank
account. When the transfer is denied, the money is returned to the account. When the transfer is denied, the money is held in escrow
originating wallet.} until authorities authorize the transfer.}
\end{figure} \end{figure}
@ -66,8 +66,15 @@
\begin{tabular}{l|l|r} \begin{tabular}{l|l|r}
{\bf Setting} & {\bf Type} & {\bf Value} \\ \hline \hline {\bf Setting} & {\bf Type} & {\bf Value} \\ \hline \hline
Allowed bank accounts & RFC 8905 RegEx & {\em CH*} \\ \hline Allowed bank accounts & RFC 8905 RegEx & {\em CH*} \\ \hline
KYC deposit threshold & Amount/month & {\em 5000 CHF} \\ KYB deposit threshold & Amount/month & {\em 5000 CHF} \\
KYC deposit threshold & Amount/year & {\em 15000 CHF} \\ KYB deposit threshold & Amount/year & {\em 25000 CHF} \\
Default AML deposit threshold & Amount/month & {\em 2500 CHF} \\ Default AML deposit threshold & Amount/month & {\em 2500 CHF} \\
\end{tabular} \end{tabular}
\end{table} \end{table}
The KYB deposit threshold of 5'000 \CURRENCY{} per month and than 25'000
\CURRENCY{} per year ensure compliance with article 48-1b.
Additionally, our terms of service will prohibit businesses to receive
amounts exceeding 1'000 \CURRENCY{} per transaction (well below the
15'000 \CURRENCY{} threshold defined in article 24-1c).

View File

@ -1,4 +1,4 @@
\section{KYC/AML: Pull Payment} \section{KYC/AML: Pull Payment} \label{sec:kyc:pull}
\begin{figure}[h!] \begin{figure}[h!]
\begin{center} \begin{center}
@ -63,7 +63,10 @@
\end{center} \end{center}
\caption{Regulatory process when receiving payments from another wallet. \caption{Regulatory process when receiving payments from another wallet.
The threshold depends on the risk profile from the KYC process. The threshold depends on the risk profile from the KYC process.
When invoicing is denied the wallet cannot generate the invoice.} When KYC thresholds would be passed, the receiving wallet cannot
generate a valid invoice until it has provided the KYC data.
When a transfer is denied by AML staff, the money is held in escrow
until authorities authorize the transfer.}
\end{figure} \end{figure}
@ -73,8 +76,11 @@
\begin{tabular}{l|l|r} \begin{tabular}{l|l|r}
{\bf Setting} & {\bf Type} & {\bf Value} \\ \hline \hline {\bf Setting} & {\bf Type} & {\bf Value} \\ \hline \hline
Permitted phone numbers & Dialing prefix & {\em +41} \\ Permitted phone numbers & Dialing prefix & {\em +41} \\
P2P KYC threshold & Amount/month & {\em 5000 CHF} \\ P2P KYC threshold & Amount/month & {\em 1000 CHF} \\
P2P KYC threshold & Amount/year & {\em 15000 CHF} \\ P2P KYC threshold & Amount/year & {\em 5000 CHF} \\
Default P2P AML threshold & Amount/month & {\em 1000 CHF} \\ Default P2P AML threshold & Amount/month & {\em 2500 CHF} \\
\end{tabular} \end{tabular}
\end{table} \end{table}
The P2P KYC thresholds of 1'000 \CURRENCY{} per month and than 5'000
\CURRENCY{} per year ensure compliance with article 49-2c.

View File

@ -1,4 +1,4 @@
\section{KYC/AML: Push Payment} \section{KYC/AML: Push Payment} \label{sec:kyc:push}
\begin{figure}[h!] \begin{figure}[h!]
\begin{center} \begin{center}
@ -63,8 +63,8 @@
\end{center} \end{center}
\caption{Regulatory process when receiving payments from another wallet. \caption{Regulatory process when receiving payments from another wallet.
The threshold depends on the risk profile from the KYC process. The threshold depends on the risk profile from the KYC process.
When the transfer is denied the money is (eventually) returned to When the transfer is denied, the money is held in escrow
the originating wallet.} until authorities authorize the transfer.}
\end{figure} \end{figure}
@ -74,8 +74,11 @@
\begin{tabular}{l|l|r} \begin{tabular}{l|l|r}
{\bf Setting} & {\bf Type} & {\bf Value} \\ \hline \hline {\bf Setting} & {\bf Type} & {\bf Value} \\ \hline \hline
Permitted phone numbers & Dialing prefix & {\em +41} \\ Permitted phone numbers & Dialing prefix & {\em +41} \\
P2P KYC threshold & Amount/month & {\em 5000 CHF} \\ P2P KYC threshold & Amount/month & {\em 1000 CHF} \\
P2P KYC threshold & Amount/year & {\em 15000 CHF} \\ P2P KYC threshold & Amount/year & {\em 5000 CHF} \\
Default P2P AML threshold & Amount & {\em 1000 CHF} \\ Default P2P AML threshold & Amount/month & {\em 2500 CHF} \\
\end{tabular} \end{tabular}
\end{table} \end{table}
The P2P KYC thresholds of 1'000 \CURRENCY{} per month and than 5'000
\CURRENCY{} per year ensure compliance with article 49-2c.

View File

@ -1,4 +1,4 @@
\section{KYC: Withdraw} \section{KYC: Withdraw} \label{sec:kyc:withdraw}
\begin{figure}[h!] \begin{figure}[h!]
\begin{center} \begin{center}
@ -43,8 +43,13 @@
\begin{tabular}{l|l|r} \begin{tabular}{l|l|r}
{\bf Setting} & {\bf Type} & {\bf Value} \\ \hline \hline {\bf Setting} & {\bf Type} & {\bf Value} \\ \hline \hline
Allowed bank accounts & RFC 8905 RegEx & {\em CH*} \\ \hline Allowed bank accounts & RFC 8905 RegEx & {\em CH*} \\ \hline
Withdraw maximum & Amount/month & {\em 5000 CHF} \\ SMS-Identification & Amount/month & {\em 200 CHF} \\
Withdraw maximum & Amount/year & {\em 15000 CHF} \\ Withdraw limit & Amount/month & {\em 5000 CHF} \\
Withdraw limit & Amount/year & {\em 25000 CHF} \\
Bounce period & Delay & 1 month \\ Bounce period & Delay & 1 month \\
\end{tabular} \end{tabular}
\end{table} \end{table}
The limit of 200 \CURRENCY{} results from article 48-2. Strictly limiting
withdrawals to less than 5'000 \CURRENCY{} per month and less than 25'000
\CURRENCY{} per year assures compliance with article 48-1c.

239
doc/flows/main.de.tex Normal file
View File

@ -0,0 +1,239 @@
% This is a (partial) translation of main.tex into
% German. Please keep the structure as parallel as
% possible when improving / expanding the translation!
\documentclass[10pt,a4paper,oneside]{book}
\usepackage[utf8]{inputenc}
\usepackage{url}
\usepackage{enumitem}
\usepackage{graphicx}
\usepackage{hyperref}
\usepackage{qrcode}
\usepackage{pgf-umlsd}
\usepackage{tikz}
\usetikzlibrary{shapes,arrows}
\usetikzlibrary{positioning}
\usetikzlibrary{calc}
\usetikzlibrary{quotes}
\author{Christian Grothoff}
\title{Flows in the GNU Taler System}
\begin{document}
\tableofcontents
\newcommand\TALER{TALER OPERATIONS AG}
\newcommand\CURRENCY{CHF}
\newcommand\LAND{der Schweiz}
\section{Transaktionen im Taler-Bezahlsystem}\label{sec:Transaktionen}
Dieser Abschnitt stellt die Transaktionen im Taler-Bezahlsystem
vor. Die Grafiken geben wieder, in welcher Reihenfolge die beteiligten
Parteien interagieren. \\
F\"ur jede einzelne Transaktion ist die automatische Ausl\"osung von
Compliance-Prozessen durch den Taler-Exchange einstellbar.
Die im Rahmen des jeweiligen Compliance-Prozesses erzwungenen
Pr\"ufschritte beschreibt Abschnitt~\ref{sec:triggers}.
Folgende Transaktionen kommen als Ausl\"oser f\"ur AML- und KYC-Prozesse
in Betracht:
\begin{description}[noitemsep]
\item[withdraw] Ein Nutzer hebt digitales Bargeld (e-money) in Form von
Taler-Coins in ein Taler-Wallet ab
\item[reimburse] Ein Nutzer l\"asst den Gegenwert von Taler-Coins vom
Taler-Exchange an das urspr\"ungliche IBAN-Bankkonto zur\"uck\"uberweisen
\item[pay] Ein Nutzer zahlt zugunsten eines IBAN-Bankkontos des Empf\"angers
\item[refund] Ein Verk\"aufer erteilt einem Zahlenden die R\"uckerstattung
eines Zahlbetrags
\item[push] Ein Nutzer sendet einen Zahlbetrag an ein anderes Taler-Wallet
\item[pull] Ein Nutzer stellt einem anderen Taler-Wallet eine Rechnung aus
und fordert eine Zahlung von diesem Wallet
\item[shutdown] Der Betreiber des Taler-Exchange informiert die Inhaber von
Coins, die diese von jenem Exchange abgehoben hatten, dass der Exchange
geplant eingestellt und die Gegenwerte der Coins restituiert werden
\end{description}
Die Nutzer beginnen ein gesch\"aftliches Nutzungsverh\"altnis mit
\TALER{}, wenn sie ihre Taler-Wallets anweisen, eine Abhebung durchzuf\"uhren.
Das Taler-Bezahlsystem verwendet jedoch keine Konten, sondern wert-basierte
Token und explizit keine konten-basierten Geld-\"Aquivalente.
Taler soll digitales Bargeld sein und erlaubt technisch bedingt
kein Nachvollziehen der Transaktionen seiner Nutzer, wie es Konten mit
Eing\"angen und Ausg\"angen von Zahlungen erm\"oglichen w\"urden.
Es gibt daher kein ``Er\"offnen'' oder ``Schliessen'' von Konten der Nutzer.
Die Begriffe ``opening'' und ``closing'' lassen sich deshalb auch nicht auf
das System anwenden oder \"ubertragen. \\
Die Nutzer k\"onnen
\begin{enumerate}[noitemsep]
\item die treuh\"andisch verwalteten Einlagen gezielt auf ein bestimmtes
Bankkonto auszahlen lassen,
%(siehe Abschnitt~\ref{sec:deposit})
\item an einen Verk\"aufer zahlen,
%(siehe Abschnitt~\ref{sec:deposit})
\item einem anderen Empf\"anger mittels peer-to-peer-Verfahren Coins zukommen
lassen
%(siehe Abschnitte~\ref{sec:push} und~\ref{sec:pull})
\item die Coins in ihrem Wallet, das verloren ging oder zerst\"ort wurde,
durch Ablauf der G\"ultigkeit entwerten lassen (dies w\"are ebenso der Fall
bei einer langen Zeit ohne Internet-Anbindung oder ohne Installation),
\item den Wert der Coins im Wallet durch Zahlung von Geb\"uhren f\"ur
die Verl\"angerung ihrer G\"ultigkeit langsam verringern lassen.
%(siehe Abschnitt~\ref{sec:fees:coin})
\end{enumerate}
Das Taler-Bezahlsystem verwehrt den Nutzern kategorisch die Abhebung
von h\"oheren Betr\"agen als 5.000 \CURRENCY{} pro Monat bzw. von
mehr als 15.000 \CURRENCY{} pro Jahr. Damit wird gew\"ahrleistet,
dass die Nutzer stets unterhalb der Grenzwerte bleiben, ab denen die
meisten Pr\"ufschritte aufgrund regulatorischer Bestimmungen erforderlich
werden. \TALER{} stellt dar\"uber hinaus sicher, dass die Nutzer
ausschliesslich in \LAND{} ans\"assig sind
(siehe Abschnitt~\ref{sec:proc:domestic}), da auf ihrer Seite ein Bankkonto
in \LAND{} f\"ur die \"Uberweisungen an den Taler-Exchange und/oder
eine Telefonnummer mit entsprechender Vorwahl (++41) ben\"otigt werden.
Zus\"atzlich setzt das Taler-Wallet zu jeder Zeit eine Obergrenze
von 5.000 \CURRENCY{} auf die Coin-Betr\"age in Summe fest, so dass es
keine weitere Abhebung \"uber diesen Grenzwert hinaus bewirken kann.
F\"ur {\bf Verk\"aufer} beginnt ein gesch\"aftliches Nutzungsverh\"altnis
mit \TALER{}, sobald sie Geldeing\"ange auf ihren IBAN-Bankkonten erhalten,
die als Zahlungen von Nutzern des Taler-Bezahlsystems ausgel\"ost wurden
(siehe Abschnitt~\ref{sec:deposit}). Sollten die Summen der Eing\"ange
5.000 \CURRENCY{} pro Monat bzw. 15.000 \CURRENCY{} pro Jahr \"ubersteigen,
kommt es zu einer KYB-Pr\"ufung, die dem Begriff ``Er\"offnen'' eines
Kontos entspricht und die eine aktualisierte KYB-Information sowie
die Pr\"ufung von Sanktionslisten erfordert, sofern der Verk\"aufer
innerhalb von 24 Monaten wenigstens einen Geldeingang erhielt.
Im Gegensatz zu normalen Nutzern k\"onnen Verk\"aufer im Prinzip
Zahlungen ohne Limit empfangen. Allerdings m\"ussen diese Transaktionen
auch wirklich als Eing\"ange auf dem Bankkonto des Unternehmens verzeichnet
werden (im Kontoauszug). In Abh\"angigkeit von den an das Gesch\"aftskonto
\"uberwiesenen Betr\"agen wird der Verk\"aufer einer KYB-Pr\"ufung unterzogen
(siehe Abschnitt~\ref{sec:KYB}). Dies gilt ebenso f\"ur
Geldw\"asche-\"Uberpr\"ufungen (AML checks).
Das Taler-Bezahlsystem transferiert lediglich Gelder auf die bestehenden
Bankkonten der Verk\"aufer, die f\"ur ihre G\"uterleistungen Zahlungen
der Nutzer erhalten, f\"ur die bereits bei der \"Uberweisung von deren
Kundenkonten eine KYC-Pr\"ufung erfolgte. Daher wird unseres Erachtens
der Betreiber eines Taler-Exchange keine Mittelherkunft verlangen bzw.
nachweisen m\"ussen
\footnote{Wenn Unternehmen das Taler-Bezahlsystem ihrerseits f\"ur
Zahlungen nutzen wollen, m\"ussen sie genauso wie alle anderen Nutzer
zuerst Geld von ihrem Bankkonto an einen Taler-Exchange \"uberweisen,
eine KYC-Pr\"ufung absolvieren und dann ihr Wallet Coins abheben lassen.
F\"ur die gesch\"aftlichen K\"aufer gelten ebenfalls die Limits wie
f\"ur alle anderen Nutzer.}.
\include{int-withdraw}
\include{int-deposit}
\include{int-pay}
\include{int-refund}
\include{int-push}
\include{int-pull}
\include{int-shutdown}
\chapter{Regulatory Triggers} \label{chap:triggers}
In this chapter we show decision diagrams for regulatory processes of the
various core operations of the GNU Taler payment system. In each case, the
{\bf start} state refers to one of the interactions described in the previous
chapter. The payment system will then use the process to arrive at an {\bf
allow} decision which permits the transaction to go through, or at a {\bf
deny} decision which ensures that the funds are not moved.
The specific {\em decisions} (in green) depend on the risk profile and the
regulatory environment. The tables in each section list the specific values
that are to be configured.
There are five types if interactions that can trigger regulatory processes:
\begin{description}
\item[withdraw] a customer withdraws digital cash from their {\bf bank account}
\item[deposit] a merchant's {\bf bank account} is designated to receive a payment in digital cash
\item[push] a {\bf wallet} accepts a payment from another wallet
\item[pull] a {\bf wallet} requests a payment from another wallet
\item[balance] a withdraw or P2P payment causes the balance of a {\bf wallet} to exceed a given threshold
\end{description}
We note in bold the {\bf anchor} for the regulator process. The anchor is used
to link the interaction to an identity. Once an identity has been established
for a particular anchor, that link is considered established for all types of
activities involving that anchor. A wallet is uniquely identified in the
system by its unique cryptographic key. A bank account is uniquely identified
in the system by its (RFC 8905) bank routing data (usually including BIC, IBAN
and account owner name).
The KYC and AML processes themselves are described in
Chapter~\ref{chap:regproc}.
\include{kyc-withdraw}
\include{kyc-deposit}
\include{kyc-push}
\include{kyc-pull}
\include{kyc-balance}
\chapter{Regulatory Processes} \label{chap:regproc}
This chapter describes the interactions between the customer, exchange and
organizations or staff assisting with regulatory processes designed to ensure
that customers are residents in the area of operation of the payment service
provider, are properly identified, and do not engage in money laundering.
The three main regulatory processes are:
\begin{description}
\item[domestic check] This process establishes that a user is generally
eligible to use the payment system. The process checks that the user has an
eligible address, but stops short of establishing the user's identity.
\item[kyc] This process establishes a user's legal identity, possibly
using external providers to review documents and check against blacklists.
\item[aml] The AML process reviews suspicious payment activities for
money laundering. Here AML staff reviews all collected information.
\end{description}
\include{proc-domestic}
%\include{proc-kyc}
\include{proc-kyb}
\include{proc-aml}
\chapter{Fees} \label{chap:fees}
The business model for operating a Taler exchange is to charge transaction
fees. Fees are charged on certain operations by the exchange. There are two
types of fees, {\bf wire fees} and {\bf coin fees}. This chapter describes
the fee structure.
Fixed, amount-independent {\bf wire fees} are charged on wire transfers using
the core banking system. Details on wire fees are described in
Section~\ref{sec:fees:wire}.
Coin fees are more complex, as they do not exactly follow neither the usual
percentage of volume model of other payment systems. Instead, coin fees are
applied per coin, resulting in a {\em logarithmic} fee structure. As a
result, the effective fee {\em percentage} for tiny transactions is high (for
example 50\% for transactions of 0.0025 CHF) while the effective fee
percentage for large transactions is nominal (for example $\approx$ 0.05\% for
transactions of $\approx$ 40 CHF). Details on coin fees are described in
Section~\ref{sec:fees:coin}.
Fees are configurable (and that fee types beyond those described here are
supported by the software). Thus, the specific fees may be adjusted in the
future based on business decisions. However, changes to the fees are never
retroactively applied to coins already in circulation. Wire fees that have
been publicly announced for a particular time period also cannot be changed.
Finally, any change to the terms of service must also be explicitly accepted
by the users before they withdraw additional funds.
\include{fees-wire}
\include{fees-coins}
%\include{fees-other}
\end{document}

View File

@ -13,8 +13,11 @@
\author{Christian Grothoff} \author{Christian Grothoff}
\title{Flows in the GNU Taler System} \title{Flows in the GNU Taler System}
\newcommand\CURRENCY{CHF}
\begin{document} \begin{document}
\maketitle
\tableofcontents \tableofcontents
\chapter{Interactions} \label{chap:interactions} \chapter{Interactions} \label{chap:interactions}
@ -37,12 +40,21 @@ The main interactions of the system are:
\item[shutdown] the Taler payment system operator informs the customers that the system is being shut down for good \item[shutdown] the Taler payment system operator informs the customers that the system is being shut down for good
\end{description} \end{description}
In the analysis of the legal requirements, it is important to differenciate
between transactions between wallets (customer-to-customer) and transactions
where money flows from a wallet into a bank account (customer-to-merchant) as
these have different limits: When digital coins are used to pay at a business in
Taler, the business never actually receives usable digital coins but instead
the amount is always directly credited to their bank account. Depending on
the transacted amounts, the business will nevertheless be subject to KYB
(Section~\ref{sec:proc:kyb}) and AML checks.
{\bf Customers} begin their business relationship with us when they withdraw {\bf Customers} begin their business relationship with us when they withdraw
digital cash. Taler has no accounts (this is digital cash) and thus there is digital cash. Taler has no accounts (this is digital cash) and thus there is
no ``opening'' or ``closing'' of accounts for consumers. Given digital cash, no ``opening'' or ``closing'' of accounts for consumers. Given digital cash,
the customers can either (1) deposit the funds explicitly into a bank account the customers can either (1) deposit the funds explicitly into a bank account
(see Section~\ref{sec:deposit}), (2) pay a merchant (see (see Section~\ref{sec:deposit}), (2) pay a merchant (see
Section~\ref{sec:deposit}), (3) pay another customer using a peer-to-peer Section~\ref{sec:pay}), (3) pay another customer using a peer-to-peer
transfer (see Sections~\ref{sec:push} and~\ref{sec:pull}), or (4) the coins transfer (see Sections~\ref{sec:push} and~\ref{sec:pull}), or (4) the coins
will expire if the wallet was lost (including offline for a long time or will expire if the wallet was lost (including offline for a long time or
uninstalled). Finally, if a wallet remains (occasionally) online but a user uninstalled). Finally, if a wallet remains (occasionally) online but a user
@ -51,33 +63,33 @@ fees (see Section~\ref{sec:fees:coin}) that apply to prevent the coins from
expiring outright. expiring outright.
For customers, we will categorically limit of digital cash withdrawn per month For customers, we will categorically limit of digital cash withdrawn per month
to less than CHF 5000 per month and less than CHF 15000 per year, thus to less than CHF 5'000 per month and less than CHF 25'000 per year, thus
ensuring that consumers remain below the thresholds where most regulatory ensuring that consumers remain below the thresholds where most regulatory
processes become applicable. We will, however, ensure that customers are Swiss processes become applicable. Payments between users will be limited
to receiving less than CHF 1'000 per month and less than CHF 5'000 per year.
We will ensure that customers are Swiss
(see Section~\ref{sec:proc:domestic}) by requiring them to have a Swiss bank (see Section~\ref{sec:proc:domestic}) by requiring them to have a Swiss bank
account and/or Swiss phone number (+41-prefix). Furthermore, the wallet will account and/or Swiss phone number (+41-prefix).
impose an upper limit of CHF 5000 on its balance at any point in time. %Furthermore, the wallet will
%impose an upper limit of CHF 5000 on its balance at any point in time.
For {\bf merchants}, the Taler equivalent of ``opening'' an account and thus For {\bf merchants}, the Taler equivalent of ``opening'' an account and thus
establishing an ongoing business relationship is for a business to receive establishing an ongoing business relationship is for a business to receive
payments (see Section~\ref{sec:deposit}) exceeding CHF 5000/month or CHF payments (see Section~\ref{sec:pay}) exceeding CHF 5'000/month or CHF
15000/year. We will consider the account ``open'' (and require up-to-date KYB 25'000/year. We will consider the account ``open'' (and require up-to-date KYB
information and check sanction lists) as long as the business has made any information and check sanction lists) as long as the business has made any
transactions within the last 24 months. transactions within the last 24 months.
In contrast to normal customers, merchants can in principle {\bf receive} As we will only transfer money into the existing bank accounts of the
payments without limit. However, these transactions must go into the bank merchants to compensate them for sales made using the Taler payment system, we
account of the business: when digital coins are deposited at a business in do not need to check the origin of funds for those merchants as they will only
Taler, the business never actually receives usable digital coins but instead receive funds from us.\footnote{Should businesses want to use Taler for
the amount is always directly credited to their bank account. Depending on expenditures, they will need to withdraw digital coins from their bank account
the transacted amounts, the business will be subject to KYB just like customers, and the limits for customers will continue to apply.}
(Section~\ref{sec:proc:kyb}) and AML checks. As we will only transfer money
into the existing bank accounts of the merchants to compensate them for sales For individual {\bf transactions}, we will impose a limit of CHF
made using the Taler payment system, we do not need to check the origin of 1'000/transaction (even though our reading of the regulations would permit
funds for those merchants as they will only receive funds from individual transactions up to CHF 15'000).
us.\footnote{Should businesses want to use Taler for expenditures, they will
need to withdraw digital coins from their bank account just like customers,
and the limits for customers will continue to apply.}
The following sections describe the respective processes for each of these The following sections describe the respective processes for each of these
interactions. interactions.
@ -108,10 +120,12 @@ There are five types if interactions that can trigger regulatory processes:
\begin{description} \begin{description}
\item[withdraw] a customer withdraws digital cash from their {\bf bank account} \item[withdraw] a customer withdraws digital cash from their {\bf bank account}
\item[deposit] a merchant's {\bf bank account} is designated to receive a payment in digital cash \item[deposit] a customer or merchant's {\bf bank account} is
designated to receive a payment due someone paying with or
depositing digital cash
\item[push] a {\bf wallet} accepts a payment from another wallet \item[push] a {\bf wallet} accepts a payment from another wallet
\item[pull] a {\bf wallet} requests a payment from another wallet \item[pull] a {\bf wallet} requests a payment from another wallet
\item[balance] a withdraw or P2P payment causes the balance of a {\bf wallet} to exceed a given threshold % \item[balance] a withdraw or P2P payment causes the balance of a {\bf wallet} to exceed a given threshold
\end{description} \end{description}
We note in bold the {\bf anchor} for the regulator process. The anchor is used We note in bold the {\bf anchor} for the regulator process. The anchor is used
@ -129,7 +143,7 @@ Chapter~\ref{chap:regproc}.
\include{kyc-deposit} \include{kyc-deposit}
\include{kyc-push} \include{kyc-push}
\include{kyc-pull} \include{kyc-pull}
\include{kyc-balance} %\include{kyc-balance}
\chapter{Regulatory Processes} \label{chap:regproc} \chapter{Regulatory Processes} \label{chap:regproc}
@ -151,7 +165,7 @@ The three main regulatory processes are:
\end{description} \end{description}
\include{proc-domestic} \include{proc-domestic}
%\include{proc-kyc} \include{proc-kyc}
\include{proc-kyb} \include{proc-kyb}
\include{proc-aml} \include{proc-aml}

97
doc/flows/proc-kyb.tex Normal file
View File

@ -0,0 +1,97 @@
\section{KYB process} \label{sec:proc:kyb}
\begin{figure}[h!]
\begin{sequencediagram}
\newinst{merchant}{\shortstack{Merchant \\
\\ \begin{tikzpicture}
\node [fill=gray!20,draw=black,thick,align=center] { Unique \\ Action};
\end{tikzpicture}
}}
\newinst[2]{exchange}{\shortstack{Taler (exchange) \\
\\ \begin{tikzpicture}[shape aspect=.5]
\tikzset{every node/.style={cylinder,shape border rotate=90, draw,fill=gray!25}}
\node at (1.5,0) {\shortstack{{{\tiny Database}}}};
\end{tikzpicture}
}}
\newinst[2]{kyb}{\shortstack{KYB provider \\
\\ \begin{tikzpicture}[shape aspect=.5]
\tikzset{every node/.style={cylinder,shape border rotate=90, draw,fill=gray!25}}
\node at (1.5,0) {\shortstack{{{\tiny Database}}}};
\end{tikzpicture}
}}
\postlevel
\mess[0]{merchant}{{Initial action}}{exchange}
\begin{callself}{exchange}{Establish KYB requirement}{}
\end{callself}
\mess[0]{exchange}{Request new KYB process}{kyb}
\mess[0]{kyb}{{Process identifier (PI)}}{exchange}
\mess[0]{exchange}{{KYB required (PI)}}{merchant}
\mess[0]{merchant}{{KYB start (PI)}}{kyb}
\mess[0]{kyb}{{Request identity documentation}}{merchant}
\mess[0]{merchant}{{Upload identity documentation}}{kyb}
\begin{callself}{kyb}{Validate documentation}{}
\end{callself}
\mess[0]{kyb}{{Share documentation (PI)}}{exchange}
\mess[0]{kyb}{{Confirm completion}}{merchant}
\mess[0]{merchant}{{Retry action}}{exchange}
\end{sequencediagram}
\caption{Deposit interactions between customer, Taler exchange (payment
service provider) and external KYB provider. The process can be
triggered by various {\em actions} described in Chapter~\ref{chap:triggers}.}
\label{fig:proc:kyb}
\end{figure}
At the beginning of the KYB process, the user needs to specify whether they
are an {\bf individual} (not incorporated) or a {\bf business}.\footnote{ In
pratice, we expect most owners of bank accounts crossing the KYB threshold to
be businesses, but in principle such a bank account could be owned by an
individual operating a business without a separate legal entity.} This then
determines which types of attributes are collected in the KYB process
(Table~\ref{table:proc:kyb:individual}
vs. Table~\ref{table:proc:kyb:business}).
\begin{table}
\caption{Information collected for unincorporated individuals}
\label{table:proc:kyb:individual}
\begin{center}
\begin{tabular}{l|c|r}
{\bf Type} & {\bf Required} & {\bf Example} \\ \hline \hline
Surname & yes & Mustermann \\
First name(s) & yes & Max \\
Date of birth & yes & 1.1.1980 \\
Nationality & yes & Swiss \\
Actual address of domicile & yes & Seestrasse 3, 8008 Zuerich \\
Phone number & no & +41-123456789 \\
E-mail & no & me@example.com \\
Identification document & yes & JPG image \\
Taxpayer identification & yes & ZPV Nr. 253'123'456 \\
\end{tabular}
\end{center}
\end{table}
\begin{table}
\caption{Information collected for businesses. Information on individals is
collected for owners with more than 25\% ownership and for those with
signature authority for the business.}
\label{table:proc:kyb:business}
\begin{center}
\begin{tabular}{l|c|r}
{\bf Type} & {\bf Required} & {\bf Example} \\ \hline \hline
Company name & yes & Mega AG \\
Registered office & yes & Seestrasse 4, 8008 Zuerich \\
Company identification document & yes & PDF file \\
Power of attorney arrangement & yes & PDF file \\
Business registration number & yes & \\
Business registration document & yes & PDF file \\
Registration authority & yes & \\ \hline
Contact person name & yes & Max Mustermann \\
Identification document & yes & JPG image \\
Date of birth & yes & 1.1.1980 \\
Nationality & yes & Swiss \\
E-mail & yes & me@example.com \\
Phone number & no & +41-123456789 \\
\end{tabular}
\end{center}
\end{table}

View File

@ -42,10 +42,11 @@
\label{fig:proc:kyc} \label{fig:proc:kyc}
\end{figure} \end{figure}
At the beginning of the KYC process, the user needs to specify At the beginning of the KYC process, the user needs to specify whether they
whether they are an {\bf individual} or a {\bf business}. This are an {\bf individual} or a {\bf business}.\footnote{ In pratice, we expect
then determines which types of attributes are collected in the most wallet-users to be individuals, but in principle a wallet could be owned
KYC process (Table~\ref{table:proc:kyc:individual} vs. by a business.} This then determines which types of attributes are collected
in the KYC process (Table~\ref{table:proc:kyc:individual} vs.
Table~\ref{table:proc:kyc:business}). Table~\ref{table:proc:kyc:business}).
\begin{table} \begin{table}
@ -66,7 +67,6 @@ Table~\ref{table:proc:kyc:business}).
\end{center} \end{center}
\end{table} \end{table}
\begin{table} \begin{table}
\caption{Information collected for businesses} \caption{Information collected for businesses}
\label{table:proc:kyc:business} \label{table:proc:kyc:business}

View File

@ -69,6 +69,7 @@ struct AgeWithdrawContext
/** /**
* kappa * #num_coins hashes of blinded coin planchets. * kappa * #num_coins hashes of blinded coin planchets.
* FIXME[oec]: Make the [][] structure more explicit.
*/ */
struct TALER_BlindedPlanchet *coin_evs; struct TALER_BlindedPlanchet *coin_evs;

View File

@ -385,7 +385,10 @@ TEH_handler_purses_get (struct TEH_RequestContext *rc,
if (0 < if (0 <
TALER_amount_cmp (&gc->amount, TALER_amount_cmp (&gc->amount,
&gc->deposited)) &gc->deposited))
{
/* amount > deposited: not yet fully paid */
dt = GNUNET_TIME_UNIT_ZERO_TS; dt = GNUNET_TIME_UNIT_ZERO_TS;
}
if (TALER_EC_NONE != if (TALER_EC_NONE !=
(ec = TALER_exchange_online_purse_status_sign ( (ec = TALER_exchange_online_purse_status_sign (
&TEH_keys_exchange_sign_, &TEH_keys_exchange_sign_,

View File

@ -439,7 +439,9 @@ struct TALER_AgeCommitmentPublicKeyP
/* /*
* @brief Hash to represent the commitment to n*kappa blinded keys during a age-withdrawal. * @brief Hash to represent the commitment to n*kappa blinded keys during a
* age-withdrawal. It is the running SHA512 hash over the hashes of the blinded
* envelopes of n*kappa coins.
*/ */
struct TALER_AgeWithdrawCommitmentHashP struct TALER_AgeWithdrawCommitmentHashP
{ {
@ -3726,7 +3728,7 @@ TALER_wallet_withdraw_verify (
/** /**
* Sign age-withdraw request. * Sign age-withdraw request.
* *
* @param h_commitment hash all n*kappa blinded coins in the commitment for the age-withdraw * @param h_commitment hash over all n*kappa blinded coins in the commitment for the age-withdraw
* @param amount_with_fee amount to debit the reserve for * @param amount_with_fee amount to debit the reserve for
* @param mask the mask that defines the age groups * @param mask the mask that defines the age groups
* @param max_age maximum age from which the age group is derived, that the withdrawn coins must be restricted to. * @param max_age maximum age from which the age group is derived, that the withdrawn coins must be restricted to.
@ -3762,7 +3764,6 @@ TALER_wallet_age_withdraw_verify (
const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_ReserveSignatureP *reserve_sig); const struct TALER_ReserveSignatureP *reserve_sig);
/** /**
* Verify exchange melt confirmation. * Verify exchange melt confirmation.
* *
@ -4871,6 +4872,22 @@ TALER_exchange_online_age_withdraw_confirmation_sign (
struct TALER_ExchangeSignatureP *sig); struct TALER_ExchangeSignatureP *sig);
/**
* Verfiy an exchange age-withdraw confirmation
*
* @param h_commitment Commitment over all n*kappa coin candidates from the original request to age-withdraw
* @param noreveal_index The index returned by the exchange
* @param exchange_pub The public key used for signing
* @param exchange_sig The signature from the exchange
*/
enum GNUNET_GenericReturnValue
TALER_exchange_online_age_withdraw_confirmation_verify (
const struct TALER_AgeWithdrawCommitmentHashP *h_commitment,
uint32_t noreveal_index,
const struct TALER_ExchangePublicKeyP *exchange_pub,
const struct TALER_ExchangeSignatureP *exchange_sig);
/* ********************* offline signing ************************** */ /* ********************* offline signing ************************** */

View File

@ -18,6 +18,7 @@
* @brief C interface of libtalerexchange, a C library to use exchange's HTTP API * @brief C interface of libtalerexchange, a C library to use exchange's HTTP API
* @author Sree Harsha Totakura <sreeharsha@totakura.in> * @author Sree Harsha Totakura <sreeharsha@totakura.in>
* @author Christian Grothoff * @author Christian Grothoff
* @author Özgür Kesim
*/ */
#ifndef _TALER_EXCHANGE_SERVICE_H #ifndef _TALER_EXCHANGE_SERVICE_H
#define _TALER_EXCHANGE_SERVICE_H #define _TALER_EXCHANGE_SERVICE_H
@ -1618,7 +1619,8 @@ typedef void
/** /**
* Get a CS R using a /csr-withdraw request. * Get a CS R using a /csr-withdraw request.
* *
* @param exchange the exchange handle; the exchange must be ready to operate * @param curl_ctx The curl context to use for the requests
* @param exchange_url Base-URL to the excnange
* @param pk Which denomination key is the /csr request for * @param pk Which denomination key is the /csr request for
* @param nonce client nonce for the request * @param nonce client nonce for the request
* @param res_cb the callback to call when the final result for this request is available * @param res_cb the callback to call when the final result for this request is available
@ -1629,7 +1631,8 @@ typedef void
*/ */
struct TALER_EXCHANGE_CsRWithdrawHandle * struct TALER_EXCHANGE_CsRWithdrawHandle *
TALER_EXCHANGE_csr_withdraw ( TALER_EXCHANGE_csr_withdraw (
struct TALER_EXCHANGE_Handle *exchange, struct GNUNET_CURL_Context *curl_ctx,
const char *exchange_url,
const struct TALER_EXCHANGE_DenomPublicKey *pk, const struct TALER_EXCHANGE_DenomPublicKey *pk,
const struct TALER_CsNonce *nonce, const struct TALER_CsNonce *nonce,
TALER_EXCHANGE_CsRWithdrawCallback res_cb, TALER_EXCHANGE_CsRWithdrawCallback res_cb,
@ -2448,7 +2451,9 @@ typedef void
* disk before calling, and be ready to repeat the request with the * disk before calling, and be ready to repeat the request with the
* same arguments in case of failures. * same arguments in case of failures.
* *
* @param exchange the exchange handle; the exchange must be ready to operate * @param curl_ctx The curl context to use
* @param exchange_url The base-URL of the exchange
* @param keys The /keys material from the exchange
* @param reserve_priv private key of the reserve to withdraw from * @param reserve_priv private key of the reserve to withdraw from
* @param wci inputs that determine the planchet * @param wci inputs that determine the planchet
* @param res_cb the callback to call when the final result for this request is available * @param res_cb the callback to call when the final result for this request is available
@ -2459,7 +2464,9 @@ typedef void
*/ */
struct TALER_EXCHANGE_WithdrawHandle * struct TALER_EXCHANGE_WithdrawHandle *
TALER_EXCHANGE_withdraw ( TALER_EXCHANGE_withdraw (
struct TALER_EXCHANGE_Handle *exchange, struct GNUNET_CURL_Context *curl_ctx,
const char *exchange_url,
struct TALER_EXCHANGE_Keys *keys,
const struct TALER_ReservePrivateKeyP *reserve_priv, const struct TALER_ReservePrivateKeyP *reserve_priv,
const struct TALER_EXCHANGE_WithdrawCoinInput *wci, const struct TALER_EXCHANGE_WithdrawCoinInput *wci,
TALER_EXCHANGE_WithdrawCallback res_cb, TALER_EXCHANGE_WithdrawCallback res_cb,
@ -2575,7 +2582,9 @@ typedef void
* disk before calling, and be ready to repeat the request with the * disk before calling, and be ready to repeat the request with the
* same arguments in case of failures. * same arguments in case of failures.
* *
* @param exchange the exchange handle; the exchange must be ready to operate * @param curl_ctx The curl context to use
* @param exchange_url The base-URL of the exchange
* @param keys The /keys material from the exchange
* @param reserve_priv private key of the reserve to withdraw from * @param reserve_priv private key of the reserve to withdraw from
* @param wcis inputs that determine the planchets * @param wcis inputs that determine the planchets
* @param wci_length number of entries in @a wcis * @param wci_length number of entries in @a wcis
@ -2587,7 +2596,9 @@ typedef void
*/ */
struct TALER_EXCHANGE_BatchWithdrawHandle * struct TALER_EXCHANGE_BatchWithdrawHandle *
TALER_EXCHANGE_batch_withdraw ( TALER_EXCHANGE_batch_withdraw (
struct TALER_EXCHANGE_Handle *exchange, struct GNUNET_CURL_Context *curl_ctx,
const char *exchange_url,
const struct TALER_EXCHANGE_Keys *keys,
const struct TALER_ReservePrivateKeyP *reserve_priv, const struct TALER_ReservePrivateKeyP *reserve_priv,
const struct TALER_EXCHANGE_WithdrawCoinInput *wcis, const struct TALER_EXCHANGE_WithdrawCoinInput *wcis,
unsigned int wci_length, unsigned int wci_length,
@ -2668,7 +2679,9 @@ struct TALER_EXCHANGE_Withdraw2Handle;
* disk before calling, and be ready to repeat the request with the * disk before calling, and be ready to repeat the request with the
* same arguments in case of failures. * same arguments in case of failures.
* *
* @param exchange the exchange handle; the exchange must be ready to operate * @param curl_ctx The curl-context to use
* @param exchange_url The base-URL of the exchange
* @param keys The /keys material from the exchange
* @param pd planchet details of the planchet to withdraw * @param pd planchet details of the planchet to withdraw
* @param reserve_priv private key of the reserve to withdraw from * @param reserve_priv private key of the reserve to withdraw from
* @param res_cb the callback to call when the final result for this request is available * @param res_cb the callback to call when the final result for this request is available
@ -2679,7 +2692,9 @@ struct TALER_EXCHANGE_Withdraw2Handle;
*/ */
struct TALER_EXCHANGE_Withdraw2Handle * struct TALER_EXCHANGE_Withdraw2Handle *
TALER_EXCHANGE_withdraw2 ( TALER_EXCHANGE_withdraw2 (
struct TALER_EXCHANGE_Handle *exchange, struct GNUNET_CURL_Context *curl_ctx,
const char *exchange_url,
struct TALER_EXCHANGE_Keys *keys,
const struct TALER_PlanchetDetail *pd, const struct TALER_PlanchetDetail *pd,
const struct TALER_ReservePrivateKeyP *reserve_priv, const struct TALER_ReservePrivateKeyP *reserve_priv,
TALER_EXCHANGE_Withdraw2Callback res_cb, TALER_EXCHANGE_Withdraw2Callback res_cb,
@ -2765,7 +2780,9 @@ struct TALER_EXCHANGE_BatchWithdraw2Handle;
* disk before calling, and be ready to repeat the request with the * disk before calling, and be ready to repeat the request with the
* same arguments in case of failures. * same arguments in case of failures.
* *
* @param exchange the exchange handle; the exchange must be ready to operate * @param curl_ctx The curl context to use
* @param exchange_url The base-URL of the exchange
* @param keys The /keys material from the exchange
* @param pds array of planchet details of the planchet to withdraw * @param pds array of planchet details of the planchet to withdraw
* @param pds_length number of entries in the @a pds array * @param pds_length number of entries in the @a pds array
* @param reserve_priv private key of the reserve to withdraw from * @param reserve_priv private key of the reserve to withdraw from
@ -2777,7 +2794,9 @@ struct TALER_EXCHANGE_BatchWithdraw2Handle;
*/ */
struct TALER_EXCHANGE_BatchWithdraw2Handle * struct TALER_EXCHANGE_BatchWithdraw2Handle *
TALER_EXCHANGE_batch_withdraw2 ( TALER_EXCHANGE_batch_withdraw2 (
struct TALER_EXCHANGE_Handle *exchange, struct GNUNET_CURL_Context *curl_ctx,
const char *exchange_url,
const struct TALER_EXCHANGE_Keys *keys,
const struct TALER_ReservePrivateKeyP *reserve_priv, const struct TALER_ReservePrivateKeyP *reserve_priv,
const struct TALER_PlanchetDetail *pds, const struct TALER_PlanchetDetail *pds,
unsigned int pds_length, unsigned int pds_length,
@ -2796,6 +2815,119 @@ TALER_EXCHANGE_batch_withdraw2_cancel (
struct TALER_EXCHANGE_BatchWithdraw2Handle *wh); struct TALER_EXCHANGE_BatchWithdraw2Handle *wh);
/* ********************* /reserve/$RESERVE_PUB/age-withdraw *************** */
/**
* @brief Information needed to withdraw age restricted coins.
*/
struct TALER_EXCHANGE_AgeWithdrawCoinInput
{
/* The master secret from which we derive all other relevant values for
* the coin: private key, nonces (if applicable) and age restriction
*/
const struct TALER_PlanchetMasterSecretP secret[TALER_CNC_KAPPA];
/* The denomination of the coin. Must support age restriction, i.e
* its .keys.age_mask MUST not be 0 */
const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
};
/**
* @brief A handle to a /reserves/$RESERVE_PUB/age-withdraw request
*/
struct TALER_EXCHANGE_AgeWithdrawHandle;
/**
* @brief Details about the response for a age withdraw request.
*/
struct TALER_EXCHANGE_AgeWithdrawResponse
{
/**
* HTTP response data.
*/
struct TALER_EXCHANGE_HttpResponse hr;
/**
* Details about the response
*/
union
{
/**
* Details if the status is #MHD_HTTP_OK.
*/
struct
{
/**
* Index that should not be revealed during the age-withdraw reveal phase.
* The struct TALER_PlanchetMasterSecretP * from the request
* with this index are the ones to keep.
*/
uint8_t noreveal_index;
/**
* Signature of the exchange over the origina TALER_AgeWithdrawRequestPS
*/
struct TALER_ExchangeSignatureP exchange_sig;
/**
* Key used by the exchange for @e exchange_sig
*/
struct TALER_ExchangePublicKeyP exchange_pub;
} ok;
/* FIXME[oec]: error cases */
} details;
};
typedef void
(*TALER_EXCHANGE_AgeWithdrawCallback)(
void *cls,
const struct TALER_EXCHANGE_AgeWithdrawResponse *awr);
/**
* Submit an age-withdraw request to the exchange and get the exchange's
* response.
*
* This API is typically used by a wallet. Note that to ensure that
* no money is lost in case of hardware failures, the provided
* argument @a rd should be committed to persistent storage
* prior to calling this function.
*
* @param curl_ctx The curl context
* @param exchange_url The base url of the exchange
* @parm keys The denomination keys from the exchange
* @param reserve_priv The pivate key to the reserve
* @param coin_inputs The input for the coins to withdraw
* @param num_coins The number of elements in @e coin_inputs
* @param max_age The maximum age we commit to.
* @param res_cb A callback for the result, maybe NULL
* @param res_cb_cls A closure for @e res_cb, maybe NULL
* @return a handle for this request; NULL if the argument was invalid.
* In this case, the callback will not be called.
*/
struct TALER_EXCHANGE_AgeWithdrawHandle *
TALER_EXCHANGE_age_withdraw (
struct GNUNET_CURL_Context *curl_ctx,
const char *exchange_url,
struct TALER_EXCHANGE_Keys *keys,
const struct TALER_ReservePrivateKeyP *reserve_priv,
const struct TALER_EXCHANGE_AgeWithdrawCoinInput *coin_inputs,
size_t num_coins,
uint8_t max_age,
TALER_EXCHANGE_AgeWithdrawCallback res_cb,
void *res_cb_cls);
/**
* Cancel a age-withdraw request. This function cannot be used
* on a request handle if a response is already served for it.
*
* @param awh the age-withdraw handle
*/
void
TALER_EXCHANGE_age_withdraw_cancel (
struct TALER_EXCHANGE_AgeWithdrawHandle *awh);
/* ********************* /refresh/melt+reveal ***************************** */ /* ********************* /refresh/melt+reveal ***************************** */
@ -3565,7 +3697,7 @@ TALER_EXCHANGE_verify_coin_history (
*/ */
enum GNUNET_GenericReturnValue enum GNUNET_GenericReturnValue
TALER_EXCHANGE_parse_reserve_history ( TALER_EXCHANGE_parse_reserve_history (
struct TALER_EXCHANGE_Keys *keys, const struct TALER_EXCHANGE_Keys *keys,
const json_t *history, const json_t *history,
const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_ReservePublicKeyP *reserve_pub,
const char *currency, const char *currency,

View File

@ -1215,8 +1215,7 @@ struct TALER_EXCHANGEDB_AgeWithdraw
/** /**
* Signature confirming the age withdrawal commitment, matching @e * Signature confirming the age withdrawal commitment, matching @e
* reserve_pub, @e maximum_age_group and @e h_commitment and @e * reserve_pub, @e max_age and @e h_commitment and @e amount_with_fee.
* total_amount_with_fee.
*/ */
struct TALER_ReserveSignatureP reserve_sig; struct TALER_ReserveSignatureP reserve_sig;

View File

@ -22,6 +22,7 @@ libtalerexchange_la_LDFLAGS = \
-no-undefined -no-undefined
libtalerexchange_la_SOURCES = \ libtalerexchange_la_SOURCES = \
exchange_api_add_aml_decision.c \ exchange_api_add_aml_decision.c \
exchange_api_age_withdraw.c \
exchange_api_auditor_add_denomination.c \ exchange_api_auditor_add_denomination.c \
exchange_api_batch_deposit.c \ exchange_api_batch_deposit.c \
exchange_api_batch_withdraw.c \ exchange_api_batch_withdraw.c \

File diff suppressed because it is too large Load Diff

View File

@ -97,9 +97,20 @@ struct TALER_EXCHANGE_BatchWithdrawHandle
{ {
/** /**
* The connection to exchange this request handle will use * The curl context to use
*/ */
struct TALER_EXCHANGE_Handle *exchange; struct GNUNET_CURL_Context *curl_ctx;
/**
* The base URL to the exchange
*/
const char *exchange_url;
/**
* The /keys information from the exchange
*/
const struct TALER_EXCHANGE_Keys *keys;
/** /**
* Handle for the actual (internal) batch withdraw operation. * Handle for the actual (internal) batch withdraw operation.
@ -255,7 +266,9 @@ phase_two (struct TALER_EXCHANGE_BatchWithdrawHandle *wh)
pds[i] = cd->pd; pds[i] = cd->pd;
} }
wh->wh2 = TALER_EXCHANGE_batch_withdraw2 ( wh->wh2 = TALER_EXCHANGE_batch_withdraw2 (
wh->exchange, wh->curl_ctx,
wh->exchange_url,
wh->keys,
wh->reserve_priv, wh->reserve_priv,
pds, pds,
wh->num_coins, wh->num_coins,
@ -322,7 +335,9 @@ withdraw_cs_stage_two_callback (
struct TALER_EXCHANGE_BatchWithdrawHandle * struct TALER_EXCHANGE_BatchWithdrawHandle *
TALER_EXCHANGE_batch_withdraw ( TALER_EXCHANGE_batch_withdraw (
struct TALER_EXCHANGE_Handle *exchange, struct GNUNET_CURL_Context *curl_ctx,
const char *exchange_url,
const struct TALER_EXCHANGE_Keys *keys,
const struct TALER_ReservePrivateKeyP *reserve_priv, const struct TALER_ReservePrivateKeyP *reserve_priv,
const struct TALER_EXCHANGE_WithdrawCoinInput *wcis, const struct TALER_EXCHANGE_WithdrawCoinInput *wcis,
unsigned int wci_length, unsigned int wci_length,
@ -332,7 +347,9 @@ TALER_EXCHANGE_batch_withdraw (
struct TALER_EXCHANGE_BatchWithdrawHandle *wh; struct TALER_EXCHANGE_BatchWithdrawHandle *wh;
wh = GNUNET_new (struct TALER_EXCHANGE_BatchWithdrawHandle); wh = GNUNET_new (struct TALER_EXCHANGE_BatchWithdrawHandle);
wh->exchange = exchange; wh->curl_ctx = curl_ctx;
wh->exchange_url = exchange_url;
wh->keys = keys;
wh->cb = res_cb; wh->cb = res_cb;
wh->cb_cls = res_cb_cls; wh->cb_cls = res_cb_cls;
wh->reserve_priv = reserve_priv; wh->reserve_priv = reserve_priv;
@ -386,7 +403,8 @@ TALER_EXCHANGE_batch_withdraw (
will be done after the /csr-withdraw request! */ will be done after the /csr-withdraw request! */
cd->pd.blinded_planchet.cipher = TALER_DENOMINATION_CS; cd->pd.blinded_planchet.cipher = TALER_DENOMINATION_CS;
cd->csrh = TALER_EXCHANGE_csr_withdraw ( cd->csrh = TALER_EXCHANGE_csr_withdraw (
exchange, curl_ctx,
exchange_url,
&cd->pk, &cd->pk,
&cd->pd.blinded_planchet.details.cs_blinded_planchet.nonce, &cd->pd.blinded_planchet.details.cs_blinded_planchet.nonce,
&withdraw_cs_stage_two_callback, &withdraw_cs_stage_two_callback,

View File

@ -38,16 +38,16 @@
struct TALER_EXCHANGE_BatchWithdraw2Handle struct TALER_EXCHANGE_BatchWithdraw2Handle
{ {
/**
* The connection to exchange this request handle will use
*/
struct TALER_EXCHANGE_Handle *exchange;
/** /**
* The url for this request. * The url for this request.
*/ */
char *url; char *url;
/**
* The /keys material from the exchange
*/
const struct TALER_EXCHANGE_Keys *keys;
/** /**
* Handle for the request. * Handle for the request.
*/ */
@ -219,7 +219,7 @@ reserve_batch_withdraw_payment_required (
if (GNUNET_OK != if (GNUNET_OK !=
TALER_EXCHANGE_parse_reserve_history ( TALER_EXCHANGE_parse_reserve_history (
TALER_EXCHANGE_get_keys (wh->exchange), wh->keys,
history, history,
&wh->reserve_pub, &wh->reserve_pub,
balance.currency, balance.currency,
@ -387,7 +387,9 @@ handle_reserve_batch_withdraw_finished (void *cls,
struct TALER_EXCHANGE_BatchWithdraw2Handle * struct TALER_EXCHANGE_BatchWithdraw2Handle *
TALER_EXCHANGE_batch_withdraw2 ( TALER_EXCHANGE_batch_withdraw2 (
struct TALER_EXCHANGE_Handle *exchange, struct GNUNET_CURL_Context *curl_ctx,
const char *exchange_url,
const struct TALER_EXCHANGE_Keys *keys,
const struct TALER_ReservePrivateKeyP *reserve_priv, const struct TALER_ReservePrivateKeyP *reserve_priv,
const struct TALER_PlanchetDetail *pds, const struct TALER_PlanchetDetail *pds,
unsigned int pds_length, unsigned int pds_length,
@ -395,21 +397,15 @@ TALER_EXCHANGE_batch_withdraw2 (
void *res_cb_cls) void *res_cb_cls)
{ {
struct TALER_EXCHANGE_BatchWithdraw2Handle *wh; struct TALER_EXCHANGE_BatchWithdraw2Handle *wh;
const struct TALER_EXCHANGE_Keys *keys;
const struct TALER_EXCHANGE_DenomPublicKey *dk; const struct TALER_EXCHANGE_DenomPublicKey *dk;
struct TALER_ReserveSignatureP reserve_sig; struct TALER_ReserveSignatureP reserve_sig;
char arg_str[sizeof (struct TALER_ReservePublicKeyP) * 2 + 32]; char arg_str[sizeof (struct TALER_ReservePublicKeyP) * 2 + 32];
struct TALER_BlindedCoinHashP bch; struct TALER_BlindedCoinHashP bch;
json_t *jc; json_t *jc;
keys = TALER_EXCHANGE_get_keys (exchange); GNUNET_assert (NULL != keys);
if (NULL == keys)
{
GNUNET_break (0);
return NULL;
}
wh = GNUNET_new (struct TALER_EXCHANGE_BatchWithdraw2Handle); wh = GNUNET_new (struct TALER_EXCHANGE_BatchWithdraw2Handle);
wh->exchange = exchange; wh->keys = keys;
wh->cb = res_cb; wh->cb = res_cb;
wh->cb_cls = res_cb_cls; wh->cb_cls = res_cb_cls;
wh->num_coins = pds_length; wh->num_coins = pds_length;
@ -430,14 +426,15 @@ TALER_EXCHANGE_batch_withdraw2 (
*end = '\0'; *end = '\0';
GNUNET_snprintf (arg_str, GNUNET_snprintf (arg_str,
sizeof (arg_str), sizeof (arg_str),
"/reserves/%s/batch-withdraw", "reserves/%s/batch-withdraw",
pub_str); pub_str);
} }
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Attempting to batch-withdraw from reserve %s\n", "Attempting to batch-withdraw from reserve %s\n",
TALER_B2S (&wh->reserve_pub)); TALER_B2S (&wh->reserve_pub));
wh->url = TEAH_path_to_url (exchange, wh->url = TALER_url_join (exchange_url,
arg_str); arg_str,
NULL);
if (NULL == wh->url) if (NULL == wh->url)
{ {
GNUNET_break (0); GNUNET_break (0);
@ -513,13 +510,11 @@ TALER_EXCHANGE_batch_withdraw2 (
} }
{ {
CURL *eh; CURL *eh;
struct GNUNET_CURL_Context *ctx;
json_t *req; json_t *req;
req = GNUNET_JSON_PACK ( req = GNUNET_JSON_PACK (
GNUNET_JSON_pack_array_steal ("planchets", GNUNET_JSON_pack_array_steal ("planchets",
jc)); jc));
ctx = TEAH_handle_to_context (exchange);
eh = TALER_EXCHANGE_curl_easy_get_ (wh->url); eh = TALER_EXCHANGE_curl_easy_get_ (wh->url);
if ( (NULL == eh) || if ( (NULL == eh) ||
(GNUNET_OK != (GNUNET_OK !=
@ -535,7 +530,7 @@ TALER_EXCHANGE_batch_withdraw2 (
return NULL; return NULL;
} }
json_decref (req); json_decref (req);
wh->job = GNUNET_CURL_job_add2 (ctx, wh->job = GNUNET_CURL_job_add2 (curl_ctx,
eh, eh,
wh->post_ctx.headers, wh->post_ctx.headers,
&handle_reserve_batch_withdraw_finished, &handle_reserve_batch_withdraw_finished,

View File

@ -36,7 +36,7 @@ struct HistoryParseContext
/** /**
* Keys of the exchange we use. * Keys of the exchange we use.
*/ */
struct TALER_EXCHANGE_Keys *keys; const struct TALER_EXCHANGE_Keys *keys;
/** /**
* Our reserve public key. * Our reserve public key.
@ -647,7 +647,7 @@ parse_close (struct TALER_EXCHANGE_ReserveHistoryEntry *rh,
enum GNUNET_GenericReturnValue enum GNUNET_GenericReturnValue
TALER_EXCHANGE_parse_reserve_history ( TALER_EXCHANGE_parse_reserve_history (
struct TALER_EXCHANGE_Keys *keys, const struct TALER_EXCHANGE_Keys *keys,
const json_t *history, const json_t *history,
const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_ReservePublicKeyP *reserve_pub,
const char *currency, const char *currency,

View File

@ -38,11 +38,6 @@
*/ */
struct TALER_EXCHANGE_CsRWithdrawHandle struct TALER_EXCHANGE_CsRWithdrawHandle
{ {
/**
* The connection to exchange this request handle will use
*/
struct TALER_EXCHANGE_Handle *exchange;
/** /**
* Function to call with the result. * Function to call with the result.
*/ */
@ -204,11 +199,13 @@ handle_csr_finished (void *cls,
struct TALER_EXCHANGE_CsRWithdrawHandle * struct TALER_EXCHANGE_CsRWithdrawHandle *
TALER_EXCHANGE_csr_withdraw (struct TALER_EXCHANGE_Handle *exchange, TALER_EXCHANGE_csr_withdraw (
const struct TALER_EXCHANGE_DenomPublicKey *pk, struct GNUNET_CURL_Context *curl_ctx,
const struct TALER_CsNonce *nonce, const char *exchange_url,
TALER_EXCHANGE_CsRWithdrawCallback res_cb, const struct TALER_EXCHANGE_DenomPublicKey *pk,
void *res_cb_cls) const struct TALER_CsNonce *nonce,
TALER_EXCHANGE_CsRWithdrawCallback res_cb,
void *res_cb_cls)
{ {
struct TALER_EXCHANGE_CsRWithdrawHandle *csrh; struct TALER_EXCHANGE_CsRWithdrawHandle *csrh;
@ -218,11 +215,11 @@ TALER_EXCHANGE_csr_withdraw (struct TALER_EXCHANGE_Handle *exchange,
return NULL; return NULL;
} }
csrh = GNUNET_new (struct TALER_EXCHANGE_CsRWithdrawHandle); csrh = GNUNET_new (struct TALER_EXCHANGE_CsRWithdrawHandle);
csrh->exchange = exchange;
csrh->cb = res_cb; csrh->cb = res_cb;
csrh->cb_cls = res_cb_cls; csrh->cb_cls = res_cb_cls;
csrh->url = TEAH_path_to_url (exchange, csrh->url = TALER_url_join (exchange_url,
"/csr-withdraw"); "csr-withdraw",
NULL);
if (NULL == csrh->url) if (NULL == csrh->url)
{ {
GNUNET_free (csrh); GNUNET_free (csrh);
@ -231,7 +228,6 @@ TALER_EXCHANGE_csr_withdraw (struct TALER_EXCHANGE_Handle *exchange,
{ {
CURL *eh; CURL *eh;
struct GNUNET_CURL_Context *ctx;
json_t *req; json_t *req;
req = GNUNET_JSON_PACK ( req = GNUNET_JSON_PACK (
@ -242,7 +238,6 @@ TALER_EXCHANGE_csr_withdraw (struct TALER_EXCHANGE_Handle *exchange,
&pk->h_key, &pk->h_key,
sizeof(struct TALER_DenominationHashP))); sizeof(struct TALER_DenominationHashP)));
GNUNET_assert (NULL != req); GNUNET_assert (NULL != req);
ctx = TEAH_handle_to_context (exchange);
eh = TALER_EXCHANGE_curl_easy_get_ (csrh->url); eh = TALER_EXCHANGE_curl_easy_get_ (csrh->url);
if ( (NULL == eh) || if ( (NULL == eh) ||
(GNUNET_OK != (GNUNET_OK !=
@ -259,7 +254,7 @@ TALER_EXCHANGE_csr_withdraw (struct TALER_EXCHANGE_Handle *exchange,
return NULL; return NULL;
} }
json_decref (req); json_decref (req);
csrh->job = GNUNET_CURL_job_add2 (ctx, csrh->job = GNUNET_CURL_job_add2 (curl_ctx,
eh, eh,
csrh->post_ctx.headers, csrh->post_ctx.headers,
&handle_csr_finished, &handle_csr_finished,

View File

@ -25,7 +25,6 @@
#define _TALER_CURL_DEFAULTS_H #define _TALER_CURL_DEFAULTS_H
#include "platform.h"
#include <gnunet/gnunet_curl_lib.h> #include <gnunet/gnunet_curl_lib.h>

View File

@ -1229,6 +1229,8 @@ TALER_EXCHANGE_check_keys_current (struct TALER_EXCHANGE_Handle *exchange,
bool force_download = 0 != (flags & TALER_EXCHANGE_CKF_FORCE_DOWNLOAD); bool force_download = 0 != (flags & TALER_EXCHANGE_CKF_FORCE_DOWNLOAD);
bool pull_all_keys = 0 != (flags & TALER_EXCHANGE_CKF_PULL_ALL_KEYS); bool pull_all_keys = 0 != (flags & TALER_EXCHANGE_CKF_PULL_ALL_KEYS);
GNUNET_assert (NULL != exchange);
if ( (NULL != cb) && if ( (NULL != cb) &&
( (exchange->cert_cb != cb) || ( (exchange->cert_cb != cb) ||
(exchange->cert_cb_cls != cb_cls) ) ) (exchange->cert_cb_cls != cb_cls) ) )

View File

@ -504,6 +504,7 @@ csr_cb (void *cls,
} }
/* FIXME: refactor this to use struct TALER_EXCHANGE_Handle */
struct TALER_EXCHANGE_MeltHandle * struct TALER_EXCHANGE_MeltHandle *
TALER_EXCHANGE_melt ( TALER_EXCHANGE_melt (
struct GNUNET_CURL_Context *ctx, struct GNUNET_CURL_Context *ctx,

View File

@ -303,6 +303,7 @@ handle_refresh_reveal_finished (void *cls,
} }
/* FIXME: refactor this to use struct TALER_EXCHANGE_Handle */
struct TALER_EXCHANGE_RefreshesRevealHandle * struct TALER_EXCHANGE_RefreshesRevealHandle *
TALER_EXCHANGE_refreshes_reveal ( TALER_EXCHANGE_refreshes_reveal (
struct GNUNET_CURL_Context *ctx, struct GNUNET_CURL_Context *ctx,

View File

@ -39,9 +39,19 @@ struct TALER_EXCHANGE_WithdrawHandle
{ {
/** /**
* The connection to exchange this request handle will use * The curl context to use
*/ */
struct TALER_EXCHANGE_Handle *exchange; struct GNUNET_CURL_Context *curl_ctx;
/**
* The base-URL to the exchange
*/
const char *exchange_url;
/**
* The /keys material from the exchange
*/
struct TALER_EXCHANGE_Keys *keys;
/** /**
* Handle for the actual (internal) withdraw operation. * Handle for the actual (internal) withdraw operation.
@ -232,7 +242,9 @@ withdraw_cs_stage_two_callback (
GNUNET_break (0); GNUNET_break (0);
break; break;
} }
wh->wh2 = TALER_EXCHANGE_withdraw2 (wh->exchange, wh->wh2 = TALER_EXCHANGE_withdraw2 (wh->curl_ctx,
wh->exchange_url,
wh->keys,
&wh->pd, &wh->pd,
wh->reserve_priv, wh->reserve_priv,
&handle_reserve_withdraw_finished, &handle_reserve_withdraw_finished,
@ -249,7 +261,9 @@ withdraw_cs_stage_two_callback (
struct TALER_EXCHANGE_WithdrawHandle * struct TALER_EXCHANGE_WithdrawHandle *
TALER_EXCHANGE_withdraw ( TALER_EXCHANGE_withdraw (
struct TALER_EXCHANGE_Handle *exchange, struct GNUNET_CURL_Context *curl_ctx,
const char *exchange_url,
struct TALER_EXCHANGE_Keys *keys,
const struct TALER_ReservePrivateKeyP *reserve_priv, const struct TALER_ReservePrivateKeyP *reserve_priv,
const struct TALER_EXCHANGE_WithdrawCoinInput *wci, const struct TALER_EXCHANGE_WithdrawCoinInput *wci,
TALER_EXCHANGE_WithdrawCallback res_cb, TALER_EXCHANGE_WithdrawCallback res_cb,
@ -258,7 +272,9 @@ TALER_EXCHANGE_withdraw (
struct TALER_EXCHANGE_WithdrawHandle *wh; struct TALER_EXCHANGE_WithdrawHandle *wh;
wh = GNUNET_new (struct TALER_EXCHANGE_WithdrawHandle); wh = GNUNET_new (struct TALER_EXCHANGE_WithdrawHandle);
wh->exchange = exchange; wh->keys = TALER_EXCHANGE_keys_incref (keys);
wh->exchange_url = exchange_url;
wh->curl_ctx = curl_ctx;
wh->cb = res_cb; wh->cb = res_cb;
wh->cb_cls = res_cb_cls; wh->cb_cls = res_cb_cls;
wh->reserve_priv = reserve_priv; wh->reserve_priv = reserve_priv;
@ -292,7 +308,9 @@ TALER_EXCHANGE_withdraw (
GNUNET_free (wh); GNUNET_free (wh);
return NULL; return NULL;
} }
wh->wh2 = TALER_EXCHANGE_withdraw2 (exchange, wh->wh2 = TALER_EXCHANGE_withdraw2 (curl_ctx,
exchange_url,
keys,
&wh->pd, &wh->pd,
wh->reserve_priv, wh->reserve_priv,
&handle_reserve_withdraw_finished, &handle_reserve_withdraw_finished,
@ -309,7 +327,8 @@ TALER_EXCHANGE_withdraw (
will be done after the /csr-withdraw request! */ will be done after the /csr-withdraw request! */
wh->pd.blinded_planchet.cipher = TALER_DENOMINATION_CS; wh->pd.blinded_planchet.cipher = TALER_DENOMINATION_CS;
wh->csrh = TALER_EXCHANGE_csr_withdraw ( wh->csrh = TALER_EXCHANGE_csr_withdraw (
exchange, curl_ctx,
exchange_url,
&wh->pk, &wh->pk,
&wh->pd.blinded_planchet.details.cs_blinded_planchet.nonce, &wh->pd.blinded_planchet.details.cs_blinded_planchet.nonce,
&withdraw_cs_stage_two_callback, &withdraw_cs_stage_two_callback,
@ -339,6 +358,7 @@ TALER_EXCHANGE_withdraw_cancel (struct TALER_EXCHANGE_WithdrawHandle *wh)
TALER_EXCHANGE_withdraw2_cancel (wh->wh2); TALER_EXCHANGE_withdraw2_cancel (wh->wh2);
wh->wh2 = NULL; wh->wh2 = NULL;
} }
TALER_EXCHANGE_keys_decref (wh->keys);
TALER_denom_pub_free (&wh->pk.key); TALER_denom_pub_free (&wh->pk.key);
GNUNET_free (wh); GNUNET_free (wh);
} }

View File

@ -39,9 +39,9 @@ struct TALER_EXCHANGE_Withdraw2Handle
{ {
/** /**
* The connection to exchange this request handle will use * The /keys material from the exchange
*/ */
struct TALER_EXCHANGE_Handle *exchange; struct TALER_EXCHANGE_Keys *keys;
/** /**
* The url for this request. * The url for this request.
@ -192,8 +192,7 @@ reserve_withdraw_payment_required (
} }
if (GNUNET_OK != if (GNUNET_OK !=
TALER_EXCHANGE_parse_reserve_history (TALER_EXCHANGE_get_keys ( TALER_EXCHANGE_parse_reserve_history (wh->keys,
wh->exchange),
history, history,
&wh->reserve_pub, &wh->reserve_pub,
balance.currency, balance.currency,
@ -361,25 +360,21 @@ handle_reserve_withdraw_finished (void *cls,
struct TALER_EXCHANGE_Withdraw2Handle * struct TALER_EXCHANGE_Withdraw2Handle *
TALER_EXCHANGE_withdraw2 ( TALER_EXCHANGE_withdraw2 (
struct TALER_EXCHANGE_Handle *exchange, struct GNUNET_CURL_Context *curl_ctx,
const char *exchange_url,
struct TALER_EXCHANGE_Keys *keys,
const struct TALER_PlanchetDetail *pd, const struct TALER_PlanchetDetail *pd,
const struct TALER_ReservePrivateKeyP *reserve_priv, const struct TALER_ReservePrivateKeyP *reserve_priv,
TALER_EXCHANGE_Withdraw2Callback res_cb, TALER_EXCHANGE_Withdraw2Callback res_cb,
void *res_cb_cls) void *res_cb_cls)
{ {
struct TALER_EXCHANGE_Withdraw2Handle *wh; struct TALER_EXCHANGE_Withdraw2Handle *wh;
const struct TALER_EXCHANGE_Keys *keys;
const struct TALER_EXCHANGE_DenomPublicKey *dk; const struct TALER_EXCHANGE_DenomPublicKey *dk;
struct TALER_ReserveSignatureP reserve_sig; struct TALER_ReserveSignatureP reserve_sig;
char arg_str[sizeof (struct TALER_ReservePublicKeyP) * 2 + 32]; char arg_str[sizeof (struct TALER_ReservePublicKeyP) * 2 + 32];
struct TALER_BlindedCoinHashP bch; struct TALER_BlindedCoinHashP bch;
keys = TALER_EXCHANGE_get_keys (exchange); GNUNET_assert (NULL != keys);
if (NULL == keys)
{
GNUNET_break (0);
return NULL;
}
dk = TALER_EXCHANGE_get_denomination_key_by_hash (keys, dk = TALER_EXCHANGE_get_denomination_key_by_hash (keys,
&pd->denom_pub_hash); &pd->denom_pub_hash);
if (NULL == dk) if (NULL == dk)
@ -388,7 +383,7 @@ TALER_EXCHANGE_withdraw2 (
return NULL; return NULL;
} }
wh = GNUNET_new (struct TALER_EXCHANGE_Withdraw2Handle); wh = GNUNET_new (struct TALER_EXCHANGE_Withdraw2Handle);
wh->exchange = exchange; wh->keys = TALER_EXCHANGE_keys_incref (keys);
wh->cb = res_cb; wh->cb = res_cb;
wh->cb_cls = res_cb_cls; wh->cb_cls = res_cb_cls;
/* Compute how much we expected to charge to the reserve */ /* Compute how much we expected to charge to the reserve */
@ -418,7 +413,7 @@ TALER_EXCHANGE_withdraw2 (
*end = '\0'; *end = '\0';
GNUNET_snprintf (arg_str, GNUNET_snprintf (arg_str,
sizeof (arg_str), sizeof (arg_str),
"/reserves/%s/withdraw", "reserves/%s/withdraw",
pub_str); pub_str);
} }
@ -448,8 +443,9 @@ TALER_EXCHANGE_withdraw2 (
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Attempting to withdraw from reserve %s\n", "Attempting to withdraw from reserve %s\n",
TALER_B2S (&wh->reserve_pub)); TALER_B2S (&wh->reserve_pub));
wh->url = TEAH_path_to_url (exchange, wh->url = TALER_url_join (exchange_url,
arg_str); arg_str,
NULL);
if (NULL == wh->url) if (NULL == wh->url)
{ {
json_decref (withdraw_obj); json_decref (withdraw_obj);
@ -458,9 +454,7 @@ TALER_EXCHANGE_withdraw2 (
} }
{ {
CURL *eh; CURL *eh;
struct GNUNET_CURL_Context *ctx;
ctx = TEAH_handle_to_context (exchange);
eh = TALER_EXCHANGE_curl_easy_get_ (wh->url); eh = TALER_EXCHANGE_curl_easy_get_ (wh->url);
if ( (NULL == eh) || if ( (NULL == eh) ||
(GNUNET_OK != (GNUNET_OK !=
@ -477,7 +471,7 @@ TALER_EXCHANGE_withdraw2 (
return NULL; return NULL;
} }
json_decref (withdraw_obj); json_decref (withdraw_obj);
wh->job = GNUNET_CURL_job_add2 (ctx, wh->job = GNUNET_CURL_job_add2 (curl_ctx,
eh, eh,
wh->post_ctx.headers, wh->post_ctx.headers,
&handle_reserve_withdraw_finished, &handle_reserve_withdraw_finished,
@ -498,5 +492,6 @@ TALER_EXCHANGE_withdraw2_cancel (struct TALER_EXCHANGE_Withdraw2Handle *wh)
} }
GNUNET_free (wh->url); GNUNET_free (wh->url);
TALER_curl_easy_post_finished (&wh->post_ctx); TALER_curl_easy_post_finished (&wh->post_ctx);
TALER_EXCHANGE_keys_decref (wh->keys);
GNUNET_free (wh); GNUNET_free (wh);
} }

View File

@ -321,12 +321,15 @@ batch_withdraw_run (void *cls,
wci->ps = &cs->ps; wci->ps = &cs->ps;
wci->ach = cs->h_age_commitment; wci->ach = cs->h_age_commitment;
} }
ws->wsh = TALER_EXCHANGE_batch_withdraw (exchange, ws->wsh = TALER_EXCHANGE_batch_withdraw (
rp, TALER_TESTING_interpreter_get_context (is),
wcis, TALER_TESTING_get_exchange_url (is),
ws->num_coins, TALER_TESTING_get_keys (is),
&reserve_batch_withdraw_cb, rp,
ws); wcis,
ws->num_coins,
&reserve_batch_withdraw_cb,
ws);
if (NULL == ws->wsh) if (NULL == ws->wsh)
{ {
GNUNET_break (0); GNUNET_break (0);

View File

@ -410,7 +410,7 @@ withdraw_run (void *cls,
if (NULL == ws->pk) if (NULL == ws->pk)
{ {
dpk = TALER_TESTING_find_pk (TALER_EXCHANGE_get_keys (exchange), dpk = TALER_TESTING_find_pk (TALER_TESTING_get_keys (is),
&ws->amount, &ws->amount,
ws->age > 0); ws->age > 0);
if (NULL == dpk) if (NULL == dpk)
@ -443,11 +443,14 @@ withdraw_run (void *cls,
.ps = &ws->ps, .ps = &ws->ps,
.ach = ws->h_age_commitment .ach = ws->h_age_commitment
}; };
ws->wsh = TALER_EXCHANGE_withdraw (exchange, ws->wsh = TALER_EXCHANGE_withdraw (
rp, TALER_TESTING_interpreter_get_context (is),
&wci, TALER_TESTING_get_exchange_url (is),
&reserve_withdraw_cb, TALER_TESTING_get_keys (is),
ws); rp,
&wci,
&reserve_withdraw_cb,
ws);
} }
if (NULL == ws->wsh) if (NULL == ws->wsh)
{ {

View File

@ -1,232 +0,0 @@
/*
This file is part of TALER
Copyright (C) 2018 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/>
*/
/**
* @file testing/testing_api_helpers_auditor.c
* @brief helper functions
* @author Christian Grothoff
*/
#include "platform.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_curl_lib.h>
#include "taler_testing_lib.h"
#include "taler_auditor_service.h"
/**
* Closure for #cleanup_auditor.
*/
struct CleanupContext
{
/**
* Where we find the state to clean up.
*/
struct TALER_TESTING_Interpreter *is;
/**
* Next cleanup routine to call, NULL for none.
*/
GNUNET_SCHEDULER_TaskCallback fcb;
/**
* Closure for @e fcb
*/
void *fcb_cls;
};
/**
* Function to clean up the auditor connection.
*
* @param cls a `struct CleanupContext`
*/
static void
cleanup_auditor (void *cls)
{
struct CleanupContext *cc = cls;
struct TALER_TESTING_Interpreter *is = cc->is;
TALER_AUDITOR_disconnect (is->auditor);
is->auditor = NULL;
if (NULL != cc->fcb)
cc->fcb (cc->fcb_cls);
GNUNET_free (cc);
}
/**
* Closure for #auditor_main_wrapper()
*/
struct MainWrapperContext
{
/**
* Main function to launch.
*/
TALER_TESTING_Main main_cb;
/**
* Closure for @e main_cb.
*/
void *main_cb_cls;
/**
* Configuration we use.
*/
const struct GNUNET_CONFIGURATION_Handle *cfg;
/**
* Name of the configuration file.
*/
const char *config_filename;
};
/**
* Function called with information about the auditor.
*
* @param cls closure
* @param hr http response details
* @param vi basic information about the auditor
* @param compat protocol compatibility information
*/
static void
auditor_version_cb (void *cls,
const struct TALER_AUDITOR_HttpResponse *hr,
const struct TALER_AUDITOR_VersionInformation *vi,
enum TALER_AUDITOR_VersionCompatibility compat)
{
struct TALER_TESTING_Interpreter *is = cls;
(void) hr;
(void) vi;
if (TALER_AUDITOR_VC_MATCH != compat)
{
TALER_TESTING_interpreter_fail (is);
return;
}
is->auditor_working = GNUNET_YES;
}
/**
* Setup the @a is 'auditor' member before running the main test loop.
*
* @param cls must be a `struct MainWrapperContext *`
* @param[in,out] is interpreter state to setup
*/
static void
auditor_main_wrapper (void *cls,
struct TALER_TESTING_Interpreter *is)
{
struct MainWrapperContext *mwc = cls;
struct CleanupContext *cc;
char *auditor_base_url;
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (mwc->cfg,
"auditor",
"BASE_URL",
&auditor_base_url))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"auditor",
"BASE_URL");
return;
}
is->auditor = TALER_AUDITOR_connect (is->ctx,
auditor_base_url,
&auditor_version_cb,
is);
GNUNET_free (auditor_base_url);
if (NULL == is->auditor)
{
GNUNET_break (0);
return;
}
cc = GNUNET_new (struct CleanupContext);
cc->is = is;
cc->fcb = is->final_cleanup_cb;
cc->fcb_cls = is->final_cleanup_cb_cls;
is->final_cleanup_cb = cleanup_auditor;
is->final_cleanup_cb_cls = cc;
mwc->main_cb (mwc->main_cb_cls,
is);
}
/**
* Install signal handlers plus schedules the main wrapper
* around the "run" method.
*
* @param cls our `struct MainWrapperContext`
* @param cfg configuration we use
* @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise.
* non-GNUNET_OK codes are #GNUNET_SYSERR most of the
* times.
*/
static int
setup_with_cfg (void *cls,
const struct GNUNET_CONFIGURATION_Handle *cfg)
{
struct MainWrapperContext *mwc = cls;
struct TALER_TESTING_SetupContext setup_ctx = {
.config_filename = mwc->config_filename,
.main_cb = &auditor_main_wrapper,
.main_cb_cls = mwc
};
mwc->cfg = cfg;
return TALER_TESTING_setup_with_auditor_and_exchange_cfg (&setup_ctx,
cfg);
}
/**
* Install signal handlers plus schedules the main wrapper
* around the "run" method.
*
* @param main_cb the "run" method which contains all the
* commands.
* @param main_cb_cls a closure for "run", typically NULL.
* @param config_filename configuration filename.
* @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise.
* non-GNUNET_OK codes are #GNUNET_SYSERR most of the
* times.
*/
int
TALER_TESTING_auditor_setup (TALER_TESTING_Main main_cb,
void *main_cb_cls,
const char *config_filename)
{
struct MainWrapperContext mwc = {
.main_cb = main_cb,
.main_cb_cls = main_cb_cls,
.config_filename = config_filename
};
return GNUNET_CONFIGURATION_parse_and_run (config_filename,
&setup_with_cfg,
&mwc);
}
/* end of testing_auditor_api_helpers.c */

View File

@ -413,6 +413,34 @@ TALER_exchange_online_age_withdraw_confirmation_sign (
} }
enum GNUNET_GenericReturnValue
TALER_exchange_online_age_withdraw_confirmation_verify (
const struct TALER_AgeWithdrawCommitmentHashP *h_commitment,
uint32_t noreveal_index,
const struct TALER_ExchangePublicKeyP *exchange_pub,
const struct TALER_ExchangeSignatureP *exchange_sig)
{
struct TALER_AgeWithdrawConfirmationPS confirm = {
.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_AGE_WITHDRAW),
.purpose.size = htonl (sizeof (confirm)),
.h_commitment = *h_commitment,
.noreveal_index = htonl (noreveal_index)
};
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (
TALER_SIGNATURE_EXCHANGE_CONFIRM_AGE_WITHDRAW,
&confirm,
&exchange_sig->eddsa_signature,
&exchange_pub->eddsa_pub))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
return GNUNET_OK;
}
/* TODO:oec: add signature for age-withdraw, age-reveal */ /* TODO:oec: add signature for age-withdraw, age-reveal */

View File

@ -22,6 +22,7 @@
#include "platform.h" #include "platform.h"
#include "taler_util.h" #include "taler_util.h"
#include "taler_signatures.h" #include "taler_signatures.h"
#include <gnunet/gnunet_common.h>
GNUNET_NETWORK_STRUCT_BEGIN GNUNET_NETWORK_STRUCT_BEGIN
@ -621,9 +622,9 @@ struct TALER_AgeWithdrawRequestPS
struct GNUNET_CRYPTO_EccSignaturePurpose purpose; struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
/** /**
* Hash of the commitment of n*kappa coins * The reserve's public key
*/ */
struct TALER_AgeWithdrawCommitmentHashP h_commitment GNUNET_PACKED; struct TALER_ReservePublicKeyP reserve_pub;
/** /**
* Value of the coin being exchanged (matching the denomination key) * Value of the coin being exchanged (matching the denomination key)
@ -635,7 +636,12 @@ struct TALER_AgeWithdrawRequestPS
struct TALER_AmountNBO amount_with_fee; struct TALER_AmountNBO amount_with_fee;
/** /**
* The mask that defines the age groups * Running SHA512 hash of the commitment of n*kappa coins
*/
struct TALER_AgeWithdrawCommitmentHashP h_commitment;
/**
* The mask that defines the age groups. MUST be the same for all denominations.
*/ */
struct TALER_AgeMask mask; struct TALER_AgeMask mask;
@ -665,6 +671,8 @@ TALER_wallet_age_withdraw_sign (
.max_age_group = TALER_get_age_group (mask, max_age) .max_age_group = TALER_get_age_group (mask, max_age)
}; };
GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv,
&req.reserve_pub.eddsa_pub);
TALER_amount_hton (&req.amount_with_fee, TALER_amount_hton (&req.amount_with_fee,
amount_with_fee); amount_with_fee);
GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv, GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv,
@ -685,6 +693,7 @@ TALER_wallet_age_withdraw_verify (
struct TALER_AgeWithdrawRequestPS awsrd = { struct TALER_AgeWithdrawRequestPS awsrd = {
.purpose.size = htonl (sizeof (awsrd)), .purpose.size = htonl (sizeof (awsrd)),
.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_AGE_WITHDRAW), .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_AGE_WITHDRAW),
.reserve_pub = *reserve_pub,
.h_commitment = *h_commitment, .h_commitment = *h_commitment,
.mask = *mask, .mask = *mask,
.max_age_group = TALER_get_age_group (mask, max_age) .max_age_group = TALER_get_age_group (mask, max_age)