fix tslint warnings

This commit is contained in:
Florian Dold 2017-10-15 19:28:35 +02:00
parent 353eeca339
commit 8b2f53e3ed
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
31 changed files with 477 additions and 313 deletions

View File

@ -67,6 +67,7 @@ export namespace Checkable {
props: Prop[]; props: Prop[];
} }
// tslint:disable-next-line:no-shadowed-variable
export const SchemaError = (function SchemaError(this: any, message: string) { export const SchemaError = (function SchemaError(this: any, message: string) {
const that: any = this as any; const that: any = this as any;
that.name = "SchemaError"; that.name = "SchemaError";
@ -167,6 +168,7 @@ export namespace Checkable {
function checkValue(target: any, prop: Prop, path: Path): any { function checkValue(target: any, prop: Prop, path: Path): any {
const type = prop.type; const type = prop.type;
const typeName = type.name || "??";
if (!type) { if (!type) {
throw Error(`assertion failed (prop is ${JSON.stringify(prop)})`); throw Error(`assertion failed (prop is ${JSON.stringify(prop)})`);
} }
@ -183,7 +185,7 @@ export namespace Checkable {
if (innerProp.optional) { if (innerProp.optional) {
continue; continue;
} }
throw new SchemaError(`Property ${innerProp.propertyKey} missing on ${path} of ${type.name||"??"}`); throw new SchemaError(`Property ${innerProp.propertyKey} missing on ${path} of ${typeName}`);
} }
if (!remainingPropNames.delete(innerProp.propertyKey)) { if (!remainingPropNames.delete(innerProp.propertyKey)) {
throw new SchemaError("assertion failed"); throw new SchemaError("assertion failed");
@ -195,7 +197,8 @@ export namespace Checkable {
} }
if (!prop.extraAllowed && remainingPropNames.size !== 0) { if (!prop.extraAllowed && remainingPropNames.size !== 0) {
throw new SchemaError(`superfluous properties ${JSON.stringify(Array.from(remainingPropNames.values()))} of ${type.name||"??"}`); const err = `superfluous properties ${JSON.stringify(Array.from(remainingPropNames.values()))} of ${typeName}`;
throw new SchemaError(err);
} }
return obj; return obj;
} }

View File

@ -22,6 +22,9 @@
/** /**
* Imports. * Imports.
*/ */
import {
canonicalJson,
} from "../helpers";
import { import {
AmountJson, AmountJson,
Amounts, Amounts,
@ -39,9 +42,6 @@ import {
ReserveRecord, ReserveRecord,
WireFee, WireFee,
} from "../types"; } from "../types";
import {
canonicalJson,
} from "../helpers";
import { import {
Amount, Amount,

View File

@ -22,6 +22,7 @@
* Imports. * Imports.
*/ */
import {AmountJson, Amounts} from "./types"; import {AmountJson, Amounts} from "./types";
import URI = require("urijs"); import URI = require("urijs");
/** /**

View File

@ -47,24 +47,24 @@ const jed = new jedLib.Jed(strings[lang]);
/** /**
* Convert template strings to a msgid * Convert template strings to a msgid
*/ */
function toI18nString(strings: ReadonlyArray<string>) { function toI18nString(stringSeq: ReadonlyArray<string>) {
let str = ""; let s = "";
for (let i = 0; i < strings.length; i++) { for (let i = 0; i < stringSeq.length; i++) {
str += strings[i]; s += stringSeq[i];
if (i < strings.length - 1) { if (i < stringSeq.length - 1) {
str += `%${i + 1}$s`; s += `%${i + 1}$s`;
} }
} }
return str; return s;
} }
/** /**
* Internationalize a string template with arbitrary serialized values. * Internationalize a string template with arbitrary serialized values.
*/ */
export function str(strings: TemplateStringsArray, ...values: any[]) { export function str(stringSeq: TemplateStringsArray, ...values: any[]) {
const str = toI18nString(strings); const s = toI18nString(stringSeq);
const tr = jed.translate(str).ifPlural(1, str).fetch(...values); const tr = jed.translate(s).ifPlural(1, s).fetch(...values);
return tr; return tr;
} }

View File

@ -66,67 +66,67 @@ msgstr ""
msgid "Confirm payment" msgid "Confirm payment"
msgstr "Bezahlung bestätigen" msgstr "Bezahlung bestätigen"
#: src/webex/pages/confirm-create-reserve.tsx:179 #: src/webex/pages/confirm-create-reserve.tsx:178
#, fuzzy, c-format #, fuzzy, c-format
msgid "Withdrawal fees:" msgid "Withdrawal fees:"
msgstr "Abheben bei %1$s" msgstr "Abheben bei %1$s"
#: src/webex/pages/confirm-create-reserve.tsx:180 #: src/webex/pages/confirm-create-reserve.tsx:179
#, c-format #, c-format
msgid "Rounding loss:" msgid "Rounding loss:"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:181 #: src/webex/pages/confirm-create-reserve.tsx:180
#, c-format #, c-format
msgid "Earliest expiration (for deposit): %1$s" msgid "Earliest expiration (for deposit): %1$s"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:186 #: src/webex/pages/confirm-create-reserve.tsx:185
#, c-format #, c-format
msgid "# Coins" msgid "# Coins"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:187 #: src/webex/pages/confirm-create-reserve.tsx:186
#, c-format #, c-format
msgid "Value" msgid "Value"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:188 #: src/webex/pages/confirm-create-reserve.tsx:187
#, fuzzy, c-format #, fuzzy, c-format
msgid "Withdraw Fee" msgid "Withdraw Fee"
msgstr "Abheben bei %1$s" msgstr "Abheben bei %1$s"
#: src/webex/pages/confirm-create-reserve.tsx:189 #: src/webex/pages/confirm-create-reserve.tsx:188
#, c-format #, c-format
msgid "Refresh Fee" msgid "Refresh Fee"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:190 #: src/webex/pages/confirm-create-reserve.tsx:189
#, c-format #, c-format
msgid "Deposit Fee" msgid "Deposit Fee"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:244 #: src/webex/pages/confirm-create-reserve.tsx:243
#, c-format #, c-format
msgid "Select" msgid "Select"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:260 #: src/webex/pages/confirm-create-reserve.tsx:259
#, c-format #, c-format
msgid "Error: URL may not be relative" msgid "Error: URL may not be relative"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:328 #: src/webex/pages/confirm-create-reserve.tsx:327
#, c-format #, c-format
msgid "The exchange is trusted by the wallet.\n" msgid "The exchange is trusted by the wallet.\n"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:334 #: src/webex/pages/confirm-create-reserve.tsx:333
#, c-format #, c-format
msgid "The exchange is audited by a trusted auditor.\n" msgid "The exchange is audited by a trusted auditor.\n"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:340 #: src/webex/pages/confirm-create-reserve.tsx:339
#, c-format #, c-format
msgid "" msgid ""
"Warning: The exchange is neither directly trusted nor audited by a trusted " "Warning: The exchange is neither directly trusted nor audited by a trusted "
@ -134,7 +134,7 @@ msgid ""
"If you withdraw from this exchange, it will be trusted in the future.\n" "If you withdraw from this exchange, it will be trusted in the future.\n"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:349 #: src/webex/pages/confirm-create-reserve.tsx:348
#, c-format #, c-format
msgid "" msgid ""
"Using exchange provider%1$s.\n" "Using exchange provider%1$s.\n"
@ -142,58 +142,58 @@ msgid ""
" %2$s in fees.\n" " %2$s in fees.\n"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:363 #: src/webex/pages/confirm-create-reserve.tsx:362
#, c-format #, c-format
msgid "" msgid ""
"Waiting for a response from\n" "Waiting for a response from\n"
" %1$s" " %1$s"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:380 #: src/webex/pages/confirm-create-reserve.tsx:379
#, c-format #, c-format
msgid "" msgid ""
"Information about fees will be available when an exchange provider is " "Information about fees will be available when an exchange provider is "
"selected." "selected."
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:423 #: src/webex/pages/confirm-create-reserve.tsx:422
#, c-format #, c-format
msgid "Accept fees and withdraw" msgid "Accept fees and withdraw"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:428 #: src/webex/pages/confirm-create-reserve.tsx:427
#, c-format #, c-format
msgid "Change Exchange Provider" msgid "Change Exchange Provider"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:485 #: src/webex/pages/confirm-create-reserve.tsx:484
#, c-format #, c-format
msgid "You are about to withdraw %1$s from your bank account into your wallet." msgid "You are about to withdraw %1$s from your bank account into your wallet."
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:570 #: src/webex/pages/confirm-create-reserve.tsx:569
#, c-format #, c-format
msgid "" msgid ""
"Oops, something went wrong. The wallet responded with error status (%1$s)." "Oops, something went wrong. The wallet responded with error status (%1$s)."
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:579 #: src/webex/pages/confirm-create-reserve.tsx:578
#, c-format #, c-format
msgid "Checking URL, please wait ..." msgid "Checking URL, please wait ..."
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:593 #: src/webex/pages/confirm-create-reserve.tsx:592
#, c-format #, c-format
msgid "Can't parse amount: %1$s" msgid "Can't parse amount: %1$s"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:600 #: src/webex/pages/confirm-create-reserve.tsx:599
#, c-format #, c-format
msgid "Can't parse wire_types: %1$s" msgid "Can't parse wire_types: %1$s"
msgstr "" msgstr ""
#. TODO:generic error reporting function or component. #. TODO:generic error reporting function or component.
#: src/webex/pages/confirm-create-reserve.tsx:626 #: src/webex/pages/confirm-create-reserve.tsx:625
#, c-format #, c-format
msgid "Fatal error: \"%1$s\"." msgid "Fatal error: \"%1$s\"."
msgstr "" msgstr ""
@ -262,24 +262,24 @@ msgid ""
" %2$s.\n" " %2$s.\n"
msgstr "Bank bestätig anlegen der Reserve (%1$s) bei %2$s" msgstr "Bank bestätig anlegen der Reserve (%1$s) bei %2$s"
#: src/webex/pages/popup.tsx:359 #: src/webex/pages/popup.tsx:358
#, fuzzy, c-format #, fuzzy, c-format
msgid "" msgid ""
"Started to withdraw\n" "Started to withdraw\n"
" %1$s from%2$s(%3$s).\n" " %1$s from%2$s(%3$s).\n"
msgstr "Reserve (%1$s) mit %2$s bei %3$s erzeugt" msgstr "Reserve (%1$s) mit %2$s bei %3$s erzeugt"
#: src/webex/pages/popup.tsx:369 #: src/webex/pages/popup.tsx:368
#, c-format #, c-format
msgid "Merchant%1$soffered contract%2$s;\n" msgid "Merchant%1$soffered contract%2$s;\n"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:379 #: src/webex/pages/popup.tsx:378
#, fuzzy, c-format #, fuzzy, c-format
msgid "Withdrew%1$sfrom%2$s(%3$s).\n" msgid "Withdrew%1$sfrom%2$s(%3$s).\n"
msgstr "Reserve (%1$s) mit %2$s bei %3$s erzeugt" msgstr "Reserve (%1$s) mit %2$s bei %3$s erzeugt"
#: src/webex/pages/popup.tsx:389 #: src/webex/pages/popup.tsx:388
#, fuzzy, c-format #, fuzzy, c-format
msgid "" msgid ""
"Paid%1$sto merchant%2$s.\n" "Paid%1$sto merchant%2$s.\n"
@ -288,15 +288,20 @@ msgstr "Reserve (%1$s) mit %2$s bei %3$s erzeugt"
#: src/webex/pages/popup.tsx:398 #: src/webex/pages/popup.tsx:398
#, c-format #, c-format
msgid "Merchant%1$sgave a refund over%2$s.\n"
msgstr ""
#: src/webex/pages/popup.tsx:405
#, c-format
msgid "Unknown event (%1$s)" msgid "Unknown event (%1$s)"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:441 #: src/webex/pages/popup.tsx:448
#, c-format #, c-format
msgid "Error: could not retrieve event history" msgid "Error: could not retrieve event history"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:466 #: src/webex/pages/popup.tsx:473
#, c-format #, c-format
msgid "Your wallet has no events recorded." msgid "Your wallet has no events recorded."
msgstr "Ihre Geldbörse verzeichnet keine Vorkommnisse." msgstr "Ihre Geldbörse verzeichnet keine Vorkommnisse."

View File

@ -66,67 +66,67 @@ msgstr ""
msgid "Confirm payment" msgid "Confirm payment"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:179 #: src/webex/pages/confirm-create-reserve.tsx:178
#, c-format #, c-format
msgid "Withdrawal fees:" msgid "Withdrawal fees:"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:180 #: src/webex/pages/confirm-create-reserve.tsx:179
#, c-format #, c-format
msgid "Rounding loss:" msgid "Rounding loss:"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:181 #: src/webex/pages/confirm-create-reserve.tsx:180
#, c-format #, c-format
msgid "Earliest expiration (for deposit): %1$s" msgid "Earliest expiration (for deposit): %1$s"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:186 #: src/webex/pages/confirm-create-reserve.tsx:185
#, c-format #, c-format
msgid "# Coins" msgid "# Coins"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:187 #: src/webex/pages/confirm-create-reserve.tsx:186
#, c-format #, c-format
msgid "Value" msgid "Value"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:188 #: src/webex/pages/confirm-create-reserve.tsx:187
#, c-format #, c-format
msgid "Withdraw Fee" msgid "Withdraw Fee"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:189 #: src/webex/pages/confirm-create-reserve.tsx:188
#, c-format #, c-format
msgid "Refresh Fee" msgid "Refresh Fee"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:190 #: src/webex/pages/confirm-create-reserve.tsx:189
#, c-format #, c-format
msgid "Deposit Fee" msgid "Deposit Fee"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:244 #: src/webex/pages/confirm-create-reserve.tsx:243
#, c-format #, c-format
msgid "Select" msgid "Select"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:260 #: src/webex/pages/confirm-create-reserve.tsx:259
#, c-format #, c-format
msgid "Error: URL may not be relative" msgid "Error: URL may not be relative"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:328 #: src/webex/pages/confirm-create-reserve.tsx:327
#, c-format #, c-format
msgid "The exchange is trusted by the wallet.\n" msgid "The exchange is trusted by the wallet.\n"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:334 #: src/webex/pages/confirm-create-reserve.tsx:333
#, c-format #, c-format
msgid "The exchange is audited by a trusted auditor.\n" msgid "The exchange is audited by a trusted auditor.\n"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:340 #: src/webex/pages/confirm-create-reserve.tsx:339
#, c-format #, c-format
msgid "" msgid ""
"Warning: The exchange is neither directly trusted nor audited by a trusted " "Warning: The exchange is neither directly trusted nor audited by a trusted "
@ -134,7 +134,7 @@ msgid ""
"If you withdraw from this exchange, it will be trusted in the future.\n" "If you withdraw from this exchange, it will be trusted in the future.\n"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:349 #: src/webex/pages/confirm-create-reserve.tsx:348
#, c-format #, c-format
msgid "" msgid ""
"Using exchange provider%1$s.\n" "Using exchange provider%1$s.\n"
@ -142,58 +142,58 @@ msgid ""
" %2$s in fees.\n" " %2$s in fees.\n"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:363 #: src/webex/pages/confirm-create-reserve.tsx:362
#, c-format #, c-format
msgid "" msgid ""
"Waiting for a response from\n" "Waiting for a response from\n"
" %1$s" " %1$s"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:380 #: src/webex/pages/confirm-create-reserve.tsx:379
#, c-format #, c-format
msgid "" msgid ""
"Information about fees will be available when an exchange provider is " "Information about fees will be available when an exchange provider is "
"selected." "selected."
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:423 #: src/webex/pages/confirm-create-reserve.tsx:422
#, c-format #, c-format
msgid "Accept fees and withdraw" msgid "Accept fees and withdraw"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:428 #: src/webex/pages/confirm-create-reserve.tsx:427
#, c-format #, c-format
msgid "Change Exchange Provider" msgid "Change Exchange Provider"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:485 #: src/webex/pages/confirm-create-reserve.tsx:484
#, c-format #, c-format
msgid "You are about to withdraw %1$s from your bank account into your wallet." msgid "You are about to withdraw %1$s from your bank account into your wallet."
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:570 #: src/webex/pages/confirm-create-reserve.tsx:569
#, c-format #, c-format
msgid "" msgid ""
"Oops, something went wrong. The wallet responded with error status (%1$s)." "Oops, something went wrong. The wallet responded with error status (%1$s)."
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:579 #: src/webex/pages/confirm-create-reserve.tsx:578
#, c-format #, c-format
msgid "Checking URL, please wait ..." msgid "Checking URL, please wait ..."
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:593 #: src/webex/pages/confirm-create-reserve.tsx:592
#, c-format #, c-format
msgid "Can't parse amount: %1$s" msgid "Can't parse amount: %1$s"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:600 #: src/webex/pages/confirm-create-reserve.tsx:599
#, c-format #, c-format
msgid "Can't parse wire_types: %1$s" msgid "Can't parse wire_types: %1$s"
msgstr "" msgstr ""
#. TODO:generic error reporting function or component. #. TODO:generic error reporting function or component.
#: src/webex/pages/confirm-create-reserve.tsx:626 #: src/webex/pages/confirm-create-reserve.tsx:625
#, c-format #, c-format
msgid "Fatal error: \"%1$s\"." msgid "Fatal error: \"%1$s\"."
msgstr "" msgstr ""
@ -262,24 +262,24 @@ msgid ""
" %2$s.\n" " %2$s.\n"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:359 #: src/webex/pages/popup.tsx:358
#, c-format #, c-format
msgid "" msgid ""
"Started to withdraw\n" "Started to withdraw\n"
" %1$s from%2$s(%3$s).\n" " %1$s from%2$s(%3$s).\n"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:369 #: src/webex/pages/popup.tsx:368
#, c-format #, c-format
msgid "Merchant%1$soffered contract%2$s;\n" msgid "Merchant%1$soffered contract%2$s;\n"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:379 #: src/webex/pages/popup.tsx:378
#, c-format #, c-format
msgid "Withdrew%1$sfrom%2$s(%3$s).\n" msgid "Withdrew%1$sfrom%2$s(%3$s).\n"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:389 #: src/webex/pages/popup.tsx:388
#, c-format #, c-format
msgid "" msgid ""
"Paid%1$sto merchant%2$s.\n" "Paid%1$sto merchant%2$s.\n"
@ -288,15 +288,20 @@ msgstr ""
#: src/webex/pages/popup.tsx:398 #: src/webex/pages/popup.tsx:398
#, c-format #, c-format
msgid "Merchant%1$sgave a refund over%2$s.\n"
msgstr ""
#: src/webex/pages/popup.tsx:405
#, c-format
msgid "Unknown event (%1$s)" msgid "Unknown event (%1$s)"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:441 #: src/webex/pages/popup.tsx:448
#, c-format #, c-format
msgid "Error: could not retrieve event history" msgid "Error: could not retrieve event history"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:466 #: src/webex/pages/popup.tsx:473
#, c-format #, c-format
msgid "Your wallet has no events recorded." msgid "Your wallet has no events recorded."
msgstr "" msgstr ""

View File

@ -66,67 +66,67 @@ msgstr ""
msgid "Confirm payment" msgid "Confirm payment"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:179 #: src/webex/pages/confirm-create-reserve.tsx:178
#, c-format #, c-format
msgid "Withdrawal fees:" msgid "Withdrawal fees:"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:180 #: src/webex/pages/confirm-create-reserve.tsx:179
#, c-format #, c-format
msgid "Rounding loss:" msgid "Rounding loss:"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:181 #: src/webex/pages/confirm-create-reserve.tsx:180
#, c-format #, c-format
msgid "Earliest expiration (for deposit): %1$s" msgid "Earliest expiration (for deposit): %1$s"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:186 #: src/webex/pages/confirm-create-reserve.tsx:185
#, c-format #, c-format
msgid "# Coins" msgid "# Coins"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:187 #: src/webex/pages/confirm-create-reserve.tsx:186
#, c-format #, c-format
msgid "Value" msgid "Value"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:188 #: src/webex/pages/confirm-create-reserve.tsx:187
#, c-format #, c-format
msgid "Withdraw Fee" msgid "Withdraw Fee"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:189 #: src/webex/pages/confirm-create-reserve.tsx:188
#, c-format #, c-format
msgid "Refresh Fee" msgid "Refresh Fee"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:190 #: src/webex/pages/confirm-create-reserve.tsx:189
#, c-format #, c-format
msgid "Deposit Fee" msgid "Deposit Fee"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:244 #: src/webex/pages/confirm-create-reserve.tsx:243
#, c-format #, c-format
msgid "Select" msgid "Select"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:260 #: src/webex/pages/confirm-create-reserve.tsx:259
#, c-format #, c-format
msgid "Error: URL may not be relative" msgid "Error: URL may not be relative"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:328 #: src/webex/pages/confirm-create-reserve.tsx:327
#, c-format #, c-format
msgid "The exchange is trusted by the wallet.\n" msgid "The exchange is trusted by the wallet.\n"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:334 #: src/webex/pages/confirm-create-reserve.tsx:333
#, c-format #, c-format
msgid "The exchange is audited by a trusted auditor.\n" msgid "The exchange is audited by a trusted auditor.\n"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:340 #: src/webex/pages/confirm-create-reserve.tsx:339
#, c-format #, c-format
msgid "" msgid ""
"Warning: The exchange is neither directly trusted nor audited by a trusted " "Warning: The exchange is neither directly trusted nor audited by a trusted "
@ -134,7 +134,7 @@ msgid ""
"If you withdraw from this exchange, it will be trusted in the future.\n" "If you withdraw from this exchange, it will be trusted in the future.\n"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:349 #: src/webex/pages/confirm-create-reserve.tsx:348
#, c-format #, c-format
msgid "" msgid ""
"Using exchange provider%1$s.\n" "Using exchange provider%1$s.\n"
@ -142,58 +142,58 @@ msgid ""
" %2$s in fees.\n" " %2$s in fees.\n"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:363 #: src/webex/pages/confirm-create-reserve.tsx:362
#, c-format #, c-format
msgid "" msgid ""
"Waiting for a response from\n" "Waiting for a response from\n"
" %1$s" " %1$s"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:380 #: src/webex/pages/confirm-create-reserve.tsx:379
#, c-format #, c-format
msgid "" msgid ""
"Information about fees will be available when an exchange provider is " "Information about fees will be available when an exchange provider is "
"selected." "selected."
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:423 #: src/webex/pages/confirm-create-reserve.tsx:422
#, c-format #, c-format
msgid "Accept fees and withdraw" msgid "Accept fees and withdraw"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:428 #: src/webex/pages/confirm-create-reserve.tsx:427
#, c-format #, c-format
msgid "Change Exchange Provider" msgid "Change Exchange Provider"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:485 #: src/webex/pages/confirm-create-reserve.tsx:484
#, c-format #, c-format
msgid "You are about to withdraw %1$s from your bank account into your wallet." msgid "You are about to withdraw %1$s from your bank account into your wallet."
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:570 #: src/webex/pages/confirm-create-reserve.tsx:569
#, c-format #, c-format
msgid "" msgid ""
"Oops, something went wrong. The wallet responded with error status (%1$s)." "Oops, something went wrong. The wallet responded with error status (%1$s)."
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:579 #: src/webex/pages/confirm-create-reserve.tsx:578
#, c-format #, c-format
msgid "Checking URL, please wait ..." msgid "Checking URL, please wait ..."
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:593 #: src/webex/pages/confirm-create-reserve.tsx:592
#, c-format #, c-format
msgid "Can't parse amount: %1$s" msgid "Can't parse amount: %1$s"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:600 #: src/webex/pages/confirm-create-reserve.tsx:599
#, c-format #, c-format
msgid "Can't parse wire_types: %1$s" msgid "Can't parse wire_types: %1$s"
msgstr "" msgstr ""
#. TODO:generic error reporting function or component. #. TODO:generic error reporting function or component.
#: src/webex/pages/confirm-create-reserve.tsx:626 #: src/webex/pages/confirm-create-reserve.tsx:625
#, c-format #, c-format
msgid "Fatal error: \"%1$s\"." msgid "Fatal error: \"%1$s\"."
msgstr "" msgstr ""
@ -262,24 +262,24 @@ msgid ""
" %2$s.\n" " %2$s.\n"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:359 #: src/webex/pages/popup.tsx:358
#, c-format #, c-format
msgid "" msgid ""
"Started to withdraw\n" "Started to withdraw\n"
" %1$s from%2$s(%3$s).\n" " %1$s from%2$s(%3$s).\n"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:369 #: src/webex/pages/popup.tsx:368
#, c-format #, c-format
msgid "Merchant%1$soffered contract%2$s;\n" msgid "Merchant%1$soffered contract%2$s;\n"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:379 #: src/webex/pages/popup.tsx:378
#, c-format #, c-format
msgid "Withdrew%1$sfrom%2$s(%3$s).\n" msgid "Withdrew%1$sfrom%2$s(%3$s).\n"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:389 #: src/webex/pages/popup.tsx:388
#, c-format #, c-format
msgid "" msgid ""
"Paid%1$sto merchant%2$s.\n" "Paid%1$sto merchant%2$s.\n"
@ -288,15 +288,20 @@ msgstr ""
#: src/webex/pages/popup.tsx:398 #: src/webex/pages/popup.tsx:398
#, c-format #, c-format
msgid "Merchant%1$sgave a refund over%2$s.\n"
msgstr ""
#: src/webex/pages/popup.tsx:405
#, c-format
msgid "Unknown event (%1$s)" msgid "Unknown event (%1$s)"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:441 #: src/webex/pages/popup.tsx:448
#, c-format #, c-format
msgid "Error: could not retrieve event history" msgid "Error: could not retrieve event history"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:466 #: src/webex/pages/popup.tsx:473
#, c-format #, c-format
msgid "Your wallet has no events recorded." msgid "Your wallet has no events recorded."
msgstr "" msgstr ""

View File

@ -66,67 +66,67 @@ msgstr ""
msgid "Confirm payment" msgid "Confirm payment"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:179 #: src/webex/pages/confirm-create-reserve.tsx:178
#, c-format #, c-format
msgid "Withdrawal fees:" msgid "Withdrawal fees:"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:180 #: src/webex/pages/confirm-create-reserve.tsx:179
#, c-format #, c-format
msgid "Rounding loss:" msgid "Rounding loss:"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:181 #: src/webex/pages/confirm-create-reserve.tsx:180
#, c-format #, c-format
msgid "Earliest expiration (for deposit): %1$s" msgid "Earliest expiration (for deposit): %1$s"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:186 #: src/webex/pages/confirm-create-reserve.tsx:185
#, c-format #, c-format
msgid "# Coins" msgid "# Coins"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:187 #: src/webex/pages/confirm-create-reserve.tsx:186
#, c-format #, c-format
msgid "Value" msgid "Value"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:188 #: src/webex/pages/confirm-create-reserve.tsx:187
#, c-format #, c-format
msgid "Withdraw Fee" msgid "Withdraw Fee"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:189 #: src/webex/pages/confirm-create-reserve.tsx:188
#, c-format #, c-format
msgid "Refresh Fee" msgid "Refresh Fee"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:190 #: src/webex/pages/confirm-create-reserve.tsx:189
#, c-format #, c-format
msgid "Deposit Fee" msgid "Deposit Fee"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:244 #: src/webex/pages/confirm-create-reserve.tsx:243
#, c-format #, c-format
msgid "Select" msgid "Select"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:260 #: src/webex/pages/confirm-create-reserve.tsx:259
#, c-format #, c-format
msgid "Error: URL may not be relative" msgid "Error: URL may not be relative"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:328 #: src/webex/pages/confirm-create-reserve.tsx:327
#, c-format #, c-format
msgid "The exchange is trusted by the wallet.\n" msgid "The exchange is trusted by the wallet.\n"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:334 #: src/webex/pages/confirm-create-reserve.tsx:333
#, c-format #, c-format
msgid "The exchange is audited by a trusted auditor.\n" msgid "The exchange is audited by a trusted auditor.\n"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:340 #: src/webex/pages/confirm-create-reserve.tsx:339
#, c-format #, c-format
msgid "" msgid ""
"Warning: The exchange is neither directly trusted nor audited by a trusted " "Warning: The exchange is neither directly trusted nor audited by a trusted "
@ -134,7 +134,7 @@ msgid ""
"If you withdraw from this exchange, it will be trusted in the future.\n" "If you withdraw from this exchange, it will be trusted in the future.\n"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:349 #: src/webex/pages/confirm-create-reserve.tsx:348
#, c-format #, c-format
msgid "" msgid ""
"Using exchange provider%1$s.\n" "Using exchange provider%1$s.\n"
@ -142,58 +142,58 @@ msgid ""
" %2$s in fees.\n" " %2$s in fees.\n"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:363 #: src/webex/pages/confirm-create-reserve.tsx:362
#, c-format #, c-format
msgid "" msgid ""
"Waiting for a response from\n" "Waiting for a response from\n"
" %1$s" " %1$s"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:380 #: src/webex/pages/confirm-create-reserve.tsx:379
#, c-format #, c-format
msgid "" msgid ""
"Information about fees will be available when an exchange provider is " "Information about fees will be available when an exchange provider is "
"selected." "selected."
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:423 #: src/webex/pages/confirm-create-reserve.tsx:422
#, c-format #, c-format
msgid "Accept fees and withdraw" msgid "Accept fees and withdraw"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:428 #: src/webex/pages/confirm-create-reserve.tsx:427
#, c-format #, c-format
msgid "Change Exchange Provider" msgid "Change Exchange Provider"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:485 #: src/webex/pages/confirm-create-reserve.tsx:484
#, c-format #, c-format
msgid "You are about to withdraw %1$s from your bank account into your wallet." msgid "You are about to withdraw %1$s from your bank account into your wallet."
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:570 #: src/webex/pages/confirm-create-reserve.tsx:569
#, c-format #, c-format
msgid "" msgid ""
"Oops, something went wrong. The wallet responded with error status (%1$s)." "Oops, something went wrong. The wallet responded with error status (%1$s)."
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:579 #: src/webex/pages/confirm-create-reserve.tsx:578
#, c-format #, c-format
msgid "Checking URL, please wait ..." msgid "Checking URL, please wait ..."
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:593 #: src/webex/pages/confirm-create-reserve.tsx:592
#, c-format #, c-format
msgid "Can't parse amount: %1$s" msgid "Can't parse amount: %1$s"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:600 #: src/webex/pages/confirm-create-reserve.tsx:599
#, c-format #, c-format
msgid "Can't parse wire_types: %1$s" msgid "Can't parse wire_types: %1$s"
msgstr "" msgstr ""
#. TODO:generic error reporting function or component. #. TODO:generic error reporting function or component.
#: src/webex/pages/confirm-create-reserve.tsx:626 #: src/webex/pages/confirm-create-reserve.tsx:625
#, c-format #, c-format
msgid "Fatal error: \"%1$s\"." msgid "Fatal error: \"%1$s\"."
msgstr "" msgstr ""
@ -262,24 +262,24 @@ msgid ""
" %2$s.\n" " %2$s.\n"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:359 #: src/webex/pages/popup.tsx:358
#, c-format #, c-format
msgid "" msgid ""
"Started to withdraw\n" "Started to withdraw\n"
" %1$s from%2$s(%3$s).\n" " %1$s from%2$s(%3$s).\n"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:369 #: src/webex/pages/popup.tsx:368
#, c-format #, c-format
msgid "Merchant%1$soffered contract%2$s;\n" msgid "Merchant%1$soffered contract%2$s;\n"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:379 #: src/webex/pages/popup.tsx:378
#, c-format #, c-format
msgid "Withdrew%1$sfrom%2$s(%3$s).\n" msgid "Withdrew%1$sfrom%2$s(%3$s).\n"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:389 #: src/webex/pages/popup.tsx:388
#, c-format #, c-format
msgid "" msgid ""
"Paid%1$sto merchant%2$s.\n" "Paid%1$sto merchant%2$s.\n"
@ -288,15 +288,20 @@ msgstr ""
#: src/webex/pages/popup.tsx:398 #: src/webex/pages/popup.tsx:398
#, c-format #, c-format
msgid "Merchant%1$sgave a refund over%2$s.\n"
msgstr ""
#: src/webex/pages/popup.tsx:405
#, c-format
msgid "Unknown event (%1$s)" msgid "Unknown event (%1$s)"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:441 #: src/webex/pages/popup.tsx:448
#, c-format #, c-format
msgid "Error: could not retrieve event history" msgid "Error: could not retrieve event history"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:466 #: src/webex/pages/popup.tsx:473
#, c-format #, c-format
msgid "Your wallet has no events recorded." msgid "Your wallet has no events recorded."
msgstr "" msgstr ""

View File

@ -165,6 +165,9 @@ strings['de'] = {
"Paid%1$sto merchant%2$s.\n (%3$s)\n": [ "Paid%1$sto merchant%2$s.\n (%3$s)\n": [
"Reserve (%1$s) mit %2$s bei %3$s erzeugt" "Reserve (%1$s) mit %2$s bei %3$s erzeugt"
], ],
"Merchant%1$sgave a refund over%2$s.\n": [
""
],
"Unknown event (%1$s)": [ "Unknown event (%1$s)": [
"" ""
], ],
@ -348,6 +351,9 @@ strings['en-US'] = {
"Paid%1$sto merchant%2$s.\n (%3$s)\n": [ "Paid%1$sto merchant%2$s.\n (%3$s)\n": [
"" ""
], ],
"Merchant%1$sgave a refund over%2$s.\n": [
""
],
"Unknown event (%1$s)": [ "Unknown event (%1$s)": [
"" ""
], ],
@ -531,6 +537,9 @@ strings['fr'] = {
"Paid%1$sto merchant%2$s.\n (%3$s)\n": [ "Paid%1$sto merchant%2$s.\n (%3$s)\n": [
"" ""
], ],
"Merchant%1$sgave a refund over%2$s.\n": [
""
],
"Unknown event (%1$s)": [ "Unknown event (%1$s)": [
"" ""
], ],
@ -714,6 +723,9 @@ strings['it'] = {
"Paid%1$sto merchant%2$s.\n (%3$s)\n": [ "Paid%1$sto merchant%2$s.\n (%3$s)\n": [
"" ""
], ],
"Merchant%1$sgave a refund over%2$s.\n": [
""
],
"Unknown event (%1$s)": [ "Unknown event (%1$s)": [
"" ""
], ],

View File

@ -66,67 +66,67 @@ msgstr ""
msgid "Confirm payment" msgid "Confirm payment"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:179 #: src/webex/pages/confirm-create-reserve.tsx:178
#, c-format #, c-format
msgid "Withdrawal fees:" msgid "Withdrawal fees:"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:180 #: src/webex/pages/confirm-create-reserve.tsx:179
#, c-format #, c-format
msgid "Rounding loss:" msgid "Rounding loss:"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:181 #: src/webex/pages/confirm-create-reserve.tsx:180
#, c-format #, c-format
msgid "Earliest expiration (for deposit): %1$s" msgid "Earliest expiration (for deposit): %1$s"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:186 #: src/webex/pages/confirm-create-reserve.tsx:185
#, c-format #, c-format
msgid "# Coins" msgid "# Coins"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:187 #: src/webex/pages/confirm-create-reserve.tsx:186
#, c-format #, c-format
msgid "Value" msgid "Value"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:188 #: src/webex/pages/confirm-create-reserve.tsx:187
#, c-format #, c-format
msgid "Withdraw Fee" msgid "Withdraw Fee"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:189 #: src/webex/pages/confirm-create-reserve.tsx:188
#, c-format #, c-format
msgid "Refresh Fee" msgid "Refresh Fee"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:190 #: src/webex/pages/confirm-create-reserve.tsx:189
#, c-format #, c-format
msgid "Deposit Fee" msgid "Deposit Fee"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:244 #: src/webex/pages/confirm-create-reserve.tsx:243
#, c-format #, c-format
msgid "Select" msgid "Select"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:260 #: src/webex/pages/confirm-create-reserve.tsx:259
#, c-format #, c-format
msgid "Error: URL may not be relative" msgid "Error: URL may not be relative"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:328 #: src/webex/pages/confirm-create-reserve.tsx:327
#, c-format #, c-format
msgid "The exchange is trusted by the wallet.\n" msgid "The exchange is trusted by the wallet.\n"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:334 #: src/webex/pages/confirm-create-reserve.tsx:333
#, c-format #, c-format
msgid "The exchange is audited by a trusted auditor.\n" msgid "The exchange is audited by a trusted auditor.\n"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:340 #: src/webex/pages/confirm-create-reserve.tsx:339
#, c-format #, c-format
msgid "" msgid ""
"Warning: The exchange is neither directly trusted nor audited by a trusted " "Warning: The exchange is neither directly trusted nor audited by a trusted "
@ -134,7 +134,7 @@ msgid ""
"If you withdraw from this exchange, it will be trusted in the future.\n" "If you withdraw from this exchange, it will be trusted in the future.\n"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:349 #: src/webex/pages/confirm-create-reserve.tsx:348
#, c-format #, c-format
msgid "" msgid ""
"Using exchange provider%1$s.\n" "Using exchange provider%1$s.\n"
@ -142,58 +142,58 @@ msgid ""
" %2$s in fees.\n" " %2$s in fees.\n"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:363 #: src/webex/pages/confirm-create-reserve.tsx:362
#, c-format #, c-format
msgid "" msgid ""
"Waiting for a response from\n" "Waiting for a response from\n"
" %1$s" " %1$s"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:380 #: src/webex/pages/confirm-create-reserve.tsx:379
#, c-format #, c-format
msgid "" msgid ""
"Information about fees will be available when an exchange provider is " "Information about fees will be available when an exchange provider is "
"selected." "selected."
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:423 #: src/webex/pages/confirm-create-reserve.tsx:422
#, c-format #, c-format
msgid "Accept fees and withdraw" msgid "Accept fees and withdraw"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:428 #: src/webex/pages/confirm-create-reserve.tsx:427
#, c-format #, c-format
msgid "Change Exchange Provider" msgid "Change Exchange Provider"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:485 #: src/webex/pages/confirm-create-reserve.tsx:484
#, c-format #, c-format
msgid "You are about to withdraw %1$s from your bank account into your wallet." msgid "You are about to withdraw %1$s from your bank account into your wallet."
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:570 #: src/webex/pages/confirm-create-reserve.tsx:569
#, c-format #, c-format
msgid "" msgid ""
"Oops, something went wrong. The wallet responded with error status (%1$s)." "Oops, something went wrong. The wallet responded with error status (%1$s)."
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:579 #: src/webex/pages/confirm-create-reserve.tsx:578
#, c-format #, c-format
msgid "Checking URL, please wait ..." msgid "Checking URL, please wait ..."
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:593 #: src/webex/pages/confirm-create-reserve.tsx:592
#, c-format #, c-format
msgid "Can't parse amount: %1$s" msgid "Can't parse amount: %1$s"
msgstr "" msgstr ""
#: src/webex/pages/confirm-create-reserve.tsx:600 #: src/webex/pages/confirm-create-reserve.tsx:599
#, c-format #, c-format
msgid "Can't parse wire_types: %1$s" msgid "Can't parse wire_types: %1$s"
msgstr "" msgstr ""
#. TODO:generic error reporting function or component. #. TODO:generic error reporting function or component.
#: src/webex/pages/confirm-create-reserve.tsx:626 #: src/webex/pages/confirm-create-reserve.tsx:625
#, c-format #, c-format
msgid "Fatal error: \"%1$s\"." msgid "Fatal error: \"%1$s\"."
msgstr "" msgstr ""
@ -262,24 +262,24 @@ msgid ""
" %2$s.\n" " %2$s.\n"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:359 #: src/webex/pages/popup.tsx:358
#, c-format #, c-format
msgid "" msgid ""
"Started to withdraw\n" "Started to withdraw\n"
" %1$s from%2$s(%3$s).\n" " %1$s from%2$s(%3$s).\n"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:369 #: src/webex/pages/popup.tsx:368
#, c-format #, c-format
msgid "Merchant%1$soffered contract%2$s;\n" msgid "Merchant%1$soffered contract%2$s;\n"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:379 #: src/webex/pages/popup.tsx:378
#, c-format #, c-format
msgid "Withdrew%1$sfrom%2$s(%3$s).\n" msgid "Withdrew%1$sfrom%2$s(%3$s).\n"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:389 #: src/webex/pages/popup.tsx:388
#, c-format #, c-format
msgid "" msgid ""
"Paid%1$sto merchant%2$s.\n" "Paid%1$sto merchant%2$s.\n"
@ -288,15 +288,20 @@ msgstr ""
#: src/webex/pages/popup.tsx:398 #: src/webex/pages/popup.tsx:398
#, c-format #, c-format
msgid "Merchant%1$sgave a refund over%2$s.\n"
msgstr ""
#: src/webex/pages/popup.tsx:405
#, c-format
msgid "Unknown event (%1$s)" msgid "Unknown event (%1$s)"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:441 #: src/webex/pages/popup.tsx:448
#, c-format #, c-format
msgid "Error: could not retrieve event history" msgid "Error: could not retrieve event history"
msgstr "" msgstr ""
#: src/webex/pages/popup.tsx:466 #: src/webex/pages/popup.tsx:473
#, c-format #, c-format
msgid "Your wallet has no events recorded." msgid "Your wallet has no events recorded."
msgstr "" msgstr ""

View File

@ -16,7 +16,7 @@
/** /**
* Semantic versioning, but libtool-style. * Semantic versioning, but libtool-style.
* See https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html * See https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
*/ */
@ -32,7 +32,7 @@ export interface VersionMatchResult {
* Is the first version older (-1), newser (+1) or * Is the first version older (-1), newser (+1) or
* identical (0)? * identical (0)?
*/ */
currentCmp: number currentCmp: number;
} }
interface Version { interface Version {
@ -41,6 +41,9 @@ interface Version {
age: number; age: number;
} }
/**
* Compare two libtool-style version strings.
*/
export function compare(me: string, other: string): VersionMatchResult|undefined { export function compare(me: string, other: string): VersionMatchResult|undefined {
const meVer = parseVersion(me); const meVer = parseVersion(me);
const otherVer = parseVersion(other); const otherVer = parseVersion(other);
@ -60,7 +63,7 @@ export function compare(me: string, other: string): VersionMatchResult|undefined
function parseVersion(v: string): Version|undefined { function parseVersion(v: string): Version|undefined {
const [currentStr, revisionStr, ageStr, ...rest] = v.split(":"); const [currentStr, revisionStr, ageStr, ...rest] = v.split(":");
if (rest.length != 0) { if (rest.length !== 0) {
return undefined; return undefined;
} }
const current = Number.parseInt(currentStr); const current = Number.parseInt(currentStr);

View File

@ -221,8 +221,9 @@ const reportCache: { [reportId: string]: any } = {};
* Formatted as RFC4122 version 4 UUID. * Formatted as RFC4122 version 4 UUID.
*/ */
function getInsecureUuid() { function getInsecureUuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c: string) => {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); const r = Math.random() * 16 | 0;
const v = c === "x" ? r : (r & 0x3 | 0x8);
return v.toString(16); return v.toString(16);
}); });
} }

View File

@ -30,13 +30,13 @@ test.cb("db open", (t) => {
t.is(evt.newVersion, 1); t.is(evt.newVersion, 1);
t.truthy(req.result); t.truthy(req.result);
t.pass(); t.pass();
} };
req.onsuccess = (evt) => { req.onsuccess = (evt) => {
t.is(ncb, 1); t.is(ncb, 1);
t.is(req.result, evt.target); t.is(req.result, evt.target);
t.truthy(req.result); t.truthy(req.result);
t.end(); t.end();
} };
}); });
test.cb("store creation", (t) => { test.cb("store creation", (t) => {
@ -57,10 +57,10 @@ test.cb("store creation", (t) => {
t.is(store3.name, "c-store"); t.is(store3.name, "c-store");
t.deepEqual(Array.from(db.objectStoreNames), ["a-store", "b-store", "c-store"]); t.deepEqual(Array.from(db.objectStoreNames), ["a-store", "b-store", "c-store"]);
t.pass(); t.pass();
} };
req.onsuccess = (evt) => { req.onsuccess = (evt) => {
t.end(); t.end();
} };
}); });
@ -71,10 +71,10 @@ test.cb("put and get", (t) => {
const db: IDBDatabase = req.result; const db: IDBDatabase = req.result;
const store1 = db.createObjectStore("mystore"); const store1 = db.createObjectStore("mystore");
store1.put({answer: 42}, "a"); store1.put({answer: 42}, "a");
} };
req.onsuccess = (evt) => { req.onsuccess = (evt) => {
t.end() t.end();
} };
}); });
@ -88,7 +88,7 @@ test("key path evaluation", (t) => {
b: "hello", b: "hello",
"": "spam", "": "spam",
arr: ["foo", "bar"], arr: ["foo", "bar"],
} };
t.deepEqual(memidb.evaluateKeyPath(obj, ""), obj); t.deepEqual(memidb.evaluateKeyPath(obj, ""), obj);
t.deepEqual(memidb.evaluateKeyPath(obj, "a.b.c"), 42); t.deepEqual(memidb.evaluateKeyPath(obj, "a.b.c"), 42);
t.deepEqual(memidb.evaluateKeyPath(obj, "a.b"), {c: 42}); t.deepEqual(memidb.evaluateKeyPath(obj, "a.b"), {c: 42});
@ -106,7 +106,7 @@ test("key path evaluation with replacement", (t) => {
c: 42, c: 42,
}, },
}, },
} };
memidb.evaluateKeyPath(obj, "a.b.c", 24); memidb.evaluateKeyPath(obj, "a.b.c", 24);
t.is(obj.a.b.c, 24); t.is(obj.a.b.c, 24);
memidb.evaluateKeyPath(obj, "a.b", 24); memidb.evaluateKeyPath(obj, "a.b", 24);

