taler-docs

Documentation for GNU Taler components, APIs and protocols
Log | Files | Refs | README | LICENSE

002-wallet-exchange-management.rst (14073B)


      1 XX 02: Wallet Exchange Management
      2 #################################
      3 
      4 .. note::
      5 
      6   This design document is deprecated in favor of DD48.
      7 
      8   Trusted exchanges and auditors are no longer something we have.
      9 
     10 Summary
     11 =======
     12 
     13 This document presents the requirements and proposed interface for an API that
     14 wallet-core exposes (to clients such as the CLI, WebExtension, Android Wallet)
     15 to manage exchanges known to and used by the wallet.
     16 
     17 
     18 Motivation
     19 ==========
     20 
     21 There currently is no documented API for this functionality.  The API that the
     22 WebExtension API uses doesn't support all required functionality and exposes
     23 the internal DB storage format.
     24 
     25 
     26 Background and Requirements
     27 ===========================
     28 
     29 The wallet maintains a list of known exchanges.  For each exchange in this
     30 list, the wallet regularly makes network queries to fetch updated information
     31 about the exchange's cryptographic key material and fee structure.
     32 
     33 Additionally, the wallet maintains a list of *trusted auditors*.  Auditors
     34 certify that they audit a (sub)set of denominations offered by the exchange.
     35 
     36 When an exchange is marked as *directly trusted*, the wallet can use it
     37 for withdrawals independent of how the exchange is audited.  Otherwise,
     38 a withdrawal can only proceed if an adequate set of denominations is
     39 audited by a trusted auditor.
     40 
     41 An exchange might only be known the wallet temporarily.  For example,
     42 the wallet UI may allow the user to review the fee structure of an
     43 exchange before the wallet is permanently added to the wallet.
     44 Once an exchange is either (a) marked as trusted or (b) used for a
     45 withdrawal operation, it is marked as permanent.
     46 
     47 Exchanges that are not permanent will be automatically be removed
     48 ("garbage-collected") by the wallet after some time.
     49 
     50 Exchanges also expose their terms of service (ToS) document.
     51 Before withdrawing, the wallet must ensure that the user
     52 has reviewed and accepted the current version of this ToS document.
     53 
     54 Exchange Management During Withdrawal
     55 -------------------------------------
     56 
     57 The functions to list / view exchanges can either be used in the context of
     58 some exchange management activity or in the context of a withdrawal.  In the
     59 context of a withdrawal, additional filtering must be applied, as not every
     60 exchange is compatible with every withdrawal process.  Additionally, the list
     61 of exchanges might contain additional details pertaining to this particular
     62 withdrawal process.
     63 
     64 An exchange is considered *compatible* if it accepts wire transfers with a wire
     65 method that matches the one of the withdrawal *and* the current exchange
     66 protocol version of the exchange is compatible with the exchange protocol
     67 version of the wallet.
     68 
     69 During the withdrawal process, the bank can also suggest an exchange.  Unless
     70 the exchange is already known to the wallet, this exchange will be added
     71 non-permanently to the wallet.  The bank-suggested will only be selected by
     72 default if no other trusted exchange compatible with the withdrawal process is
     73 known to the wallet.
     74 
     75 Otherwise, the exchange selected by default will be the exchange that has most
     76 recently been used for a withdrawal and is compatible with the current withdrawal.
     77 
     78 
     79 Open Questions
     80 --------------
     81 
     82 If the user reviews a **new** exchange during withdrawal
     83 but then does not decide to use it, will this exchange be permanent?
     84 
     85 Pro:
     86 
     87 * Staying permanently in the list might help when comparing multiple exchanges
     88 
     89 Con:
     90 
     91 * It clutters the list of exchanges, especially as we're not planning
     92   to have a mechanism to remove exchanges.
     93 
     94 => Maybe non-permanent exchanges can be "sticky" to some particular
     95 withdrawal session?
     96 
     97 => CG: Eh, I was expecting there to be a way to remove exchanges at least
     98    from the list of _trusted_ exchanges (if I view the full list, maybe
     99    with a trash bin or a swipe-to-remove functionality, or maybe on the
    100    "detailed view" of the exchange where I can review TOS/PP).
    101    Now, if there are coins actively withdrawn from the exchange, that would
    102    _only_ remove the exchange from the trusted list (what the user sees),
    103    and once all coins have been spent, we could stop refreshing /keys
    104    for that exchange and thus truly "deactivate" it. And once all spent coins
    105    have been "garbage collected", we can then truly forget about everything.
    106    (See above about garbage collection of exchanges.)
    107 
    108    [The auditor list view should also have a similar way to remove auditors.]
    109 
    110    So I'm not sure why you are saying that we are not planning on
    111    having a "mechanism to remove exchanges".
    112 
    113 
    114 Proposed Solution
    115 =================
    116 
    117 We will add the following functions (invoked over IPC with wallet-core).
    118 
    119 queryExchangeInfo
    120 -----------------
    121 
    122 This function will query information about an exchange based on the base URL
    123 of the exchange.  If the exchange is not known yet to the wallet, it will be
    124 added non-permanently.
    125 
    126 Request:
    127 
    128 .. code:: ts
    129 
    130   interface QueryExchangeInfoRequest {
    131     // If given, return error description if the exchange is
    132     // not compatible with this withdrawal operation.
    133     talerWithdrawUri?: string;
    134 
    135     // Exchange base URL to use for the query.
    136     exchangeBaseUrl: string;
    137 
    138     // If true, the query already returns a result even if
    139     // /wire and denomination signatures weren't processed yet
    140     partial: boolean;
    141   }
    142 
    143 Response:
    144 
    145 .. code:: ts
    146 
    147   interface QueryExchangeInfoResponse {
    148     exchangeBaseUrl: string;
    149 
    150     // Master public key
    151     exchangePub: string;
    152 
    153     trustedDirectly: boolean;
    154 
    155     // The "reasonable-ness" of the exchange's fees.
    156     feeStructureSummary: FeeStructureSummary | undefined;
    157 
    158     // Detailed info for each individual denomination
    159     denominations: ExchangeDenomination[];
    160 
    161     // Currency of the exchange.
    162     currency: string;
    163 
    164     // Last observed protocol version range of the exchange
    165     protocolVersionRange: string;
    166 
    167     // Is this exchange either trusted directly or in use?
    168     permanent: boolean;
    169 
    170     // Only present if the last exchange information update
    171     // failed.  Same error as the corresponding pending operation.
    172     lastError?: OperationError;
    173 
    174     wireInfo: ExchangeWireInfo;
    175 
    176     // Auditing state for each auditor.
    177     auditingState: ExchangeAuditingState[];
    178 
    179     // Do we trust an auditor that sufficiently audits
    180     // this exchange's denominations?
    181     trustedViaAuditor: boolean;
    182 
    183     currentTosVersion: string;
    184     acceptedTosVersion: string;
    185 
    186     // When (if so) was this exchange last used for withdrawal?
    187     lastUsedForWithdrawal: Timestamp | undefined;
    188 
    189     withdrawalRelatedInfo?: {
    190       // Can the user accept the withdrawal directly?
    191       // This field is redundant and derivable from other fields.
    192       acceptable: boolean;
    193 
    194       recommendedByBank: boolean;
    195 
    196       // Is this exchange the default exchange for this withdrawal?
    197       isDefault: boolean;
    198 
    199       withdrawalWithdrawnAmount: Amount;
    200       withdrawalCreditAmount: Amount;
    201       withdrawalFeeAmount: Amount;
    202       withdrawalOverheadAmount: Amount;
    203     };
    204   }
    205 
    206   export interface ExchangeWireInfo {
    207     feesForType: { [wireMethod: string]: WireFee[] };
    208     accounts: { paytoUri: string }[];
    209   }
    210 
    211   interface ExchangeAuditingState {
    212     auditorName: string;
    213     auditorBaseUrl: string;
    214     auditorPub: string;
    215 
    216     // Is the auditor already trusted by the wallet?
    217     trustedByWallet: boolean;
    218 
    219     // Does the auditor audit some reasonable set of
    220     // denominations of the exchange?
    221     // If this is false, at least some warning should be shown.
    222     auditedDenominationsReasonable: boolean;
    223   }
    224 
    225 
    226   interface FeeStructureSummary {
    227     // Does the fee structure fulfill our basic reasonableness
    228     // requirements?
    229     reasonable: boolean;
    230 
    231     // Lower range of amounts that this exchange can
    232     // deal with efficiently.
    233     smallAmount: Amount;
    234 
    235     // Upper range of amounts that this exchange can deal
    236     // with efficiently.
    237     bigAmount: Amount;
    238 
    239     // Rest to be specified later
    240     // [ ... ]
    241   }
    242 
    243 
    244 getExchangeTos
    245 --------------
    246 
    247 Request:
    248 
    249 .. code:: ts
    250 
    251   interface GetExchangeTosRequest {
    252     exchangeBaseUrl: string;
    253   }
    254 
    255 
    256 Response:
    257 
    258 .. code:: ts
    259 
    260   interface GetTosResponse {
    261     // Version of the exchange ToS (corresponds to tos ETag)
    262     version: string;
    263 
    264     // Text of the exchange ToS, with (optional) markdown markup.
    265     tosMarkdownText: string;
    266   }
    267 
    268 listExchanges
    269 -------------
    270 
    271 List exchanges known to the wallet.  Either lists all exchanges, or exchanges
    272 related to a withdrawal process.
    273 
    274 Request:
    275 
    276 .. code:: ts
    277 
    278   interface ExchangeListRequest {
    279     // If given, only return exchanges that
    280     // match the currency of this withdrawal
    281     // process.
    282     talerWithdrawUri?: string;
    283   }
    284 
    285 Response:
    286 
    287 .. code:: ts
    288 
    289   interface ExchangeListRespose {
    290     // Only returned in the context of withdrawals.
    291     // The base URL of the exchange that should
    292     // be considered the default for the withdrawal.
    293     withdrawalDefaultExchangeBaseUrl?: string;
    294 
    295     exchanges: {
    296       exchangeBaseUrl: string;
    297 
    298       // Incompatible exchanges are also returned,
    299       // as otherwise users might wonder why their expected
    300       // exchange is not there.
    301       compatibility: "compatible" |
    302         "incompatible-version" | "incompatible-wire";
    303 
    304       // Currency of the exchange.
    305       currency: string;
    306 
    307       // Does the wallet directly trust this exchange?
    308       trustedDirectly: boolean;
    309 
    310       // Is this exchange either trusted directly or in use?
    311       permanent: boolean;
    312 
    313       // This information is only returned if it's
    314       // already available to us, as the list query
    315       // must be fast!
    316       trustedViaAuditor: boolean | undefined;
    317 
    318       // The "reasonable-ness" of the exchange's fees.
    319       // Only provided if available (if we've already queried
    320       // and checked this exchange before).
    321       feeStructureSummary: FeeStructureSummary | undefined;
    322 
    323       // Did the user accept the current version of the exchange's ToS?
    324       currentTosAccepted: boolean;
    325 
    326       // When (if so) was this exchange last used for withdrawal?
    327       lastUsedForWithdrawal: Timestamp | undefined;
    328 
    329       withdrawalRelatedInfo?: {
    330         // Can the user accept the withdrawal directly?
    331         // This field is redundant and derivable from other fields.
    332         acceptable: boolean;
    333 
    334         recommendedByBank: boolean;
    335 
    336         // Is this exchange the default exchange for this withdrawal?
    337         isDefault: boolean;
    338 
    339         withdrawalWithdrawnAmount: Amount;
    340         withdrawalCreditAmount: Amount;
    341         withdrawalFeeAmount: Amount;
    342         withdrawalOverheadAmount: Amount;
    343       };
    344     }[];
    345   }
    346 
    347 
    348 setExchangeTrust
    349 ----------------
    350 
    351 Request:
    352 
    353 .. code:: ts
    354 
    355   interface SetExchangeTrustRequest {
    356     exchangeBaseUrl: string;
    357 
    358     trusted: boolean;
    359   }
    360 
    361 The response is an empty object or an error response.
    362 
    363 setExchangeTosAccepted
    364 ----------------------
    365 
    366 Request:
    367 
    368 .. code:: ts
    369 
    370   interface SetExchangeTosAccepted {
    371     exchangeBaseUrl: string;
    372   }
    373 
    374 The response is an empty object or an error response.
    375 
    376 
    377 Alternatives
    378 ============
    379 
    380 * The UI could directly access the wallet's DB for more flexible access to the
    381   required data.  But this would make the UI less robust against changes in wallet-core.
    382 
    383 
    384 Trust
    385 =====
    386 
    387 Ideally, exchanges come with auditors that are trusted by the wallet and
    388 therefore the user.  An exchange responsible for a three-letter currency is
    389 required to have an auditor, as these currencies are assumed to be legal
    390 tender in a nation state.
    391 
    392 If an exchange and/or an auditor are controlled by an attacker, they can steal
    393 user's funds.  Therefore, users should only use "official" auditors
    394 responsible for their currency.  As users should not be expected to know which
    395 auditors are official nor perform technical verification steps, the wallet
    396 ships with auditors pre-installed.
    397 
    398 It is assumed that -- from the user's point of view -- all auditors for a
    399 given currency are equivalent and that (modulo fees) there are no significant
    400 differences between the coins (fungibility) because most merchants will accept
    401 coins from exchanges of any auditor.  Thus, there is no need for the user
    402 interface to explicitly show the auditor for audited currencies, and we only
    403 show the currency code.  This is mandatory for three-letter currencies, but also
    404 expected to hold for other currency codes if an auditor is used.
    405 
    406 It must be possible to add a custom auditor, for example in case the wallet is
    407 outdated, someone is setting up an experimental deployment and wants to test
    408 it with the wallet, or simply to ensure that the user always has the last word
    409 about whom to trust.  Since adding custom auditors is dangerous and can be
    410 used to trick users into using malicious exchanges, this operation should be
    411 accompanied by appropriate warnings and security confirmations.
    412 
    413 Taler also supports regional currencies which are represented using currency
    414 codes between 4 and 12 letters.  These are not required to have an auditor.
    415 Regional currencies should be shown separate from real currencies in the
    416 wallet's balance sheet. If a regional currency does not have an auditor, its
    417 balance display in the user interface will be accompanied by their exchange's
    418 URL to allow for the fact that different regions or organisations may choose
    419 the same currency code, but use different and non-interoperable exchanges to
    420 handle the independent currencies.
    421 
    422 If a regional currency wants to use more than one exchange, it must use an
    423 auditor. In this case, operators must ensure that from the user's point of
    424 view, the coins of the different exchanges are interoperable.  If a regional
    425 exchange has an auditor, the regional currency code will be shown together
    426 with the URL of the auditor instead of the URL of the exchange.
    427 
    428 When withdrawing money from a regional currency exchange, the user should be
    429 made aware of the fact that the currency of the exchange is not "official".  A
    430 warning should be shown if a currency does not have an auditor or the auditor
    431 is not trusted by the users.  If the user expressed trust for a regional
    432 currency's auditor or a regional currency's exchange, no further warnings will
    433 be shown for the given currency.