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.