View File

@ -278,7 +278,8 @@ abstract class QueryStreamBase<T> implements QueryStream<T> {
keyFn: (obj: T) => I): QueryStream<JoinResult<T, S>> { keyFn: (obj: T) => I): QueryStream<JoinResult<T, S>> {
this.root.addStoreAccess(store.name, false); this.root.addStoreAccess(store.name, false);
return new QueryStreamKeyJoin<T, S>(this, store.name, keyFn); return new QueryStreamKeyJoin<T, S>(this, store.name, keyFn);
} }
filter(f: (x: any) => boolean): QueryStream<T> { filter(f: (x: any) => boolean): QueryStream<T> {
return new QueryStreamFilter(this, f); return new QueryStreamFilter(this, f);
} }

View File

@ -79,7 +79,9 @@ export function after(delayMs: number, callback: () => void): TimerHandle {
const nullTimerHandle = { const nullTimerHandle = {
clear() { clear() {
} // do nothing
return;
},
}; };
/** /**
@ -109,7 +111,7 @@ export class TimerGroup {
return nullTimerHandle; return nullTimerHandle;
} }
const h = after(delayMs, callback); const h = after(delayMs, callback);
let myId = this.idGen++; const myId = this.idGen++;
this.timerMap[myId] = h; this.timerMap[myId] = h;
const tm = this.timerMap; const tm = this.timerMap;
@ -128,7 +130,7 @@ export class TimerGroup {
return nullTimerHandle; return nullTimerHandle;
} }
const h = every(delayMs, callback); const h = every(delayMs, callback);
let myId = this.idGen++; const myId = this.idGen++;
this.timerMap[myId] = h; this.timerMap[myId] = h;
const tm = this.timerMap; const tm = this.timerMap;

View File

@ -839,7 +839,6 @@ export enum CoinStatus {
} }
/** /**
* State of returning a list of coins * State of returning a list of coins
* to the customer's bank account. * to the customer's bank account.
@ -1198,6 +1197,10 @@ export class ProposalRecord {
@Checkable.Optional(Checkable.Number) @Checkable.Optional(Checkable.Number)
id?: number; id?: number;
/**
* Timestamp (in ms) of when the record
* was created.
*/
@Checkable.Number @Checkable.Number
timestamp: number; timestamp: number;
@ -1450,10 +1453,17 @@ export namespace Amounts {
}; };
} }
/**
* Convert the amount to a float.
*/
export function toFloat(a: AmountJson): number { export function toFloat(a: AmountJson): number {
return a.value + (a.fraction / fractionalBase); return a.value + (a.fraction / fractionalBase);
} }
/**
* Convert a float to a Taler amount.
* Loss of precision possible.
*/
export function fromFloat(floatVal: number, currency: string) { export function fromFloat(floatVal: number, currency: string) {
return { return {
currency, currency,
@ -1495,7 +1505,7 @@ export interface CheckPayResult {
export type ConfirmPayResult = "paid" | "insufficient-balance"; export type ConfirmPayResult = "paid" | "insufficient-balance";
/* /**
* Activity history record. * Activity history record.
*/ */
export interface HistoryRecord { export interface HistoryRecord {
@ -1672,17 +1682,52 @@ export class ReturnCoinsRequest {
} }
/**
* Refund permission in the format that the merchant gives it to us.
*/
export interface RefundPermission { export interface RefundPermission {
/**
* Amount to be refunded.
*/
refund_amount: AmountJson; refund_amount: AmountJson;
/**
* Fee for the refund.
*/
refund_fee: AmountJson; refund_fee: AmountJson;
/**
* Contract terms hash to identify the contract that this
* refund is for.
*/
h_contract_terms: string; h_contract_terms: string;
/**
* Public key of the coin being refunded.
*/
coin_pub: string; coin_pub: string;
/**
* Refund transaction ID between merchant and exchange.
*/
rtransaction_id: number; rtransaction_id: number;
/**
* Public key of the merchant.
*/
merchant_pub: string; merchant_pub: string;
/**
* Signature made by the merchant over the refund permission.
*/
merchant_sig: string; merchant_sig: string;
} }
/**
* Record that stores status information about one purchase, starting from when
* the customer accepts a proposal. Includes refund status if applicable.
*/
export interface PurchaseRecord { export interface PurchaseRecord {
contractTermsHash: string; contractTermsHash: string;
contractTerms: ContractTerms; contractTerms: ContractTerms;

View File

@ -86,8 +86,8 @@ import {
WireFee, WireFee,
WireInfo, WireInfo,
} from "./types"; } from "./types";
import URI = require("urijs");
import URI = require("urijs");
/** /**
@ -229,7 +229,6 @@ class WireDetailJson {
} }
/** /**
* Badge that shows activity for the wallet. * Badge that shows activity for the wallet.
*/ */
@ -277,6 +276,11 @@ export interface DepositCoin {
depositedSig?: string; depositedSig?: string;
} }
/**
* Record stored in the wallet's database when the user sends coins back to
* their own bank account. Stores the status of coins that are deposited to
* the wallet itself, where the wallet acts as a "merchant" for the customer.
*/
export interface CoinsReturnRecord { export interface CoinsReturnRecord {
/** /**
* Hash of the contract for sending coins to our own bank account. * Hash of the contract for sending coins to our own bank account.
@ -356,7 +360,6 @@ function isWithdrawableDenom(d: DenominationRecord) {
} }
function strcmp(s1: string, s2: string): number { function strcmp(s1: string, s2: string): number {
if (s1 < s2) { if (s1 < s2) {
return -1; return -1;
@ -385,10 +388,13 @@ interface SelectPayCoinsResult {
* Considers refresh fees, withdrawal fees after refresh and amounts too small * Considers refresh fees, withdrawal fees after refresh and amounts too small
* to refresh. * to refresh.
*/ */
export function getTotalRefreshCost(denoms: DenominationRecord[], refreshedDenom: DenominationRecord, amountLeft: AmountJson): AmountJson { export function getTotalRefreshCost(denoms: DenominationRecord[],
refreshedDenom: DenominationRecord,
amountLeft: AmountJson): AmountJson {
const withdrawAmount = Amounts.sub(amountLeft, refreshedDenom.feeRefresh).amount; const withdrawAmount = Amounts.sub(amountLeft, refreshedDenom.feeRefresh).amount;
const withdrawDenoms = getWithdrawDenomList(withdrawAmount, denoms); const withdrawDenoms = getWithdrawDenomList(withdrawAmount, denoms);
const resultingAmount = Amounts.add(Amounts.getZero(withdrawAmount.currency), ...withdrawDenoms.map((d) => d.value)).amount; const resultingAmount = Amounts.add(Amounts.getZero(withdrawAmount.currency),
...withdrawDenoms.map((d) => d.value)).amount;
const totalCost = Amounts.sub(amountLeft, resultingAmount).amount; const totalCost = Amounts.sub(amountLeft, resultingAmount).amount;
console.log("total refresh cost for", amountToPretty(amountLeft), "is", amountToPretty(totalCost)); console.log("total refresh cost for", amountToPretty(amountLeft), "is", amountToPretty(totalCost));
return totalCost; return totalCost;
@ -407,7 +413,8 @@ export function selectPayCoins(denoms: DenominationRecord[], cds: CoinWithDenom[
} }
// Sort by ascending deposit fee and denomPub if deposit fee is the same // Sort by ascending deposit fee and denomPub if deposit fee is the same
// (to guarantee deterministic results) // (to guarantee deterministic results)
cds.sort((o1, o2) => Amounts.cmp(o1.denom.feeDeposit, o2.denom.feeDeposit) || strcmp(o1.denom.denomPub, o2.denom.denomPub)); cds.sort((o1, o2) => Amounts.cmp(o1.denom.feeDeposit, o2.denom.feeDeposit) ||
strcmp(o1.denom.denomPub, o2.denom.denomPub));
const currency = cds[0].denom.value.currency; const currency = cds[0].denom.value.currency;
const cdsResult: CoinWithDenom[] = []; const cdsResult: CoinWithDenom[] = [];
let accDepositFee: AmountJson = Amounts.getZero(currency); let accDepositFee: AmountJson = Amounts.getZero(currency);
@ -435,7 +442,7 @@ export function selectPayCoins(denoms: DenominationRecord[], cds: CoinWithDenom[
console.log("coin selection", { coversAmount, isBelowFee, accDepositFee, accAmount, paymentAmount }); console.log("coin selection", { coversAmount, isBelowFee, accDepositFee, accAmount, paymentAmount });
if ((coversAmount && isBelowFee) || coversAmountWithFee) { if ((coversAmount && isBelowFee) || coversAmountWithFee) {
let depositFeeToCover = Amounts.sub(accDepositFee, depositFeeLimit).amount; const depositFeeToCover = Amounts.sub(accDepositFee, depositFeeLimit).amount;
leftAmount = Amounts.sub(leftAmount, depositFeeToCover).amount; leftAmount = Amounts.sub(leftAmount, depositFeeToCover).amount;
console.log("deposit fee to cover", amountToPretty(depositFeeToCover)); console.log("deposit fee to cover", amountToPretty(depositFeeToCover));
@ -798,7 +805,7 @@ export class Wallet {
if (res) { if (res) {
return res.cds; return res.cds;
} }
return undefined return undefined;
} }
@ -1076,10 +1083,10 @@ export class Wallet {
} }
console.log("query for payment succeeded:", t); console.log("query for payment succeeded:", t);
return { return {
contractTermsHash: t.contractTermsHash,
contractTerms: t.contractTerms, contractTerms: t.contractTerms,
payReq: t.payReq, contractTermsHash: t.contractTermsHash,
found: true, found: true,
payReq: t.payReq,
}; };
} }
@ -1100,7 +1107,7 @@ export class Wallet {
// random, exponential backoff truncated at 3 minutes // random, exponential backoff truncated at 3 minutes
const nextDelay = Math.min(2 * retryDelayMs + retryDelayMs * Math.random(), 3000 * 60); const nextDelay = Math.min(2 * retryDelayMs + retryDelayMs * Math.random(), 3000 * 60);
console.warn(`Failed to deplete reserve, trying again in ${retryDelayMs} ms`); console.warn(`Failed to deplete reserve, trying again in ${retryDelayMs} ms`);
this.timerGroup.after(retryDelayMs, () => this.processReserve(reserveRecord, nextDelay)) this.timerGroup.after(retryDelayMs, () => this.processReserve(reserveRecord, nextDelay));
} finally { } finally {
this.stopOperation(opId); this.stopOperation(opId);
} }
@ -1115,7 +1122,8 @@ export class Wallet {
// Throttle concurrent executions of this function, so we don't withdraw too many coins at once. // Throttle concurrent executions of this function, so we don't withdraw too many coins at once.
if (this.processPreCoinConcurrent >= 4 || this.processPreCoinThrottle[preCoin.exchangeBaseUrl]) { if (this.processPreCoinConcurrent >= 4 || this.processPreCoinThrottle[preCoin.exchangeBaseUrl]) {
console.log("delaying processPreCoin"); console.log("delaying processPreCoin");
this.timerGroup.after(retryDelayMs, () => this.processPreCoin(preCoin, Math.min(retryDelayMs * 2, 5 * 60 * 1000))); this.timerGroup.after(retryDelayMs,
() => this.processPreCoin(preCoin, Math.min(retryDelayMs * 2, 5 * 60 * 1000)));
return; return;
} }
console.log("executing processPreCoin"); console.log("executing processPreCoin");
@ -1163,7 +1171,7 @@ export class Wallet {
"ms", e); "ms", e);
// exponential backoff truncated at one minute // exponential backoff truncated at one minute
const nextRetryDelayMs = Math.min(retryDelayMs * 2, 5 * 60 * 1000); const nextRetryDelayMs = Math.min(retryDelayMs * 2, 5 * 60 * 1000);
this.timerGroup.after(retryDelayMs, () => this.processPreCoin(preCoin, nextRetryDelayMs)) this.timerGroup.after(retryDelayMs, () => this.processPreCoin(preCoin, nextRetryDelayMs));
const currentThrottle = this.processPreCoinThrottle[preCoin.exchangeBaseUrl] || 0; const currentThrottle = this.processPreCoinThrottle[preCoin.exchangeBaseUrl] || 0;
this.processPreCoinThrottle[preCoin.exchangeBaseUrl] = currentThrottle + 1; this.processPreCoinThrottle[preCoin.exchangeBaseUrl] = currentThrottle + 1;
@ -1436,12 +1444,12 @@ export class Wallet {
.toArray() .toArray()
); );
possibleDenoms.sort((d1, d2) => { possibleDenoms.sort((d1, d2) => {
let a1 = Amounts.add(d1.feeWithdraw, d1.value).amount; const a1 = Amounts.add(d1.feeWithdraw, d1.value).amount;
let a2 = Amounts.add(d2.feeWithdraw, d2.value).amount; const a2 = Amounts.add(d2.feeWithdraw, d2.value).amount;
return Amounts.cmp(a1, a2); return Amounts.cmp(a1, a2);
}); });
for (let denom of possibleDenoms) { for (const denom of possibleDenoms) {
if (denom.status === DenominationStatus.VerifiedGood) { if (denom.status === DenominationStatus.VerifiedGood) {
return Amounts.add(denom.feeWithdraw, denom.value).amount; return Amounts.add(denom.feeWithdraw, denom.value).amount;
} }
@ -1591,7 +1599,7 @@ export class Wallet {
if (exchangeInfo.protocolVersion) { if (exchangeInfo.protocolVersion) {
versionMatch = LibtoolVersion.compare(WALLET_PROTOCOL_VERSION, exchangeInfo.protocolVersion); versionMatch = LibtoolVersion.compare(WALLET_PROTOCOL_VERSION, exchangeInfo.protocolVersion);
if (versionMatch && !versionMatch.compatible && versionMatch.currentCmp == -1) { if (versionMatch && !versionMatch.compatible && versionMatch.currentCmp === -1) {
console.log("wallet version might be outdated, checking for updates"); console.log("wallet version might be outdated, checking for updates");
chrome.runtime.requestUpdateCheck((status, details) => { chrome.runtime.requestUpdateCheck((status, details) => {
console.log("update check status:", status); console.log("update check status:", status);
@ -1609,10 +1617,10 @@ export class Wallet {
overhead: Amounts.sub(amount, actualCoinCost).amount, overhead: Amounts.sub(amount, actualCoinCost).amount,
selectedDenoms, selectedDenoms,
trustedAuditorPubs, trustedAuditorPubs,
versionMatch,
wireFees, wireFees,
wireInfo, wireInfo,
withdrawFee: acc, withdrawFee: acc,
versionMatch,
}; };
return ret; return ret;
} }
@ -1837,7 +1845,10 @@ export class Wallet {
* Add amount to a balance field, both for * Add amount to a balance field, both for
* the slicing by exchange and currency. * the slicing by exchange and currency.
*/ */
function addTo(balance: WalletBalance, field: keyof WalletBalanceEntry, amount: AmountJson, exchange: string): void { function addTo(balance: WalletBalance,
field: keyof WalletBalanceEntry,
amount: AmountJson,
exchange: string): void {
const z = Amounts.getZero(amount.currency); const z = Amounts.getZero(amount.currency);
const balanceIdentity = {available: z, paybackAmount: z, pendingIncoming: z, pendingPayment: z}; const balanceIdentity = {available: z, paybackAmount: z, pendingIncoming: z, pendingPayment: z};
let entryCurr = balance.byCurrency[amount.currency]; let entryCurr = balance.byCurrency[amount.currency];
@ -1925,9 +1936,9 @@ export class Wallet {
return sw; return sw;
} }
const balance = { const balanceStore = {
byExchange: {},
byCurrency: {}, byCurrency: {},
byExchange: {},
}; };
// Mapping from exchange pub to smallest // Mapping from exchange pub to smallest
// possible amount we can withdraw // possible amount we can withdraw
@ -1941,17 +1952,17 @@ export class Wallet {
const tx = this.q(); const tx = this.q();
tx.iter(Stores.coins) tx.iter(Stores.coins)
.reduce(collectBalances, balance); .reduce(collectBalances, balanceStore);
tx.iter(Stores.refresh) tx.iter(Stores.refresh)
.reduce(collectPendingRefresh, balance); .reduce(collectPendingRefresh, balanceStore);
tx.iter(Stores.reserves) tx.iter(Stores.reserves)
.reduce(collectPendingWithdraw, balance); .reduce(collectPendingWithdraw, balanceStore);
tx.iter(Stores.reserves) tx.iter(Stores.reserves)
.reduce(collectPaybacks, balance); .reduce(collectPaybacks, balanceStore);
tx.iter(Stores.purchases) tx.iter(Stores.purchases)
.reduce(collectPayments, balance); .reduce(collectPayments, balanceStore);
await tx.finish(); await tx.finish();
return balance; return balanceStore;
} }
@ -2231,28 +2242,28 @@ export class Wallet {
// FIXME: do pagination instead of generating the full history // FIXME: do pagination instead of generating the full history
const proposals = await this.q().iter<ProposalRecord>(Stores.proposals).toArray(); const proposals = await this.q().iter<ProposalRecord>(Stores.proposals).toArray();
for (let p of proposals) { for (const p of proposals) {
history.push({ history.push({
type: "offer-contract",
timestamp: p.timestamp,
detail: { detail: {
contractTermsHash: p.contractTermsHash, contractTermsHash: p.contractTermsHash,
merchantName: p.contractTerms.merchant.name, merchantName: p.contractTerms.merchant.name,
}, },
timestamp: p.timestamp,
type: "offer-contract",
}); });
} }
const purchases = await this.q().iter<PurchaseRecord>(Stores.purchases).toArray(); const purchases = await this.q().iter<PurchaseRecord>(Stores.purchases).toArray();
for (let p of purchases) { for (const p of purchases) {
history.push({ history.push({
type: "pay",
timestamp: p.timestamp,
detail: { detail: {
amount: p.contractTerms.amount, amount: p.contractTerms.amount,
contractTermsHash: p.contractTermsHash, contractTermsHash: p.contractTermsHash,
fulfillmentUrl: p.contractTerms.fulfillment_url, fulfillmentUrl: p.contractTerms.fulfillment_url,
merchantName: p.contractTerms.merchant.name, merchantName: p.contractTerms.merchant.name,
}, },
timestamp: p.timestamp,
type: "pay",
}); });
if (p.timestamp_refund) { if (p.timestamp_refund) {
const amountsPending = Object.keys(p.refundsPending).map((x) => p.refundsPending[x].refund_amount); const amountsPending = Object.keys(p.refundsPending).map((x) => p.refundsPending[x].refund_amount);
@ -2261,44 +2272,44 @@ export class Wallet {
const amount = Amounts.add(Amounts.getZero(p.contractTerms.amount.currency), ...amounts).amount; const amount = Amounts.add(Amounts.getZero(p.contractTerms.amount.currency), ...amounts).amount;
history.push({ history.push({
type: "refund",
timestamp: p.timestamp_refund,
detail: { detail: {
refundAmount: amount,
contractTermsHash: p.contractTermsHash, contractTermsHash: p.contractTermsHash,
fulfillmentUrl: p.contractTerms.fulfillment_url, fulfillmentUrl: p.contractTerms.fulfillment_url,
merchantName: p.contractTerms.merchant.name, merchantName: p.contractTerms.merchant.name,
refundAmount: amount,
}, },
timestamp: p.timestamp_refund,
type: "refund",
}); });
} }
} }
const reserves: ReserveRecord[] = await this.q().iter<ReserveRecord>(Stores.reserves).toArray(); const reserves: ReserveRecord[] = await this.q().iter<ReserveRecord>(Stores.reserves).toArray();
for (let r of reserves) { for (const r of reserves) {
history.push({ history.push({
type: "create-reserve",
timestamp: r.created,
detail: { detail: {
exchangeBaseUrl: r.exchange_base_url, exchangeBaseUrl: r.exchange_base_url,
requestedAmount: r.requested_amount, requestedAmount: r.requested_amount,
reservePub: r.reserve_pub, reservePub: r.reserve_pub,
}, },
timestamp: r.created,
type: "create-reserve",
}); });
if (r.timestamp_depleted) { if (r.timestamp_depleted) {
history.push({ history.push({
type: "depleted-reserve",
timestamp: r.timestamp_depleted,
detail: { detail: {
exchangeBaseUrl: r.exchange_base_url, exchangeBaseUrl: r.exchange_base_url,
requestedAmount: r.requested_amount, requestedAmount: r.requested_amount,
reservePub: r.reserve_pub, reservePub: r.reserve_pub,
}, },
timestamp: r.timestamp_depleted,
type: "depleted-reserve",
}); });
} }
} }
history.sort((h1, h2) => Math.sign(h1.timestamp - h2.timestamp)); history.sort((h1, h2) => Math.sign(h1.timestamp - h2.timestamp));
return {history}; return {history};
} }
@ -2563,20 +2574,20 @@ export class Wallet {
H_wire: wireHash, H_wire: wireHash,
amount: req.amount, amount: req.amount,
auditors: [], auditors: [],
wire_method: wireType, exchanges: [ { master_pub: exchange.masterPublicKey, url: exchange.baseUrl } ],
pay_deadline: `/Date(${stampSecNow + 60 * 5})/`, extra: {},
fulfillment_url: "",
locations: [], locations: [],
max_fee: req.amount, max_fee: req.amount,
merchant: {}, merchant: {},
merchant_pub: pub, merchant_pub: pub,
exchanges: [ { master_pub: exchange.masterPublicKey, url: exchange.baseUrl } ], order_id: "none",
pay_deadline: `/Date(${stampSecNow + 60 * 5})/`,
pay_url: "",
products: [], products: [],
refund_deadline: `/Date(${stampSecNow + 60 * 5})/`, refund_deadline: `/Date(${stampSecNow + 60 * 5})/`,
timestamp: `/Date(${stampSecNow})/`, timestamp: `/Date(${stampSecNow})/`,
order_id: "none", wire_method: wireType,
pay_url: "",
fulfillment_url: "",
extra: {},
}; };
const contractTermsHash = await this.cryptoApi.hashString(canonicalJson(contractTerms)); const contractTermsHash = await this.cryptoApi.hashString(canonicalJson(contractTerms));
@ -2589,12 +2600,12 @@ export class Wallet {
const coinsReturnRecord: CoinsReturnRecord = { const coinsReturnRecord: CoinsReturnRecord = {
coins, coins,
exchange: exchange.baseUrl,
contractTerms, contractTerms,
contractTermsHash, contractTermsHash,
exchange: exchange.baseUrl,
merchantPriv: priv, merchantPriv: priv,
wire: req.senderWire, wire: req.senderWire,
} };
await this.q() await this.q()
.put(Stores.coinsReturns, coinsReturnRecord) .put(Stores.coinsReturns, coinsReturnRecord)
@ -2611,19 +2622,19 @@ export class Wallet {
continue; continue;
} }
const req = { const req = {
f: c.coinPaySig.f,
wire: coinsReturnRecord.wire,
H_wire: coinsReturnRecord.contractTerms.H_wire, H_wire: coinsReturnRecord.contractTerms.H_wire,
h_contract_terms: coinsReturnRecord.contractTermsHash,
coin_pub: c.coinPaySig.coin_pub, coin_pub: c.coinPaySig.coin_pub,
coin_sig: c.coinPaySig.coin_sig,
denom_pub: c.coinPaySig.denom_pub, denom_pub: c.coinPaySig.denom_pub,
ub_sig: c.coinPaySig.ub_sig, f: c.coinPaySig.f,
timestamp: coinsReturnRecord.contractTerms.timestamp, h_contract_terms: coinsReturnRecord.contractTermsHash,
wire_transfer_deadline: coinsReturnRecord.contractTerms.pay_deadline, merchant_pub: coinsReturnRecord.contractTerms.merchant_pub,
pay_deadline: coinsReturnRecord.contractTerms.pay_deadline, pay_deadline: coinsReturnRecord.contractTerms.pay_deadline,
refund_deadline: coinsReturnRecord.contractTerms.refund_deadline, refund_deadline: coinsReturnRecord.contractTerms.refund_deadline,
merchant_pub: coinsReturnRecord.contractTerms.merchant_pub, timestamp: coinsReturnRecord.contractTerms.timestamp,
coin_sig: c.coinPaySig.coin_sig, ub_sig: c.coinPaySig.ub_sig,
wire: coinsReturnRecord.wire,
wire_transfer_deadline: coinsReturnRecord.contractTerms.pay_deadline,
}; };
console.log("req", req); console.log("req", req);
const reqUrl = (new URI("deposit")).absoluteTo(coinsReturnRecord.exchange); const reqUrl = (new URI("deposit")).absoluteTo(coinsReturnRecord.exchange);
@ -2773,7 +2784,7 @@ export class Wallet {
if (refundPermissions.length === 0) { if (refundPermissions.length === 0) {
throw Error("no refunds given"); throw Error("no refunds given");
} }
const coin0 = await this.q().get(Stores.coins, refundPermissions[0].coin_pub) const coin0 = await this.q().get(Stores.coins, refundPermissions[0].coin_pub);
if (!coin0) { if (!coin0) {
throw Error("coin not found"); throw Error("coin not found");
} }

View File

@ -56,14 +56,14 @@ export interface MessageMap {
"create-reserve": { "create-reserve": {
request: { request: {
amount: types.AmountJson; amount: types.AmountJson;
exchange: string exchange: string
}; };
response: void; response: void;
}; };
"confirm-reserve": { "confirm-reserve": {
request: { reservePub: string }; request: { reservePub: string };
response: void; response: void;
} };
"generate-nonce": { "generate-nonce": {
request: { } request: { }
response: string; response: string;
@ -99,7 +99,7 @@ export interface MessageMap {
"reserve-creation-info": { "reserve-creation-info": {
request: { baseUrl: string, amount: types.AmountJson }; request: { baseUrl: string, amount: types.AmountJson };
response: types.ReserveCreationInfo; response: types.ReserveCreationInfo;
} };
"get-history": { "get-history": {
request: { }; request: { };
response: types.HistoryRecord[]; response: types.HistoryRecord[];
@ -139,7 +139,7 @@ export interface MessageMap {
"withdraw-payback-reserve": { "withdraw-payback-reserve": {
request: { reservePub: string }; request: { reservePub: string };
response: void; response: void;
} };
"get-precoins": { "get-precoins": {
request: { exchangeBaseUrl: string }; request: { exchangeBaseUrl: string };
response: types.PreCoinRecord[]; response: types.PreCoinRecord[];

View File

@ -30,7 +30,7 @@ import wxApi = require("./wxApi");
import { QueryPaymentResult } from "../types"; import { QueryPaymentResult } from "../types";
import axios from 'axios'; import axios from "axios";
declare var cloneInto: any; declare var cloneInto: any;
@ -111,17 +111,17 @@ async function handlePaymentResponse(maybeFoundResponse: QueryPaymentResult) {
let resp; let resp;
try { try {
const config = { const config = {
timeout: 5000, /* 5 seconds */
headers: { "Content-Type": "application/json;charset=UTF-8" }, headers: { "Content-Type": "application/json;charset=UTF-8" },
validateStatus: (s: number) => s == 200, timeout: 5000, /* 5 seconds */
} validateStatus: (s: number) => s === 200,
};
resp = await axios.post(walletResp.contractTerms.pay_url, walletResp.payReq, config); resp = await axios.post(walletResp.contractTerms.pay_url, walletResp.payReq, config);
} catch (e) { } catch (e) {
// Gives the user the option to retry / abort and refresh // Gives the user the option to retry / abort and refresh
wxApi.logAndDisplayError({ wxApi.logAndDisplayError({
name: "pay-post-failed",
contractTerms: walletResp.contractTerms, contractTerms: walletResp.contractTerms,
message: e.message, message: e.message,
name: "pay-post-failed",
response: e.response, response: e.response,
}); });
throw e; throw e;
@ -195,11 +195,11 @@ async function downloadContract(url: string, nonce: string): Promise<any> {
console.log("downloading contract from '" + url + "'"); console.log("downloading contract from '" + url + "'");
let resp; let resp;
try { try {
resp = await axios.get(url, { validateStatus: (s) => s == 200 }); resp = await axios.get(url, { validateStatus: (s) => s === 200 });
} catch (e) { } catch (e) {
wxApi.logAndDisplayError({ wxApi.logAndDisplayError({
name: "contract-download-failed",
message: e.message, message: e.message,
name: "contract-download-failed",
response: e.response, response: e.response,
sameTab: true, sameTab: true,
}); });
@ -236,11 +236,11 @@ async function processProposal(proposal: any) {
// bad contract / name not included // bad contract / name not included
} }
let proposalId = await wxApi.saveProposal({ const proposalId = await wxApi.saveProposal({
timestamp: (new Date()).getTime(),
contractTerms: proposal.data, contractTerms: proposal.data,
contractTermsHash: proposal.hash, contractTermsHash: proposal.hash,
merchantSig: proposal.sig, merchantSig: proposal.sig,
timestamp: (new Date()).getTime(),
}); });
const uri = new URI(chrome.extension.getURL("/src/webex/pages/confirm-contract.html")); const uri = new URI(chrome.extension.getURL("/src/webex/pages/confirm-contract.html"));
@ -265,13 +265,13 @@ function talerPay(msg: any): Promise<any> {
let resp; let resp;
try { try {
const config = { const config = {
validateStatus: (s: number) => s == 200, validateStatus: (s: number) => s === 200,
} };
resp = await axios.get(msg.refund_url, config); resp = await axios.get(msg.refund_url, config);
} catch (e) { } catch (e) {
wxApi.logAndDisplayError({ wxApi.logAndDisplayError({
name: "refund-download-failed",
message: e.message, message: e.message,
name: "refund-download-failed",
response: e.response, response: e.response,
sameTab: true, sameTab: true,
}); });

View File

@ -124,9 +124,9 @@ class ContractPrompt extends React.Component<ContractPromptProps, ContractPrompt
alreadyPaid: false, alreadyPaid: false,
error: null, error: null,
exchanges: null, exchanges: null,
proposal: null,
payDisabled: true,
holdCheck: false, holdCheck: false,
payDisabled: true,
proposal: null,
}; };
} }
@ -220,8 +220,11 @@ class ContractPrompt extends React.Component<ContractPromptProps, ContractPrompt
(p: any, i: number) => (<li key={i}>{p.description}: {renderAmount(p.price)}</li>)) (p: any, i: number) => (<li key={i}>{p.description}: {renderAmount(p.price)}</li>))
} }
</ul> </ul>
{(this.state.payStatus && this.state.payStatus.coinSelection) ? {(this.state.payStatus && this.state.payStatus.coinSelection)
<p>The total price is <span>{amount}</span> (plus <span>{renderAmount(this.state.payStatus.coinSelection.totalFees)}</span> fees).</p> ? <p>
The total price is <span>{amount}</span>{" "}
(plus <span>{renderAmount(this.state.payStatus.coinSelection.totalFees)}</span> fees).
</p>
: :
<p>The total price is <span>{amount}</span>.</p> <p>The total price is <span>{amount}</span>.</p>
} }
@ -232,7 +235,11 @@ class ContractPrompt extends React.Component<ContractPromptProps, ContractPrompt
{i18n.str`Confirm payment`} {i18n.str`Confirm payment`}
</button> </button>
<div> <div>
{(this.state.alreadyPaid ? <p className="okaybox">You already paid for this, clicking "Confirm payment" will not cost money again.</p> : <p />)} {(this.state.alreadyPaid
? <p className="okaybox">
You already paid for this, clicking "Confirm payment" will not cost money again.
</p>
: <p />)}
{(this.state.error ? <p className="errorbox">{this.state.error}</p> : <p />)} {(this.state.error ? <p className="errorbox">{this.state.error}</p> : <p />)}
</div> </div>
<Details exchanges={this.state.exchanges} contractTerms={c} collapsed={!this.state.error}/> <Details exchanges={this.state.exchanges} contractTerms={c} collapsed={!this.state.error}/>

View File

@ -43,10 +43,10 @@ import {
import {Collapsible, renderAmount} from "../renderHtml"; import {Collapsible, renderAmount} from "../renderHtml";
import * as moment from "moment";
import * as React from "react"; import * as React from "react";
import * as ReactDOM from "react-dom"; import * as ReactDOM from "react-dom";
import URI = require("urijs"); import URI = require("urijs");
import * as moment from "moment";
function delay<T>(delayMs: number, value: T): Promise<T> { function delay<T>(delayMs: number, value: T): Promise<T> {
@ -80,7 +80,6 @@ class EventTrigger {
} }
function renderAuditorDetails(rci: ReserveCreationInfo|null) { function renderAuditorDetails(rci: ReserveCreationInfo|null) {
console.log("rci", rci); console.log("rci", rci);
if (!rci) { if (!rci) {
@ -393,7 +392,7 @@ class ExchangeSelection extends ImplicitStateComponent<ExchangeSelectionProps> {
if (rci.versionMatch.compatible) { if (rci.versionMatch.compatible) {
return null; return null;
} }
if (rci.versionMatch.currentCmp == -1) { if (rci.versionMatch.currentCmp === -1) {
return ( return (
<p className="errorbox"> <p className="errorbox">
Your wallet might be outdated. The exchange has a higher, incompatible Your wallet might be outdated. The exchange has a higher, incompatible
@ -401,7 +400,7 @@ class ExchangeSelection extends ImplicitStateComponent<ExchangeSelectionProps> {
</p> </p>
); );
} }
if (rci.versionMatch.currentCmp == 1) { if (rci.versionMatch.currentCmp === 1) {
return ( return (
<p className="errorbox"> <p className="errorbox">
The chosen exchange might be outdated. The exchange has a lower, incompatible The chosen exchange might be outdated. The exchange has a lower, incompatible
@ -522,10 +521,10 @@ class ExchangeSelection extends ImplicitStateComponent<ExchangeSelectionProps> {
} }
async confirmReserveImpl(rci: ReserveCreationInfo, async confirmReserveImpl(rci: ReserveCreationInfo,
exchange: string, exchange: string,
amount: AmountJson, amount: AmountJson,
callback_url: string, callback_url: string,
sender_wire: object | undefined) { sender_wire: object | undefined) {
const rawResp = await createReserve({ const rawResp = await createReserve({
amount, amount,
exchange: canonicalizeBaseUrl(exchange), exchange: canonicalizeBaseUrl(exchange),
@ -612,9 +611,9 @@ async function main() {
amount, amount,
callback_url, callback_url,
currencyRecord, currencyRecord,
sender_wire,
suggestedExchangeUrl, suggestedExchangeUrl,
wt_types, wt_types,
sender_wire,
}; };
ReactDOM.render(<ExchangeSelection {...args} />, document.getElementById( ReactDOM.render(<ExchangeSelection {...args} />, document.getElementById(

View File

@ -55,9 +55,14 @@ class ErrorView extends React.Component<ErrorProps, { }> {
return ( return (
<div id="main"> <div id="main">
<h1>Failed to send payment</h1> <h1>Failed to send payment</h1>
<p>Failed to send payment for <strong>{summary}</strong> to merchant <strong>{report.contractTerms.merchant.name}</strong>.</p> <p>
<p>You can <a href={report.contractTerms.fulfillment_url}>retry</a> the payment. If this problem persists, Failed to send payment for <strong>{summary}</strong>{" "}
please contact the mechant with the error details below.</p> to merchant <strong>{report.contractTerms.merchant.name}</strong>.
</p>
<p>
You can <a href={report.contractTerms.fulfillment_url}>retry</a> the payment.{" "}
If this problem persists, please contact the mechant with the error details below.
</p>
<Collapsible initiallyCollapsed={true} title="Error Details"> <Collapsible initiallyCollapsed={true} title="Error Details">
<pre> <pre>
{JSON.stringify(report, null, " ")} {JSON.stringify(report, null, " ")}

View File

@ -24,12 +24,12 @@
/** /**
* Imports. * Imports.
*/ */
import { renderAmount } from "../renderHtml";
import { import {
ReserveRecord, ReserveRecord,
} from "../../types"; } from "../../types";
import { ImplicitStateComponent, StateHolder } from "../components"; import { ImplicitStateComponent, StateHolder } from "../components";
import { renderAmount } from "../renderHtml";
import { import {
getPaybackReserves, getPaybackReserves,
withdrawPaybackReserve, withdrawPaybackReserve,

View File

@ -105,12 +105,12 @@ class Router extends React.Component<any, any> {
foundChild = child; foundChild = child;
} }
}); });
const child: React.ReactChild | null = foundChild || defaultChild; const c: React.ReactChild | null = foundChild || defaultChild;
if (!child) { if (!c) {
throw Error("unknown route"); throw Error("unknown route");
} }
Router.setRoute((child as any).props.route); Router.setRoute((c as any).props.route);
return <div>{child}</div>; return <div>{c}</div>;
} }
} }
@ -367,7 +367,8 @@ function formatHistoryItem(historyItem: HistoryRecord) {
const link = chrome.extension.getURL("view-contract.html"); const link = chrome.extension.getURL("view-contract.html");
return ( return (
<i18n.Translate wrap="p"> <i18n.Translate wrap="p">
Merchant <em>{abbrev(d.merchantName, 15)}</em> offered contract <a href={link}>{abbrev(d.contractTermsHash)}</a>; Merchant <em>{abbrev(d.merchantName, 15)}</em> offered{" "}
contract <a href={link}>{abbrev(d.contractTermsHash)}</a>.
</i18n.Translate> </i18n.Translate>
); );
} }

View File

@ -26,10 +26,10 @@ import * as React from "react";
import * as ReactDOM from "react-dom"; import * as ReactDOM from "react-dom";
import URI = require("urijs"); import URI = require("urijs");
import * as wxApi from "../wxApi";
import * as types from "../../types"; import * as types from "../../types";
import { AmountDisplay } from "../renderHtml"; import { AmountDisplay } from "../renderHtml";
import * as wxApi from "../wxApi";
interface RefundStatusViewProps { interface RefundStatusViewProps {
contractTermsHash: string; contractTermsHash: string;
@ -41,25 +41,30 @@ interface RefundStatusViewState {
gotResult: boolean; gotResult: boolean;
} }
interface RefundDetailProps {
purchase: types.PurchaseRecord;
fullRefundFees: types.AmountJson;
}
const RefundDetail = ({purchase, fullRefundFees}: {purchase: types.PurchaseRecord, fullRefundFees: types.AmountJson}) => { const RefundDetail = ({purchase, fullRefundFees}: RefundDetailProps) => {
const pendingKeys = Object.keys(purchase.refundsPending); const pendingKeys = Object.keys(purchase.refundsPending);
const doneKeys = Object.keys(purchase.refundsDone); const doneKeys = Object.keys(purchase.refundsDone);
if (pendingKeys.length == 0 && doneKeys.length == 0) { if (pendingKeys.length === 0 && doneKeys.length === 0) {
return <p>No refunds</p>; return <p>No refunds</p>;
} }
const currency = { ...purchase.refundsDone, ...purchase.refundsPending }[([...pendingKeys, ...doneKeys][0])].refund_amount.currency; const firstRefundKey = [...pendingKeys, ...doneKeys][0];
const currency = { ...purchase.refundsDone, ...purchase.refundsPending }[firstRefundKey].refund_amount.currency;
if (!currency) { if (!currency) {
throw Error("invariant"); throw Error("invariant");
} }
let amountPending = types.Amounts.getZero(currency); let amountPending = types.Amounts.getZero(currency);
for (let k of pendingKeys) { for (const k of pendingKeys) {
amountPending = types.Amounts.add(amountPending, purchase.refundsPending[k].refund_amount).amount; amountPending = types.Amounts.add(amountPending, purchase.refundsPending[k].refund_amount).amount;
} }
let amountDone = types.Amounts.getZero(currency); let amountDone = types.Amounts.getZero(currency);
for (let k of doneKeys) { for (const k of doneKeys) {
amountDone = types.Amounts.add(amountDone, purchase.refundsDone[k].refund_amount).amount; amountDone = types.Amounts.add(amountDone, purchase.refundsDone[k].refund_amount).amount;
} }
@ -68,7 +73,9 @@ const RefundDetail = ({purchase, fullRefundFees}: {purchase: types.PurchaseRecor
return ( return (
<div> <div>
{hasPending ? <p>Refund pending: <AmountDisplay amount={amountPending} /></p> : null} {hasPending ? <p>Refund pending: <AmountDisplay amount={amountPending} /></p> : null}
<p>Refund received: <AmountDisplay amount={amountDone} /> (refund fees: <AmountDisplay amount={fullRefundFees} />)</p> <p>
Refund received: <AmountDisplay amount={amountDone} /> (refund fees: <AmountDisplay amount={fullRefundFees} />)
</p>
</div> </div>
); );
}; };
@ -105,9 +112,14 @@ class RefundStatusView extends React.Component<RefundStatusViewProps, RefundStat
return ( return (
<div id="main"> <div id="main">
<h1>Refund Status</h1> <h1>Refund Status</h1>
<p>Status of purchase <strong>{summary}</strong> from merchant <strong>{merchantName}</strong> (order id {purchase.contractTerms.order_id}).</p> <p>
Status of purchase <strong>{summary}</strong> from merchant <strong>{merchantName}</strong>{" "}
(order id {purchase.contractTerms.order_id}).
</p>
<p>Total amount: <AmountDisplay amount={purchase.contractTerms.amount} /></p> <p>Total amount: <AmountDisplay amount={purchase.contractTerms.amount} /></p>
{purchase.finished ? <RefundDetail purchase={purchase} fullRefundFees={this.state.refundFees!} /> : <p>Purchase not completed.</p>} {purchase.finished
? <RefundDetail purchase={purchase} fullRefundFees={this.state.refundFees!} />
: <p>Purchase not completed.</p>}
</div> </div>
); );
} }

View File

@ -27,7 +27,14 @@ import * as ReactDOM from "react-dom";
import * as wxApi from "../wxApi"; import * as wxApi from "../wxApi";
class State { class State {
/**
* Did the user check the confirmation check box?
*/
checked: boolean; checked: boolean;
/**
* Do we actually need to reset the db?
*/
resetRequired: boolean; resetRequired: boolean;
} }
@ -47,9 +54,15 @@ class ResetNotification extends React.Component<any, State> {
return ( return (
<div> <div>
<h1>Manual Reset Reqired</h1> <h1>Manual Reset Reqired</h1>
<p>The wallet's database in your browser is incompatible with the currently installed wallet. Please reset manually.</p> <p>
The wallet's database in your browser is incompatible with the {" "}
currently installed wallet. Please reset manually.
</p>
<p>Once the database format has stabilized, we will provide automatic upgrades.</p> <p>Once the database format has stabilized, we will provide automatic upgrades.</p>
<input id="check" type="checkbox" checked={this.state.checked} onChange={(e) => this.setState({checked: e.target.checked})} />{" "} <input id="check"
type="checkbox"
checked={this.state.checked}
onChange={(e) => this.setState({checked: e.target.checked})} />{" "}
<label htmlFor="check"> <label htmlFor="check">
I understand that I will lose all my data I understand that I will lose all my data
</label> </label>

View File

@ -95,7 +95,7 @@ class ReturnSelectionItem extends React.Component<ReturnSelectionItemProps, Retu
<select value={this.state.selectedWire} onChange={(evt) => this.setState({selectedWire: evt.target.value})}> <select value={this.state.selectedWire} onChange={(evt) => this.setState({selectedWire: evt.target.value})}>
<option style={{display: "none"}}>Select account</option> <option style={{display: "none"}}>Select account</option>
{this.state.supportedWires.map((w, n) => {this.state.supportedWires.map((w, n) =>
<option value={n.toString()} key={JSON.stringify(w)}>{n+1}: {wire.summarizeWire(w)}</option> <option value={n.toString()} key={JSON.stringify(w)}>{n + 1}: {wire.summarizeWire(w)}</option>,
)} )}
</select>. </select>.
</p> </p>
@ -252,7 +252,9 @@ class ReturnCoins extends React.Component<any, ReturnCoinsState> {
<p>You can send coins back into your own bank account. Note that <p>You can send coins back into your own bank account. Note that
you're acting as a merchant when doing this, and thus the same fees apply.</p> you're acting as a merchant when doing this, and thus the same fees apply.</p>
{this.state.lastConfirmedDetail {this.state.lastConfirmedDetail
? <p className="okaybox">Transfer of {renderAmount(this.state.lastConfirmedDetail.amount)} successfully initiated.</p> ? <p className="okaybox">
Transfer of {renderAmount(this.state.lastConfirmedDetail.amount)} successfully initiated.
</p>
: null} : null}
<ReturnSelectionList <ReturnSelectionList
selectDetail={(d) => this.selectDetail(d)} selectDetail={(d) => this.selectDetail(d)}

View File

@ -61,16 +61,21 @@ export function abbrev(s: string, n: number = 5) {
} }
interface CollapsibleState { interface CollapsibleState {
collapsed: boolean; collapsed: boolean;
} }
interface CollapsibleProps { interface CollapsibleProps {
initiallyCollapsed: boolean; initiallyCollapsed: boolean;
title: string; title: string;
} }
/**
* Component that shows/hides its children when clicking
* a heading.
*/
export class Collapsible extends React.Component<CollapsibleProps, CollapsibleState> { export class Collapsible extends React.Component<CollapsibleProps, CollapsibleState> {
constructor(props: CollapsibleProps) { constructor(props: CollapsibleProps) {
super(props); super(props);

View File

@ -40,7 +40,7 @@ import {
WalletBalance, WalletBalance,
} from "../types"; } from "../types";
import { MessageType, MessageMap } from "./messages"; import { MessageMap, MessageType } from "./messages";
/** /**
@ -328,18 +328,33 @@ export function logAndDisplayError(args: any): Promise<void> {
return callBackend("log-and-display-error", args); return callBackend("log-and-display-error", args);
} }
export function getReport(reportUid: string): Promise<void> { /**
* Get an error report from the logging database for the
* given report UID.
*/
export function getReport(reportUid: string): Promise<any> {
return callBackend("get-report", { reportUid }); return callBackend("get-report", { reportUid });
} }
/**
* Apply a refund that we got from the merchant.
*/
export function acceptRefund(refundData: any): Promise<number> { export function acceptRefund(refundData: any): Promise<number> {
return callBackend("accept-refund", refundData); return callBackend("accept-refund", refundData);
} }
/**
* Look up a purchase in the wallet database from
* the contract terms hash.
*/
export function getPurchase(contractTermsHash: string): Promise<PurchaseRecord> { export function getPurchase(contractTermsHash: string): Promise<PurchaseRecord> {
return callBackend("get-purchase", { contractTermsHash }); return callBackend("get-purchase", { contractTermsHash });
} }
/**
* Get the refund fees for a refund permission, including
* subsequent refresh and unrefreshable coins.
*/
export function getFullRefundFees(args: { refundPermissions: RefundPermission[] }): Promise<AmountJson> { export function getFullRefundFees(args: { refundPermissions: RefundPermission[] }): Promise<AmountJson> {
return callBackend("get-full-refund-fees", { refundPermissions: args.refundPermissions }); return callBackend("get-full-refund-fees", { refundPermissions: args.refundPermissions });
} }

View File

@ -230,7 +230,7 @@ function handleMessage(sender: MessageSender,
if (typeof detail.exchangeBaseUrl !== "string") { if (typeof detail.exchangeBaseUrl !== "string") {
return Promise.reject(Error("exchangBaseUrl missing")); return Promise.reject(Error("exchangBaseUrl missing"));
} }
return needsWallet().getPreCoins(detail.exchangeBaseUrl); return needsWallet().getPreCoins(detail.exchangeBaseUrl);
} }
case "get-denoms": { case "get-denoms": {
if (typeof detail.exchangeBaseUrl !== "string") { if (typeof detail.exchangeBaseUrl !== "string") {
@ -287,10 +287,10 @@ function handleMessage(sender: MessageSender,
dbResetRequired = true; dbResetRequired = true;
} }
const resp: wxApi.UpgradeResponse = { const resp: wxApi.UpgradeResponse = {
dbResetRequired,
currentDbVersion: WALLET_DB_VERSION.toString(), currentDbVersion: WALLET_DB_VERSION.toString(),
dbResetRequired,
oldDbVersion: (oldDbVersion || "unknown").toString(), oldDbVersion: (oldDbVersion || "unknown").toString(),
} };
return resp; return resp;
} }
case "log-and-display-error": case "log-and-display-error":
@ -307,12 +307,13 @@ function handleMessage(sender: MessageSender,
return logging.getReport(detail.reportUid); return logging.getReport(detail.reportUid);
case "accept-refund": case "accept-refund":
return needsWallet().acceptRefund(detail.refund_permissions); return needsWallet().acceptRefund(detail.refund_permissions);
case "get-purchase": case "get-purchase": {
const contractTermsHash = detail.contractTermsHash; const contractTermsHash = detail.contractTermsHash;
if (!contractTermsHash) { if (!contractTermsHash) {
throw Error("contractTermsHash missing"); throw Error("contractTermsHash missing");
} }
return needsWallet().getPurchase(contractTermsHash); return needsWallet().getPurchase(contractTermsHash);
}
case "get-full-refund-fees": case "get-full-refund-fees":
return needsWallet().getFullRefundFees(detail.refundPermissions); return needsWallet().getFullRefundFees(detail.refundPermissions);
default: default:
@ -452,7 +453,7 @@ function handleBankRequest(wallet: Wallet, headerList: chrome.webRequest.HttpHea
return; return;
} }
if (operation == "confirm-reserve") { if (operation === "confirm-reserve") {
const reservePub = headers["x-taler-reserve-pub"]; const reservePub = headers["x-taler-reserve-pub"];
if (reservePub !== undefined) { if (reservePub !== undefined) {
console.log(`confirming reserve ${reservePub} via 201`); console.log(`confirming reserve ${reservePub} via 201`);
@ -462,7 +463,7 @@ function handleBankRequest(wallet: Wallet, headerList: chrome.webRequest.HttpHea
return; return;
} }
if (operation == "create-reserve") { if (operation === "create-reserve") {
const amount = headers["x-taler-amount"]; const amount = headers["x-taler-amount"];
if (!amount) { if (!amount) {
console.log("202 not understood (X-Taler-Amount missing)"); console.log("202 not understood (X-Taler-Amount missing)");
@ -477,13 +478,13 @@ function handleBankRequest(wallet: Wallet, headerList: chrome.webRequest.HttpHea
try { try {
amountParsed = JSON.parse(amount); amountParsed = JSON.parse(amount);
} catch (e) { } catch (e) {
const uri = new URI(chrome.extension.getURL("/src/webex/pages/error.html")); const errUri = new URI(chrome.extension.getURL("/src/webex/pages/error.html"));
const p = { const p = {
message: `Can't parse amount ("${amount}"): ${e.message}`, message: `Can't parse amount ("${amount}"): ${e.message}`,
}; };
const redirectUrl = uri.query(p).href(); const errRedirectUrl = errUri.query(p).href();
// FIXME: use direct redirect when https://bugzilla.mozilla.org/show_bug.cgi?id=707624 is fixed // FIXME: use direct redirect when https://bugzilla.mozilla.org/show_bug.cgi?id=707624 is fixed
chrome.tabs.update(tabId, {url: redirectUrl}); chrome.tabs.update(tabId, {url: errRedirectUrl});
return; return;
} }
const wtTypes = headers["x-taler-wt-types"]; const wtTypes = headers["x-taler-wt-types"];
@ -495,9 +496,9 @@ function handleBankRequest(wallet: Wallet, headerList: chrome.webRequest.HttpHea
amount, amount,
bank_url: url, bank_url: url,
callback_url: new URI(callbackUrl) .absoluteTo(url), callback_url: new URI(callbackUrl) .absoluteTo(url),
sender_wire: headers["x-taler-sender-wire"],
suggested_exchange_url: headers["x-taler-suggested-exchange"], suggested_exchange_url: headers["x-taler-suggested-exchange"],
wt_types: wtTypes, wt_types: wtTypes,
sender_wire: headers["x-taler-sender-wire"],
}; };
const uri = new URI(chrome.extension.getURL("/src/webex/pages/confirm-create-reserve.html")); const uri = new URI(chrome.extension.getURL("/src/webex/pages/confirm-create-reserve.html"));
const redirectUrl = uri.query(params).href(); const redirectUrl = uri.query(params).href();
@ -584,7 +585,7 @@ export async function wxMain() {
chrome.runtime.onUpdateAvailable.addListener((details) => { chrome.runtime.onUpdateAvailable.addListener((details) => {
console.log("update available:", details); console.log("update available:", details);
chrome.runtime.reload(); chrome.runtime.reload();
}) });
window.onerror = (m, source, lineno, colno, error) => { window.onerror = (m, source, lineno, colno, error) => {
logging.record("error", m + error, undefined, source || "(unknown)", lineno || 0, colno || 0); logging.record("error", m + error, undefined, source || "(unknown)", lineno || 0, colno || 0);

View File

@ -29,7 +29,7 @@ import * as i18n from "./i18n";
/** /**
* Short summary of the wire information. * Short summary of the wire information.
* *
* Might abbreviate and return the same summary for different * Might abbreviate and return the same summary for different
* wire details. * wire details.
*/ */