implement returning coins to user's account
This commit is contained in:
parent
419a05e801
commit
d5bba630a3
@ -217,12 +217,11 @@ export namespace Checkable {
|
||||
type: target,
|
||||
}, ["(root)"]);
|
||||
if (opts.validate) {
|
||||
const instance = new target();
|
||||
if (typeof instance.validate !== "function") {
|
||||
if (target.validate !== "function") {
|
||||
throw Error("invalid Checkable annotion: validate method required");
|
||||
}
|
||||
// May throw exception
|
||||
instance.validate.call(cv);
|
||||
target.validate(cv);
|
||||
}
|
||||
return cv;
|
||||
};
|
||||
|
@ -26,8 +26,8 @@
|
||||
import {
|
||||
AmountJson,
|
||||
CoinRecord,
|
||||
ContractTerms,
|
||||
DenominationRecord,
|
||||
ProposalRecord,
|
||||
PayCoinInfo,
|
||||
PaybackRequest,
|
||||
PreCoinRecord,
|
||||
@ -277,9 +277,9 @@ export class CryptoApi {
|
||||
return this.doRpc<PayCoinInfo>("isValidPaymentSignature", 1, sig, contractHash, merchantPub);
|
||||
}
|
||||
|
||||
signDeposit(proposal: ProposalRecord,
|
||||
signDeposit(contractTerms: ContractTerms,
|
||||
cds: CoinWithDenom[]): Promise<PayCoinInfo> {
|
||||
return this.doRpc<PayCoinInfo>("signDeposit", 3, proposal, cds);
|
||||
return this.doRpc<PayCoinInfo>("signDeposit", 3, contractTerms, cds);
|
||||
}
|
||||
|
||||
createEddsaKeypair(): Promise<{priv: string, pub: string}> {
|
||||
|
@ -28,8 +28,8 @@ import {
|
||||
CoinPaySig,
|
||||
CoinRecord,
|
||||
CoinStatus,
|
||||
ContractTerms,
|
||||
DenominationRecord,
|
||||
ProposalRecord,
|
||||
PayCoinInfo,
|
||||
PaybackRequest,
|
||||
PreCoinRecord,
|
||||
@ -38,6 +38,9 @@ import {
|
||||
ReserveRecord,
|
||||
WireFee,
|
||||
} from "../types";
|
||||
import {
|
||||
canonicalJson,
|
||||
} from "../helpers";
|
||||
import {
|
||||
CoinWithDenom,
|
||||
} from "../wallet";
|
||||
@ -227,16 +230,17 @@ namespace RpcFunctions {
|
||||
* Generate updated coins (to store in the database)
|
||||
* and deposit permissions for each given coin.
|
||||
*/
|
||||
export function signDeposit(proposal: ProposalRecord,
|
||||
export function signDeposit(contractTerms: ContractTerms,
|
||||
cds: CoinWithDenom[]): PayCoinInfo {
|
||||
const ret: PayCoinInfo = [];
|
||||
|
||||
const contractTermsHash = hashString(canonicalJson(contractTerms));
|
||||
|
||||
const feeList: AmountJson[] = cds.map((x) => x.denom.feeDeposit);
|
||||
let fees = Amounts.add(Amounts.getZero(feeList[0].currency), ...feeList).amount;
|
||||
// okay if saturates
|
||||
fees = Amounts.sub(fees, proposal.contractTerms.max_fee).amount;
|
||||
const total = Amounts.add(fees, proposal.contractTerms.amount).amount;
|
||||
fees = Amounts.sub(fees, contractTerms.max_fee).amount;
|
||||
const total = Amounts.add(fees, contractTerms.amount).amount;
|
||||
|
||||
const amountSpent = native.Amount.getZero(cds[0].coin.currentAmount.currency);
|
||||
const amountRemaining = new native.Amount(total);
|
||||
@ -273,11 +277,11 @@ namespace RpcFunctions {
|
||||
amount_with_fee: coinSpend.toNbo(),
|
||||
coin_pub: native.EddsaPublicKey.fromCrock(cd.coin.coinPub),
|
||||
deposit_fee: new native.Amount(cd.denom.feeDeposit).toNbo(),
|
||||
h_contract: native.HashCode.fromCrock(proposal.contractTermsHash),
|
||||
h_wire: native.HashCode.fromCrock(proposal.contractTerms.H_wire),
|
||||
merchant: native.EddsaPublicKey.fromCrock(proposal.contractTerms.merchant_pub),
|
||||
refund_deadline: native.AbsoluteTimeNbo.fromTalerString(proposal.contractTerms.refund_deadline),
|
||||
timestamp: native.AbsoluteTimeNbo.fromTalerString(proposal.contractTerms.timestamp),
|
||||
h_contract: native.HashCode.fromCrock(contractTermsHash),
|
||||
h_wire: native.HashCode.fromCrock(contractTerms.H_wire),
|
||||
merchant: native.EddsaPublicKey.fromCrock(contractTerms.merchant_pub),
|
||||
refund_deadline: native.AbsoluteTimeNbo.fromTalerString(contractTerms.refund_deadline),
|
||||
timestamp: native.AbsoluteTimeNbo.fromTalerString(contractTerms.timestamp),
|
||||
});
|
||||
|
||||
const coinSig = native.eddsaSign(d.toPurpose(),
|
||||
|
@ -56,67 +56,67 @@ msgid ""
|
||||
"wallet."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:212
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:213
|
||||
#, fuzzy, c-format
|
||||
msgid "Withdrawal fees:"
|
||||
msgstr "Abheben bei %1$s"
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:213
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:214
|
||||
#, c-format
|
||||
msgid "Rounding loss:"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:214
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:215
|
||||
#, c-format
|
||||
msgid "Earliest expiration (for deposit): %1$s"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:219
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:220
|
||||
#, c-format
|
||||
msgid "# Coins"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:220
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:221
|
||||
#, c-format
|
||||
msgid "Value"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:221
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:222
|
||||
#, fuzzy, c-format
|
||||
msgid "Withdraw Fee"
|
||||
msgstr "Abheben bei %1$s"
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:222
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:223
|
||||
#, c-format
|
||||
msgid "Refresh Fee"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:223
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:224
|
||||
#, c-format
|
||||
msgid "Deposit Fee"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:276
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:278
|
||||
#, c-format
|
||||
msgid "Select"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:292
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:294
|
||||
#, c-format
|
||||
msgid "Error: URL may not be relative"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:360
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:362
|
||||
#, c-format
|
||||
msgid "The exchange is trusted by the wallet.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:366
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:368
|
||||
#, c-format
|
||||
msgid "The exchange is audited by a trusted auditor.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:372
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:374
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Warning: The exchange is neither directly trusted nor audited by a trusted "
|
||||
@ -124,7 +124,7 @@ msgid ""
|
||||
"If you withdraw from this exchange, it will be trusted in the future.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:381
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:383
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Using exchange provider%1$s.\n"
|
||||
@ -132,151 +132,166 @@ msgid ""
|
||||
" %2$s in fees.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:395
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:397
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Waiting for a response from\n"
|
||||
" %1$s"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:406
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:408
|
||||
#, c-format
|
||||
msgid "A problem occured, see below. %1$s"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:412
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:414
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Information about fees will be available when an exchange provider is "
|
||||
"selected."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:455
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:457
|
||||
#, c-format
|
||||
msgid "Accept fees and withdraw"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:460
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:462
|
||||
#, c-format
|
||||
msgid "Change Exchange Provider"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:517
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:519
|
||||
#, c-format
|
||||
msgid "You are about to withdraw %1$s from your bank account into your wallet."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:600
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:607
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Oops, something went wrong. The wallet responded with error status (%1$s)."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:611
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:616
|
||||
#, c-format
|
||||
msgid "Checking URL, please wait ..."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:625
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:630
|
||||
#, c-format
|
||||
msgid "Can't parse amount: %1$s"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:632
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:637
|
||||
#, c-format
|
||||
msgid "Can't parse wire_types: %1$s"
|
||||
msgstr ""
|
||||
|
||||
#. TODO:generic error reporting function or component.
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:652
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:663
|
||||
#, c-format
|
||||
msgid "Fatal error: \"%1$s\"."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:160
|
||||
#: src/webex/pages/popup.tsx:161
|
||||
#, c-format
|
||||
msgid "Balance"
|
||||
msgstr "Saldo"
|
||||
|
||||
#: src/webex/pages/popup.tsx:163
|
||||
#: src/webex/pages/popup.tsx:164
|
||||
#, c-format
|
||||
msgid "History"
|
||||
msgstr "Verlauf"
|
||||
|
||||
#: src/webex/pages/popup.tsx:166
|
||||
#: src/webex/pages/popup.tsx:167
|
||||
#, c-format
|
||||
msgid "Debug"
|
||||
msgstr "Debug"
|
||||
|
||||
#: src/webex/pages/popup.tsx:242
|
||||
#: src/webex/pages/popup.tsx:247
|
||||
#, c-format
|
||||
msgid "help"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:247
|
||||
#: src/webex/pages/popup.tsx:252
|
||||
#, fuzzy, c-format
|
||||
msgid ""
|
||||
"You have no balance to show. Need some\n"
|
||||
" %1$s getting started?\n"
|
||||
msgstr "Sie haben kein Digitalgeld. Wollen Sie %1$s? abheben?"
|
||||
|
||||
#: src/webex/pages/popup.tsx:264
|
||||
#: src/webex/pages/popup.tsx:269
|
||||
#, c-format
|
||||
msgid "%1$s incoming\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:277
|
||||
#: src/webex/pages/popup.tsx:282
|
||||
#, c-format
|
||||
msgid "%1$s being spent\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:303
|
||||
#: src/webex/pages/popup.tsx:308
|
||||
#, c-format
|
||||
msgid "Error: could not retrieve balance information."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:342
|
||||
#: src/webex/pages/popup.tsx:335
|
||||
#, c-format
|
||||
msgid "Payback"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:336
|
||||
#, c-format
|
||||
msgid "Return Electronic Cash to Bank Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:337
|
||||
#, c-format
|
||||
msgid "Manage Trusted Auditors and Exchanges"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:349
|
||||
#, fuzzy, c-format
|
||||
msgid ""
|
||||
"Bank requested reserve (%1$s) for\n"
|
||||
" %2$s.\n"
|
||||
msgstr "Bank bestätig anlegen der Reserve (%1$s) bei %2$s"
|
||||
|
||||
#: src/webex/pages/popup.tsx:353
|
||||
#: src/webex/pages/popup.tsx:360
|
||||
#, fuzzy, c-format
|
||||
msgid ""
|
||||
"Started to withdraw\n"
|
||||
" %1$s from%2$s(%3$s).\n"
|
||||
msgstr "Reserve (%1$s) mit %2$s bei %3$s erzeugt"
|
||||
|
||||
#: src/webex/pages/popup.tsx:363
|
||||
#: src/webex/pages/popup.tsx:370
|
||||
#, c-format
|
||||
msgid "Merchant%1$soffered contract%2$s;\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:373
|
||||
#: src/webex/pages/popup.tsx:380
|
||||
#, fuzzy, c-format
|
||||
msgid "Withdrew%1$sfrom%2$s(%3$s).\n"
|
||||
msgstr "Reserve (%1$s) mit %2$s bei %3$s erzeugt"
|
||||
|
||||
#: src/webex/pages/popup.tsx:383
|
||||
#: src/webex/pages/popup.tsx:390
|
||||
#, fuzzy, c-format
|
||||
msgid ""
|
||||
"Paid%1$sto merchant%2$s.\n"
|
||||
" (%3$s)\n"
|
||||
msgstr "Reserve (%1$s) mit %2$s bei %3$s erzeugt"
|
||||
|
||||
#: src/webex/pages/popup.tsx:392
|
||||
#: src/webex/pages/popup.tsx:399
|
||||
#, c-format
|
||||
msgid "Unknown event (%1$s)"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:435
|
||||
#: src/webex/pages/popup.tsx:442
|
||||
#, c-format
|
||||
msgid "Error: could not retrieve event history"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:469
|
||||
#: src/webex/pages/popup.tsx:476
|
||||
#, c-format
|
||||
msgid "Your wallet has no events recorded."
|
||||
msgstr "Ihre Geldbörse verzeichnet keine Vorkommnisse."
|
||||
|
@ -56,67 +56,67 @@ msgid ""
|
||||
"wallet."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:212
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:213
|
||||
#, c-format
|
||||
msgid "Withdrawal fees:"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:213
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:214
|
||||
#, c-format
|
||||
msgid "Rounding loss:"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:214
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:215
|
||||
#, c-format
|
||||
msgid "Earliest expiration (for deposit): %1$s"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:219
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:220
|
||||
#, c-format
|
||||
msgid "# Coins"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:220
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:221
|
||||
#, c-format
|
||||
msgid "Value"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:221
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:222
|
||||
#, c-format
|
||||
msgid "Withdraw Fee"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:222
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:223
|
||||
#, c-format
|
||||
msgid "Refresh Fee"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:223
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:224
|
||||
#, c-format
|
||||
msgid "Deposit Fee"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:276
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:278
|
||||
#, c-format
|
||||
msgid "Select"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:292
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:294
|
||||
#, c-format
|
||||
msgid "Error: URL may not be relative"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:360
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:362
|
||||
#, c-format
|
||||
msgid "The exchange is trusted by the wallet.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:366
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:368
|
||||
#, c-format
|
||||
msgid "The exchange is audited by a trusted auditor.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:372
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:374
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Warning: The exchange is neither directly trusted nor audited by a trusted "
|
||||
@ -124,7 +124,7 @@ msgid ""
|
||||
"If you withdraw from this exchange, it will be trusted in the future.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:381
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:383
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Using exchange provider%1$s.\n"
|
||||
@ -132,151 +132,166 @@ msgid ""
|
||||
" %2$s in fees.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:395
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:397
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Waiting for a response from\n"
|
||||
" %1$s"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:406
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:408
|
||||
#, c-format
|
||||
msgid "A problem occured, see below. %1$s"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:412
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:414
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Information about fees will be available when an exchange provider is "
|
||||
"selected."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:455
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:457
|
||||
#, c-format
|
||||
msgid "Accept fees and withdraw"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:460
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:462
|
||||
#, c-format
|
||||
msgid "Change Exchange Provider"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:517
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:519
|
||||
#, c-format
|
||||
msgid "You are about to withdraw %1$s from your bank account into your wallet."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:600
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:607
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Oops, something went wrong. The wallet responded with error status (%1$s)."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:611
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:616
|
||||
#, c-format
|
||||
msgid "Checking URL, please wait ..."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:625
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:630
|
||||
#, c-format
|
||||
msgid "Can't parse amount: %1$s"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:632
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:637
|
||||
#, c-format
|
||||
msgid "Can't parse wire_types: %1$s"
|
||||
msgstr ""
|
||||
|
||||
#. TODO:generic error reporting function or component.
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:652
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:663
|
||||
#, c-format
|
||||
msgid "Fatal error: \"%1$s\"."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:160
|
||||
#: src/webex/pages/popup.tsx:161
|
||||
#, c-format
|
||||
msgid "Balance"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:163
|
||||
#: src/webex/pages/popup.tsx:164
|
||||
#, c-format
|
||||
msgid "History"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:166
|
||||
#: src/webex/pages/popup.tsx:167
|
||||
#, c-format
|
||||
msgid "Debug"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:242
|
||||
#: src/webex/pages/popup.tsx:247
|
||||
#, c-format
|
||||
msgid "help"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:247
|
||||
#: src/webex/pages/popup.tsx:252
|
||||
#, c-format
|
||||
msgid ""
|
||||
"You have no balance to show. Need some\n"
|
||||
" %1$s getting started?\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:264
|
||||
#: src/webex/pages/popup.tsx:269
|
||||
#, c-format
|
||||
msgid "%1$s incoming\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:277
|
||||
#: src/webex/pages/popup.tsx:282
|
||||
#, c-format
|
||||
msgid "%1$s being spent\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:303
|
||||
#: src/webex/pages/popup.tsx:308
|
||||
#, c-format
|
||||
msgid "Error: could not retrieve balance information."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:342
|
||||
#: src/webex/pages/popup.tsx:335
|
||||
#, c-format
|
||||
msgid "Payback"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:336
|
||||
#, c-format
|
||||
msgid "Return Electronic Cash to Bank Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:337
|
||||
#, c-format
|
||||
msgid "Manage Trusted Auditors and Exchanges"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:349
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Bank requested reserve (%1$s) for\n"
|
||||
" %2$s.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:353
|
||||
#: src/webex/pages/popup.tsx:360
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Started to withdraw\n"
|
||||
" %1$s from%2$s(%3$s).\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:363
|
||||
#: src/webex/pages/popup.tsx:370
|
||||
#, c-format
|
||||
msgid "Merchant%1$soffered contract%2$s;\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:373
|
||||
#: src/webex/pages/popup.tsx:380
|
||||
#, c-format
|
||||
msgid "Withdrew%1$sfrom%2$s(%3$s).\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:383
|
||||
#: src/webex/pages/popup.tsx:390
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Paid%1$sto merchant%2$s.\n"
|
||||
" (%3$s)\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:392
|
||||
#: src/webex/pages/popup.tsx:399
|
||||
#, c-format
|
||||
msgid "Unknown event (%1$s)"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:435
|
||||
#: src/webex/pages/popup.tsx:442
|
||||
#, c-format
|
||||
msgid "Error: could not retrieve event history"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:469
|
||||
#: src/webex/pages/popup.tsx:476
|
||||
#, c-format
|
||||
msgid "Your wallet has no events recorded."
|
||||
msgstr ""
|
||||
|
@ -56,67 +56,67 @@ msgid ""
|
||||
"wallet."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:212
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:213
|
||||
#, c-format
|
||||
msgid "Withdrawal fees:"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:213
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:214
|
||||
#, c-format
|
||||
msgid "Rounding loss:"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:214
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:215
|
||||
#, c-format
|
||||
msgid "Earliest expiration (for deposit): %1$s"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:219
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:220
|
||||
#, c-format
|
||||
msgid "# Coins"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:220
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:221
|
||||
#, c-format
|
||||
msgid "Value"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:221
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:222
|
||||
#, c-format
|
||||
msgid "Withdraw Fee"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:222
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:223
|
||||
#, c-format
|
||||
msgid "Refresh Fee"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:223
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:224
|
||||
#, c-format
|
||||
msgid "Deposit Fee"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:276
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:278
|
||||
#, c-format
|
||||
msgid "Select"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:292
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:294
|
||||
#, c-format
|
||||
msgid "Error: URL may not be relative"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:360
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:362
|
||||
#, c-format
|
||||
msgid "The exchange is trusted by the wallet.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:366
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:368
|
||||
#, c-format
|
||||
msgid "The exchange is audited by a trusted auditor.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:372
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:374
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Warning: The exchange is neither directly trusted nor audited by a trusted "
|
||||
@ -124,7 +124,7 @@ msgid ""
|
||||
"If you withdraw from this exchange, it will be trusted in the future.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:381
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:383
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Using exchange provider%1$s.\n"
|
||||
@ -132,151 +132,166 @@ msgid ""
|
||||
" %2$s in fees.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:395
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:397
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Waiting for a response from\n"
|
||||
" %1$s"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:406
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:408
|
||||
#, c-format
|
||||
msgid "A problem occured, see below. %1$s"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:412
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:414
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Information about fees will be available when an exchange provider is "
|
||||
"selected."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:455
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:457
|
||||
#, c-format
|
||||
msgid "Accept fees and withdraw"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:460
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:462
|
||||
#, c-format
|
||||
msgid "Change Exchange Provider"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:517
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:519
|
||||
#, c-format
|
||||
msgid "You are about to withdraw %1$s from your bank account into your wallet."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:600
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:607
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Oops, something went wrong. The wallet responded with error status (%1$s)."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:611
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:616
|
||||
#, c-format
|
||||
msgid "Checking URL, please wait ..."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:625
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:630
|
||||
#, c-format
|
||||
msgid "Can't parse amount: %1$s"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:632
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:637
|
||||
#, c-format
|
||||
msgid "Can't parse wire_types: %1$s"
|
||||
msgstr ""
|
||||
|
||||
#. TODO:generic error reporting function or component.
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:652
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:663
|
||||
#, c-format
|
||||
msgid "Fatal error: \"%1$s\"."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:160
|
||||
#: src/webex/pages/popup.tsx:161
|
||||
#, c-format
|
||||
msgid "Balance"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:163
|
||||
#: src/webex/pages/popup.tsx:164
|
||||
#, c-format
|
||||
msgid "History"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:166
|
||||
#: src/webex/pages/popup.tsx:167
|
||||
#, c-format
|
||||
msgid "Debug"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:242
|
||||
#: src/webex/pages/popup.tsx:247
|
||||
#, c-format
|
||||
msgid "help"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:247
|
||||
#: src/webex/pages/popup.tsx:252
|
||||
#, c-format
|
||||
msgid ""
|
||||
"You have no balance to show. Need some\n"
|
||||
" %1$s getting started?\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:264
|
||||
#: src/webex/pages/popup.tsx:269
|
||||
#, c-format
|
||||
msgid "%1$s incoming\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:277
|
||||
#: src/webex/pages/popup.tsx:282
|
||||
#, c-format
|
||||
msgid "%1$s being spent\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:303
|
||||
#: src/webex/pages/popup.tsx:308
|
||||
#, c-format
|
||||
msgid "Error: could not retrieve balance information."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:342
|
||||
#: src/webex/pages/popup.tsx:335
|
||||
#, c-format
|
||||
msgid "Payback"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:336
|
||||
#, c-format
|
||||
msgid "Return Electronic Cash to Bank Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:337
|
||||
#, c-format
|
||||
msgid "Manage Trusted Auditors and Exchanges"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:349
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Bank requested reserve (%1$s) for\n"
|
||||
" %2$s.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:353
|
||||
#: src/webex/pages/popup.tsx:360
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Started to withdraw\n"
|
||||
" %1$s from%2$s(%3$s).\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:363
|
||||
#: src/webex/pages/popup.tsx:370
|
||||
#, c-format
|
||||
msgid "Merchant%1$soffered contract%2$s;\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:373
|
||||
#: src/webex/pages/popup.tsx:380
|
||||
#, c-format
|
||||
msgid "Withdrew%1$sfrom%2$s(%3$s).\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:383
|
||||
#: src/webex/pages/popup.tsx:390
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Paid%1$sto merchant%2$s.\n"
|
||||
" (%3$s)\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:392
|
||||
#: src/webex/pages/popup.tsx:399
|
||||
#, c-format
|
||||
msgid "Unknown event (%1$s)"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:435
|
||||
#: src/webex/pages/popup.tsx:442
|
||||
#, c-format
|
||||
msgid "Error: could not retrieve event history"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:469
|
||||
#: src/webex/pages/popup.tsx:476
|
||||
#, c-format
|
||||
msgid "Your wallet has no events recorded."
|
||||
msgstr ""
|
||||
|
@ -56,67 +56,67 @@ msgid ""
|
||||
"wallet."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:212
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:213
|
||||
#, c-format
|
||||
msgid "Withdrawal fees:"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:213
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:214
|
||||
#, c-format
|
||||
msgid "Rounding loss:"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:214
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:215
|
||||
#, c-format
|
||||
msgid "Earliest expiration (for deposit): %1$s"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:219
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:220
|
||||
#, c-format
|
||||
msgid "# Coins"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:220
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:221
|
||||
#, c-format
|
||||
msgid "Value"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:221
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:222
|
||||
#, c-format
|
||||
msgid "Withdraw Fee"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:222
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:223
|
||||
#, c-format
|
||||
msgid "Refresh Fee"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:223
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:224
|
||||
#, c-format
|
||||
msgid "Deposit Fee"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:276
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:278
|
||||
#, c-format
|
||||
msgid "Select"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:292
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:294
|
||||
#, c-format
|
||||
msgid "Error: URL may not be relative"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:360
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:362
|
||||
#, c-format
|
||||
msgid "The exchange is trusted by the wallet.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:366
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:368
|
||||
#, c-format
|
||||
msgid "The exchange is audited by a trusted auditor.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:372
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:374
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Warning: The exchange is neither directly trusted nor audited by a trusted "
|
||||
@ -124,7 +124,7 @@ msgid ""
|
||||
"If you withdraw from this exchange, it will be trusted in the future.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:381
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:383
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Using exchange provider%1$s.\n"
|
||||
@ -132,151 +132,166 @@ msgid ""
|
||||
" %2$s in fees.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:395
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:397
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Waiting for a response from\n"
|
||||
" %1$s"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:406
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:408
|
||||
#, c-format
|
||||
msgid "A problem occured, see below. %1$s"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:412
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:414
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Information about fees will be available when an exchange provider is "
|
||||
"selected."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:455
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:457
|
||||
#, c-format
|
||||
msgid "Accept fees and withdraw"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:460
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:462
|
||||
#, c-format
|
||||
msgid "Change Exchange Provider"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:517
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:519
|
||||
#, c-format
|
||||
msgid "You are about to withdraw %1$s from your bank account into your wallet."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:600
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:607
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Oops, something went wrong. The wallet responded with error status (%1$s)."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:611
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:616
|
||||
#, c-format
|
||||
msgid "Checking URL, please wait ..."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:625
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:630
|
||||
#, c-format
|
||||
msgid "Can't parse amount: %1$s"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:632
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:637
|
||||
#, c-format
|
||||
msgid "Can't parse wire_types: %1$s"
|
||||
msgstr ""
|
||||
|
||||
#. TODO:generic error reporting function or component.
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:652
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:663
|
||||
#, c-format
|
||||
msgid "Fatal error: \"%1$s\"."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:160
|
||||
#: src/webex/pages/popup.tsx:161
|
||||
#, c-format
|
||||
msgid "Balance"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:163
|
||||
#: src/webex/pages/popup.tsx:164
|
||||
#, c-format
|
||||
msgid "History"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:166
|
||||
#: src/webex/pages/popup.tsx:167
|
||||
#, c-format
|
||||
msgid "Debug"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:242
|
||||
#: src/webex/pages/popup.tsx:247
|
||||
#, c-format
|
||||
msgid "help"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:247
|
||||
#: src/webex/pages/popup.tsx:252
|
||||
#, c-format
|
||||
msgid ""
|
||||
"You have no balance to show. Need some\n"
|
||||
" %1$s getting started?\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:264
|
||||
#: src/webex/pages/popup.tsx:269
|
||||
#, c-format
|
||||
msgid "%1$s incoming\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:277
|
||||
#: src/webex/pages/popup.tsx:282
|
||||
#, c-format
|
||||
msgid "%1$s being spent\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:303
|
||||
#: src/webex/pages/popup.tsx:308
|
||||
#, c-format
|
||||
msgid "Error: could not retrieve balance information."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:342
|
||||
#: src/webex/pages/popup.tsx:335
|
||||
#, c-format
|
||||
msgid "Payback"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:336
|
||||
#, c-format
|
||||
msgid "Return Electronic Cash to Bank Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:337
|
||||
#, c-format
|
||||
msgid "Manage Trusted Auditors and Exchanges"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:349
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Bank requested reserve (%1$s) for\n"
|
||||
" %2$s.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:353
|
||||
#: src/webex/pages/popup.tsx:360
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Started to withdraw\n"
|
||||
" %1$s from%2$s(%3$s).\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:363
|
||||
#: src/webex/pages/popup.tsx:370
|
||||
#, c-format
|
||||
msgid "Merchant%1$soffered contract%2$s;\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:373
|
||||
#: src/webex/pages/popup.tsx:380
|
||||
#, c-format
|
||||
msgid "Withdrew%1$sfrom%2$s(%3$s).\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:383
|
||||
#: src/webex/pages/popup.tsx:390
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Paid%1$sto merchant%2$s.\n"
|
||||
" (%3$s)\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:392
|
||||
#: src/webex/pages/popup.tsx:399
|
||||
#, c-format
|
||||
msgid "Unknown event (%1$s)"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:435
|
||||
#: src/webex/pages/popup.tsx:442
|
||||
#, c-format
|
||||
msgid "Error: could not retrieve event history"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:469
|
||||
#: src/webex/pages/popup.tsx:476
|
||||
#, c-format
|
||||
msgid "Your wallet has no events recorded."
|
||||
msgstr ""
|
||||
|
@ -138,6 +138,15 @@ strings['de'] = {
|
||||
"Error: could not retrieve balance information.": [
|
||||
""
|
||||
],
|
||||
"Payback": [
|
||||
""
|
||||
],
|
||||
"Return Electronic Cash to Bank Account": [
|
||||
""
|
||||
],
|
||||
"Manage Trusted Auditors and Exchanges": [
|
||||
""
|
||||
],
|
||||
"Bank requested reserve (%1$s) for\n %2$s.\n": [
|
||||
"Bank bestätig anlegen der Reserve (%1$s) bei %2$s"
|
||||
],
|
||||
@ -294,6 +303,15 @@ strings['en-US'] = {
|
||||
"Error: could not retrieve balance information.": [
|
||||
""
|
||||
],
|
||||
"Payback": [
|
||||
""
|
||||
],
|
||||
"Return Electronic Cash to Bank Account": [
|
||||
""
|
||||
],
|
||||
"Manage Trusted Auditors and Exchanges": [
|
||||
""
|
||||
],
|
||||
"Bank requested reserve (%1$s) for\n %2$s.\n": [
|
||||
""
|
||||
],
|
||||
@ -450,6 +468,15 @@ strings['fr'] = {
|
||||
"Error: could not retrieve balance information.": [
|
||||
""
|
||||
],
|
||||
"Payback": [
|
||||
""
|
||||
],
|
||||
"Return Electronic Cash to Bank Account": [
|
||||
""
|
||||
],
|
||||
"Manage Trusted Auditors and Exchanges": [
|
||||
""
|
||||
],
|
||||
"Bank requested reserve (%1$s) for\n %2$s.\n": [
|
||||
""
|
||||
],
|
||||
@ -606,6 +633,15 @@ strings['it'] = {
|
||||
"Error: could not retrieve balance information.": [
|
||||
""
|
||||
],
|
||||
"Payback": [
|
||||
""
|
||||
],
|
||||
"Return Electronic Cash to Bank Account": [
|
||||
""
|
||||
],
|
||||
"Manage Trusted Auditors and Exchanges": [
|
||||
""
|
||||
],
|
||||
"Bank requested reserve (%1$s) for\n %2$s.\n": [
|
||||
""
|
||||
],
|
||||
|
@ -56,67 +56,67 @@ msgid ""
|
||||
"wallet."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:212
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:213
|
||||
#, c-format
|
||||
msgid "Withdrawal fees:"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:213
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:214
|
||||
#, c-format
|
||||
msgid "Rounding loss:"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:214
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:215
|
||||
#, c-format
|
||||
msgid "Earliest expiration (for deposit): %1$s"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:219
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:220
|
||||
#, c-format
|
||||
msgid "# Coins"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:220
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:221
|
||||
#, c-format
|
||||
msgid "Value"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:221
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:222
|
||||
#, c-format
|
||||
msgid "Withdraw Fee"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:222
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:223
|
||||
#, c-format
|
||||
msgid "Refresh Fee"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:223
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:224
|
||||
#, c-format
|
||||
msgid "Deposit Fee"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:276
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:278
|
||||
#, c-format
|
||||
msgid "Select"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:292
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:294
|
||||
#, c-format
|
||||
msgid "Error: URL may not be relative"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:360
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:362
|
||||
#, c-format
|
||||
msgid "The exchange is trusted by the wallet.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:366
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:368
|
||||
#, c-format
|
||||
msgid "The exchange is audited by a trusted auditor.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:372
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:374
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Warning: The exchange is neither directly trusted nor audited by a trusted "
|
||||
@ -124,7 +124,7 @@ msgid ""
|
||||
"If you withdraw from this exchange, it will be trusted in the future.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:381
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:383
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Using exchange provider%1$s.\n"
|
||||
@ -132,151 +132,166 @@ msgid ""
|
||||
" %2$s in fees.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:395
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:397
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Waiting for a response from\n"
|
||||
" %1$s"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:406
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:408
|
||||
#, c-format
|
||||
msgid "A problem occured, see below. %1$s"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:412
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:414
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Information about fees will be available when an exchange provider is "
|
||||
"selected."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:455
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:457
|
||||
#, c-format
|
||||
msgid "Accept fees and withdraw"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:460
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:462
|
||||
#, c-format
|
||||
msgid "Change Exchange Provider"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:517
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:519
|
||||
#, c-format
|
||||
msgid "You are about to withdraw %1$s from your bank account into your wallet."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:600
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:607
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Oops, something went wrong. The wallet responded with error status (%1$s)."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:611
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:616
|
||||
#, c-format
|
||||
msgid "Checking URL, please wait ..."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:625
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:630
|
||||
#, c-format
|
||||
msgid "Can't parse amount: %1$s"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:632
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:637
|
||||
#, c-format
|
||||
msgid "Can't parse wire_types: %1$s"
|
||||
msgstr ""
|
||||
|
||||
#. TODO:generic error reporting function or component.
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:652
|
||||
#: src/webex/pages/confirm-create-reserve.tsx:663
|
||||
#, c-format
|
||||
msgid "Fatal error: \"%1$s\"."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:160
|
||||
#: src/webex/pages/popup.tsx:161
|
||||
#, c-format
|
||||
msgid "Balance"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:163
|
||||
#: src/webex/pages/popup.tsx:164
|
||||
#, c-format
|
||||
msgid "History"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:166
|
||||
#: src/webex/pages/popup.tsx:167
|
||||
#, c-format
|
||||
msgid "Debug"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:242
|
||||
#: src/webex/pages/popup.tsx:247
|
||||
#, c-format
|
||||
msgid "help"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:247
|
||||
#: src/webex/pages/popup.tsx:252
|
||||
#, c-format
|
||||
msgid ""
|
||||
"You have no balance to show. Need some\n"
|
||||
" %1$s getting started?\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:264
|
||||
#: src/webex/pages/popup.tsx:269
|
||||
#, c-format
|
||||
msgid "%1$s incoming\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:277
|
||||
#: src/webex/pages/popup.tsx:282
|
||||
#, c-format
|
||||
msgid "%1$s being spent\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:303
|
||||
#: src/webex/pages/popup.tsx:308
|
||||
#, c-format
|
||||
msgid "Error: could not retrieve balance information."
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:342
|
||||
#: src/webex/pages/popup.tsx:335
|
||||
#, c-format
|
||||
msgid "Payback"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:336
|
||||
#, c-format
|
||||
msgid "Return Electronic Cash to Bank Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:337
|
||||
#, c-format
|
||||
msgid "Manage Trusted Auditors and Exchanges"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:349
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Bank requested reserve (%1$s) for\n"
|
||||
" %2$s.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:353
|
||||
#: src/webex/pages/popup.tsx:360
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Started to withdraw\n"
|
||||
" %1$s from%2$s(%3$s).\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:363
|
||||
#: src/webex/pages/popup.tsx:370
|
||||
#, c-format
|
||||
msgid "Merchant%1$soffered contract%2$s;\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:373
|
||||
#: src/webex/pages/popup.tsx:380
|
||||
#, c-format
|
||||
msgid "Withdrew%1$sfrom%2$s(%3$s).\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:383
|
||||
#: src/webex/pages/popup.tsx:390
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Paid%1$sto merchant%2$s.\n"
|
||||
" (%3$s)\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:392
|
||||
#: src/webex/pages/popup.tsx:399
|
||||
#, c-format
|
||||
msgid "Unknown event (%1$s)"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:435
|
||||
#: src/webex/pages/popup.tsx:442
|
||||
#, c-format
|
||||
msgid "Error: could not retrieve event history"
|
||||
msgstr ""
|
||||
|
||||
#: src/webex/pages/popup.tsx:469
|
||||
#: src/webex/pages/popup.tsx:476
|
||||
#, c-format
|
||||
msgid "Your wallet has no events recorded."
|
||||
msgstr ""
|
||||
|
40
src/query.ts
40
src/query.ts
@ -130,7 +130,11 @@ export interface QueryStream<T> {
|
||||
*/
|
||||
first(): QueryValue<T>;
|
||||
|
||||
then(onfulfill: any, onreject: any): any;
|
||||
/**
|
||||
* Run the query without returning a result.
|
||||
* Useful for queries with side effects.
|
||||
*/
|
||||
run(): Promise<void>;
|
||||
}
|
||||
|
||||
|
||||
@ -225,7 +229,7 @@ export const AbortTransaction = Symbol("abort_transaction");
|
||||
* function.
|
||||
*/
|
||||
export function openPromise<T>(): any {
|
||||
let resolve: ((value?: T | PromiseLike<T>) => void) | null = null;
|
||||
let resolve: ((x?: any) => void) | null = null;
|
||||
let reject: ((reason?: any) => void) | null = null;
|
||||
const promise = new Promise<T>((res, rej) => {
|
||||
resolve = res;
|
||||
@ -239,7 +243,7 @@ export function openPromise<T>(): any {
|
||||
}
|
||||
|
||||
|
||||
abstract class QueryStreamBase<T> implements QueryStream<T>, PromiseLike<void> {
|
||||
abstract class QueryStreamBase<T> implements QueryStream<T> {
|
||||
abstract subscribe(f: (isDone: boolean,
|
||||
value: any,
|
||||
tx: IDBTransaction) => void): void;
|
||||
@ -250,11 +254,6 @@ abstract class QueryStreamBase<T> implements QueryStream<T>, PromiseLike<void> {
|
||||
return new FirstQueryValue(this);
|
||||
}
|
||||
|
||||
then<R>(onfulfilled: (value: void) => R | PromiseLike<R>,
|
||||
onrejected: (reason: any) => R | PromiseLike<R>): PromiseLike<R> {
|
||||
return this.root.then(onfulfilled, onrejected);
|
||||
}
|
||||
|
||||
flatMap<S>(f: (x: T) => S[]): QueryStream<S> {
|
||||
return new QueryStreamFlatMap<T, S>(this, f);
|
||||
}
|
||||
@ -279,8 +278,7 @@ abstract class QueryStreamBase<T> implements QueryStream<T>, PromiseLike<void> {
|
||||
keyFn: (obj: T) => I): QueryStream<JoinResult<T, S>> {
|
||||
this.root.addStoreAccess(store.name, false);
|
||||
return new QueryStreamKeyJoin<T, S>(this, store.name, keyFn);
|
||||
}
|
||||
|
||||
}
|
||||
filter(f: (x: any) => boolean): QueryStream<T> {
|
||||
return new QueryStreamFilter(this, f);
|
||||
}
|
||||
@ -318,6 +316,21 @@ abstract class QueryStreamBase<T> implements QueryStream<T>, PromiseLike<void> {
|
||||
.then(() => this.root.finish())
|
||||
.then(() => promise);
|
||||
}
|
||||
|
||||
run(): Promise<void> {
|
||||
const {resolve, promise} = openPromise();
|
||||
|
||||
this.subscribe((isDone, value) => {
|
||||
if (isDone) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
return Promise.resolve()
|
||||
.then(() => this.root.finish())
|
||||
.then(() => promise);
|
||||
}
|
||||
}
|
||||
|
||||
type FilterFn = (e: any) => boolean;
|
||||
@ -519,7 +532,7 @@ class IterQueryStream<T> extends QueryStreamBase<T> {
|
||||
/**
|
||||
* Root wrapper around an IndexedDB for queries with a fluent interface.
|
||||
*/
|
||||
export class QueryRoot implements PromiseLike<void> {
|
||||
export class QueryRoot {
|
||||
private work: Array<((t: IDBTransaction) => void)> = [];
|
||||
private stores = new Set();
|
||||
private kickoffPromise: Promise<void>;
|
||||
@ -537,11 +550,6 @@ export class QueryRoot implements PromiseLike<void> {
|
||||
constructor(public db: IDBDatabase) {
|
||||
}
|
||||
|
||||
then<R>(onfulfilled: (value: void) => R | PromiseLike<R>,
|
||||
onrejected: (reason: any) => R | PromiseLike<R>): PromiseLike<R> {
|
||||
return this.finish().then(onfulfilled, onrejected);
|
||||
}
|
||||
|
||||
private checkFinished() {
|
||||
if (this.finished) {
|
||||
throw Error("Can't add work to query after it was started");
|
||||
|
192
src/types.ts
192
src/types.ts
@ -126,6 +126,12 @@ export interface ReserveRecord {
|
||||
* withdraw money from it.
|
||||
*/
|
||||
hasPayback: boolean;
|
||||
|
||||
/**
|
||||
* Wire information for the bank account that
|
||||
* transfered funds for this reserve.
|
||||
*/
|
||||
senderWire?: object;
|
||||
}
|
||||
|
||||
|
||||
@ -814,6 +820,61 @@ export enum CoinStatus {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* State of returning a list of coins
|
||||
* to the customer's bank account.
|
||||
*/
|
||||
export interface CoinsReturnRecord {
|
||||
/**
|
||||
* Coins that we're returning.
|
||||
*/
|
||||
coins: CoinPaySig[];
|
||||
|
||||
/**
|
||||
* Responses to the deposit requests.
|
||||
*/
|
||||
responses: any;
|
||||
|
||||
/**
|
||||
* Ephemeral dummy merchant key for
|
||||
* the coins returns operation.
|
||||
*/
|
||||
dummyMerchantPub: string;
|
||||
|
||||
/**
|
||||
* Ephemeral dummy merchant key for
|
||||
* the coins returns operation.
|
||||
*/
|
||||
dummyMerchantPriv: string;
|
||||
|
||||
/**
|
||||
* Contract terms.
|
||||
*/
|
||||
contractTerms: string;
|
||||
|
||||
/**
|
||||
* Hash of contract terms.
|
||||
*/
|
||||
contractTermsHash: string;
|
||||
|
||||
/**
|
||||
* Wire info to send the money for the coins to.
|
||||
*/
|
||||
wire: object;
|
||||
|
||||
/**
|
||||
* Hash of the wire object.
|
||||
*/
|
||||
wireHash: string;
|
||||
|
||||
/**
|
||||
* All coins were deposited.
|
||||
*/
|
||||
finished: boolean;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* CoinRecord as stored in the "coins" data store
|
||||
* of the wallet database.
|
||||
@ -903,14 +964,19 @@ export class ExchangeHandle {
|
||||
|
||||
|
||||
/**
|
||||
* Mapping from currency names to detailed balance
|
||||
* information for that particular currency.
|
||||
* Mapping from currency/exchange to detailed balance
|
||||
* information.
|
||||
*/
|
||||
export interface WalletBalance {
|
||||
/**
|
||||
* Mapping from currency name to defailed balance info.
|
||||
* Mapping from currency name to detailed balance info.
|
||||
*/
|
||||
[currency: string]: WalletBalanceEntry;
|
||||
byExchange: { [exchangeBaseUrl: string]: WalletBalanceEntry };
|
||||
|
||||
/**
|
||||
* Mapping from currency name to detailed balance info.
|
||||
*/
|
||||
byCurrency: { [currency: string]: WalletBalanceEntry };
|
||||
}
|
||||
|
||||
|
||||
@ -942,8 +1008,8 @@ export interface WalletBalanceEntry {
|
||||
*/
|
||||
@Checkable.Class({validate: true})
|
||||
export class ContractTerms {
|
||||
validate() {
|
||||
if (this.exchanges.length === 0) {
|
||||
static validate(x: ContractTerms) {
|
||||
if (x.exchanges.length === 0) {
|
||||
throw Error("no exchanges in contract terms");
|
||||
}
|
||||
}
|
||||
@ -1361,6 +1427,18 @@ export namespace Amounts {
|
||||
value: Number.parseInt(res[2]),
|
||||
};
|
||||
}
|
||||
|
||||
export function toFloat(a: AmountJson): number {
|
||||
return a.value + (a.fraction / fractionalBase);
|
||||
}
|
||||
|
||||
export function fromFloat(floatVal: number, currency: string) {
|
||||
return {
|
||||
currency,
|
||||
fraction: (floatVal - Math.floor(floatVal)) * fractionalBase,
|
||||
value: Math.floor(floatVal),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1457,7 +1535,7 @@ export interface PayReq {
|
||||
order_id: string;
|
||||
|
||||
/**
|
||||
* Exchange that the coins are from.
|
||||
* Exchange that the coins are from (base URL).
|
||||
*/
|
||||
exchange: string;
|
||||
}
|
||||
@ -1484,3 +1562,103 @@ export interface QueryPaymentFound {
|
||||
contractTerms: ContractTerms;
|
||||
payReq: PayReq;
|
||||
}
|
||||
|
||||
/**
|
||||
* Information about all sender wire details known to the wallet,
|
||||
* as well as exchanges that accept these wire types.
|
||||
*/
|
||||
export interface SenderWireInfos {
|
||||
/**
|
||||
* Mapping from exchange base url to list of accepted
|
||||
* wire types.
|
||||
*/
|
||||
exchangeWireTypes: { [exchangeBaseUrl: string]: string[] };
|
||||
|
||||
/**
|
||||
* Sender wire types stored in the wallet.
|
||||
*/
|
||||
senderWires: object[];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Request to mark a reserve as confirmed.
|
||||
*/
|
||||
@Checkable.Class()
|
||||
export class CreateReserveRequest {
|
||||
/**
|
||||
* The initial amount for the reserve.
|
||||
*/
|
||||
@Checkable.Value(AmountJson)
|
||||
amount: AmountJson;
|
||||
|
||||
/**
|
||||
* Exchange URL where the bank should create the reserve.
|
||||
*/
|
||||
@Checkable.String
|
||||
exchange: string;
|
||||
|
||||
/**
|
||||
* Wire details for the bank account that sent the funds to the exchange.
|
||||
*/
|
||||
@Checkable.Optional(Checkable.Any)
|
||||
senderWire?: object;
|
||||
|
||||
/**
|
||||
* Verify that a value matches the schema of this class and convert it into a
|
||||
* member.
|
||||
*/
|
||||
static checked: (obj: any) => CreateReserveRequest;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Request to mark a reserve as confirmed.
|
||||
*/
|
||||
@Checkable.Class()
|
||||
export class ConfirmReserveRequest {
|
||||
/**
|
||||
* Public key of then reserve that should be marked
|
||||
* as confirmed.
|
||||
*/
|
||||
@Checkable.String
|
||||
reservePub: string;
|
||||
|
||||
/**
|
||||
* Verify that a value matches the schema of this class and convert it into a
|
||||
* member.
|
||||
*/
|
||||
static checked: (obj: any) => ConfirmReserveRequest;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wire coins to the user's own bank account.
|
||||
*/
|
||||
@Checkable.Class()
|
||||
export class ReturnCoinsRequest {
|
||||
/**
|
||||
* The amount to wire.
|
||||
*/
|
||||
@Checkable.Value(AmountJson)
|
||||
amount: AmountJson;
|
||||
|
||||
/**
|
||||
* The exchange to take the coins from.
|
||||
*/
|
||||
@Checkable.String
|
||||
exchange: string;
|
||||
|
||||
/**
|
||||
* Wire details for the bank account of the customer that will
|
||||
* receive the funds.
|
||||
*/
|
||||
@Checkable.Any
|
||||
senderWire?: object;
|
||||
|
||||
/**
|
||||
* Verify that a value matches the schema of this class and convert it into a
|
||||
* member.
|
||||
*/
|
||||
static checked: (obj: any) => ReturnCoinsRequest;
|
||||
}
|
||||
|
369
src/wallet.ts
369
src/wallet.ts
@ -49,10 +49,13 @@ import {
|
||||
Amounts,
|
||||
Auditor,
|
||||
CheckPayResult,
|
||||
CoinPaySig,
|
||||
CoinRecord,
|
||||
CoinStatus,
|
||||
ConfirmPayResult,
|
||||
ConfirmReserveRequest,
|
||||
ContractTerms,
|
||||
CreateReserveRequest,
|
||||
CreateReserveResponse,
|
||||
CurrencyRecord,
|
||||
Denomination,
|
||||
@ -73,6 +76,8 @@ import {
|
||||
RefreshSessionRecord,
|
||||
ReserveCreationInfo,
|
||||
ReserveRecord,
|
||||
ReturnCoinsRequest,
|
||||
SenderWireInfos,
|
||||
WalletBalance,
|
||||
WalletBalanceEntry,
|
||||
WireFee,
|
||||
@ -236,51 +241,6 @@ class WireDetailJson {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Request to mark a reserve as confirmed.
|
||||
*/
|
||||
@Checkable.Class()
|
||||
export class CreateReserveRequest {
|
||||
/**
|
||||
* The initial amount for the reserve.
|
||||
*/
|
||||
@Checkable.Value(AmountJson)
|
||||
amount: AmountJson;
|
||||
|
||||
/**
|
||||
* Exchange URL where the bank should create the reserve.
|
||||
*/
|
||||
@Checkable.String
|
||||
exchange: string;
|
||||
|
||||
/**
|
||||
* Verify that a value matches the schema of this class and convert it into a
|
||||
* member.
|
||||
*/
|
||||
static checked: (obj: any) => CreateReserveRequest;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Request to mark a reserve as confirmed.
|
||||
*/
|
||||
@Checkable.Class()
|
||||
export class ConfirmReserveRequest {
|
||||
/**
|
||||
* Public key of then reserve that should be marked
|
||||
* as confirmed.
|
||||
*/
|
||||
@Checkable.String
|
||||
reservePub: string;
|
||||
|
||||
/**
|
||||
* Verify that a value matches the schema of this class and convert it into a
|
||||
* member.
|
||||
*/
|
||||
static checked: (obj: any) => ConfirmReserveRequest;
|
||||
}
|
||||
|
||||
|
||||
interface TransactionRecord {
|
||||
contractTermsHash: string;
|
||||
contractTerms: ContractTerms;
|
||||
@ -329,6 +289,48 @@ export interface ConfigRecord {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Coin that we're depositing ourselves.
|
||||
*/
|
||||
export interface DepositCoin {
|
||||
coinPaySig: CoinPaySig;
|
||||
|
||||
/**
|
||||
* Undefined if coin not deposited, otherwise signature
|
||||
* from the exchange confirming the deposit.
|
||||
*/
|
||||
depositedSig?: string;
|
||||
}
|
||||
|
||||
export interface CoinsReturnRecord {
|
||||
/**
|
||||
* Hash of the contract for sending coins to our own bank account.
|
||||
*/
|
||||
contractTermsHash: string;
|
||||
|
||||
contractTerms: ContractTerms;
|
||||
|
||||
/**
|
||||
* Private key where corresponding
|
||||
* public key is used in the contract terms
|
||||
* as merchant pub.
|
||||
*/
|
||||
merchantPriv: string;
|
||||
|
||||
coins: DepositCoin[];
|
||||
|
||||
/**
|
||||
* Exchange base URL to deposit coins at.
|
||||
*/
|
||||
exchange: string;
|
||||
|
||||
/**
|
||||
* Our own wire information for the deposit.
|
||||
*/
|
||||
wire: any;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wallet protocol version spoken with the exchange
|
||||
* and merchant.
|
||||
@ -343,7 +345,7 @@ export const WALLET_PROTOCOL_VERSION = "0:0:0";
|
||||
* In the future we might consider adding migration functions for
|
||||
* each version increment.
|
||||
*/
|
||||
export const WALLET_DB_VERSION = 18;
|
||||
export const WALLET_DB_VERSION = 19;
|
||||
|
||||
const builtinCurrencies: CurrencyRecord[] = [
|
||||
{
|
||||
@ -421,6 +423,7 @@ export function selectPayCoins(cds: CoinWithDenom[], paymentAmount: AmountJson,
|
||||
Amounts.add(paymentAmount,
|
||||
denom.feeDeposit).amount) >= 0;
|
||||
isBelowFee = Amounts.cmp(accFee, depositFeeLimit) <= 0;
|
||||
|
||||
if ((coversAmount && isBelowFee) || coversAmountWithFee) {
|
||||
return cdsResult;
|
||||
}
|
||||
@ -553,6 +556,7 @@ export namespace Stores {
|
||||
}
|
||||
|
||||
export const coins = new CoinsStore();
|
||||
export const coinsReturns = new Store<CoinsReturnRecord>("coinsReturns", {keyPath: "contractTermsHash"});
|
||||
export const config = new ConfigStore();
|
||||
export const currencies = new CurrenciesStore();
|
||||
export const denominations = new DenominationsStore();
|
||||
@ -700,6 +704,12 @@ export class Wallet {
|
||||
this.continueRefreshSession(r);
|
||||
});
|
||||
|
||||
this.q()
|
||||
.iter(Stores.coinsReturns)
|
||||
.reduce((r: CoinsReturnRecord) => {
|
||||
this.depositReturnedCoins(r);
|
||||
});
|
||||
|
||||
// FIXME: optimize via index
|
||||
this.q()
|
||||
.iter(Stores.coins)
|
||||
@ -712,6 +722,58 @@ export class Wallet {
|
||||
}
|
||||
|
||||
|
||||
private async getCoinsForReturn(exchangeBaseUrl: string, amount: AmountJson): Promise<CoinWithDenom[] | undefined> {
|
||||
const exchange = await this.q().get(Stores.exchanges, exchangeBaseUrl);
|
||||
if (!exchange) {
|
||||
throw Error(`Exchange ${exchangeBaseUrl} not known to the wallet`);
|
||||
}
|
||||
|
||||
const coins: CoinRecord[] = await (
|
||||
this.q()
|
||||
.iterIndex(Stores.coins.exchangeBaseUrlIndex, exchange.baseUrl)
|
||||
.toArray()
|
||||
);
|
||||
|
||||
if (!coins || !coins.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Denomination of the first coin, we assume that all other
|
||||
// coins have the same currency
|
||||
const firstDenom = await this.q().get(Stores.denominations,
|
||||
[
|
||||
exchange.baseUrl,
|
||||
coins[0].denomPub,
|
||||
]);
|
||||
if (!firstDenom) {
|
||||
throw Error("db inconsistent");
|
||||
}
|
||||
const currency = firstDenom.value.currency;
|
||||
|
||||
const cds: CoinWithDenom[] = [];
|
||||
for (const coin of coins) {
|
||||
const denom = await this.q().get(Stores.denominations,
|
||||
[exchange.baseUrl, coin.denomPub]);
|
||||
if (!denom) {
|
||||
throw Error("db inconsistent");
|
||||
}
|
||||
if (denom.value.currency !== currency) {
|
||||
console.warn(`same pubkey for different currencies at exchange ${exchange.baseUrl}`);
|
||||
continue;
|
||||
}
|
||||
if (coin.suspended) {
|
||||
continue;
|
||||
}
|
||||
if (coin.status !== CoinStatus.Fresh) {
|
||||
continue;
|
||||
}
|
||||
cds.push({coin, denom});
|
||||
}
|
||||
|
||||
return selectPayCoins(cds, amount, amount);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get exchanges and associated coins that are still spendable,
|
||||
* but only if the sum the coins' remaining value exceeds the payment amount.
|
||||
@ -769,6 +831,7 @@ export class Wallet {
|
||||
if (!coins || coins.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Denomination of the first coin, we assume that all other
|
||||
// coins have the same currency
|
||||
const firstDenom = await this.q().get(Stores.denominations,
|
||||
@ -903,7 +966,7 @@ export class Wallet {
|
||||
*/
|
||||
async confirmPay(proposalId: number): Promise<ConfirmPayResult> {
|
||||
console.log("executing confirmPay");
|
||||
const proposal = await this.q().get(Stores.proposals, proposalId);
|
||||
const proposal: ProposalRecord|undefined = await this.q().get(Stores.proposals, proposalId);
|
||||
|
||||
if (!proposal) {
|
||||
throw Error(`proposal with id ${proposalId} not found`);
|
||||
@ -936,7 +999,7 @@ export class Wallet {
|
||||
}
|
||||
const {exchangeUrl, cds} = res;
|
||||
|
||||
const ds = await this.cryptoApi.signDeposit(proposal, cds);
|
||||
const ds = await this.cryptoApi.signDeposit(proposal.contractTerms, cds);
|
||||
await this.recordConfirmPay(proposal, ds, exchangeUrl);
|
||||
return "paid";
|
||||
}
|
||||
@ -1138,6 +1201,7 @@ export class Wallet {
|
||||
requested_amount: req.amount,
|
||||
reserve_priv: keypair.priv,
|
||||
reserve_pub: keypair.pub,
|
||||
senderWire: req.senderWire,
|
||||
};
|
||||
|
||||
const historyEntry = {
|
||||
@ -1755,22 +1819,26 @@ export class Wallet {
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve a mapping from currency name to the amount
|
||||
* that is currenctly available for spending in the wallet.
|
||||
* Get detailed balance information, sliced by exchange and by currency.
|
||||
*/
|
||||
async getBalances(): Promise<WalletBalance> {
|
||||
function ensureEntry(balance: WalletBalance, currency: string) {
|
||||
let entry: WalletBalanceEntry|undefined = balance[currency];
|
||||
const z = Amounts.getZero(currency);
|
||||
if (!entry) {
|
||||
balance[currency] = entry = {
|
||||
available: z,
|
||||
paybackAmount: z,
|
||||
pendingIncoming: z,
|
||||
pendingPayment: z,
|
||||
};
|
||||
/**
|
||||
* Add amount to a balance field, both for
|
||||
* the slicing by exchange and currency.
|
||||
*/
|
||||
function addTo(balance: WalletBalance, field: keyof WalletBalanceEntry, amount: AmountJson, exchange: string): void {
|
||||
const z = Amounts.getZero(amount.currency);
|
||||
const balanceIdentity = {available: z, paybackAmount: z, pendingIncoming: z, pendingPayment: z};
|
||||
let entryCurr = balance.byCurrency[amount.currency];
|
||||
if (!entryCurr) {
|
||||
balance.byCurrency[amount.currency] = entryCurr = { ...balanceIdentity };
|
||||
}
|
||||
return entry;
|
||||
let entryEx = balance.byExchange[exchange];
|
||||
if (!entryEx) {
|
||||
balance.byExchange[exchange] = entryEx = { ...balanceIdentity };
|
||||
}
|
||||
entryCurr[field] = Amounts.add(entryCurr[field], amount).amount;
|
||||
entryEx[field] = Amounts.add(entryEx[field], amount).amount;
|
||||
}
|
||||
|
||||
function collectBalances(c: CoinRecord, balance: WalletBalance) {
|
||||
@ -1780,9 +1848,8 @@ export class Wallet {
|
||||
if (!(c.status === CoinStatus.Dirty || c.status === CoinStatus.Fresh)) {
|
||||
return balance;
|
||||
}
|
||||
const currency = c.currentAmount.currency;
|
||||
const entry = ensureEntry(balance, currency);
|
||||
entry.available = Amounts.add(entry.available, c.currentAmount).amount;
|
||||
console.log("collecting balance");
|
||||
addTo(balance, "available", c.currentAmount, c.exchangeBaseUrl);
|
||||
return balance;
|
||||
}
|
||||
|
||||
@ -1790,15 +1857,13 @@ export class Wallet {
|
||||
if (!r.confirmed) {
|
||||
return balance;
|
||||
}
|
||||
const entry = ensureEntry(balance, r.requested_amount.currency);
|
||||
let amount = r.current_amount;
|
||||
if (!amount) {
|
||||
amount = r.requested_amount;
|
||||
}
|
||||
amount = Amounts.add(amount, r.precoin_amount).amount;
|
||||
if (Amounts.cmp(smallestWithdraw[r.exchange_base_url], amount) < 0) {
|
||||
entry.pendingIncoming = Amounts.add(entry.pendingIncoming,
|
||||
amount).amount;
|
||||
addTo(balance, "pendingIncoming", amount, r.exchange_base_url);
|
||||
}
|
||||
return balance;
|
||||
}
|
||||
@ -1807,9 +1872,8 @@ export class Wallet {
|
||||
if (!r.hasPayback) {
|
||||
return balance;
|
||||
}
|
||||
const entry = ensureEntry(balance, r.requested_amount.currency);
|
||||
if (Amounts.cmp(smallestWithdraw[r.exchange_base_url], r.current_amount!) < 0) {
|
||||
entry.paybackAmount = Amounts.add(entry.paybackAmount, r.current_amount!).amount;
|
||||
addTo(balance, "paybackAmount", r.current_amount!, r.exchange_base_url);
|
||||
}
|
||||
return balance;
|
||||
}
|
||||
@ -1821,9 +1885,7 @@ export class Wallet {
|
||||
if (r.finished) {
|
||||
return balance;
|
||||
}
|
||||
const entry = ensureEntry(balance, r.valueWithFee.currency);
|
||||
entry.pendingIncoming = Amounts.add(entry.pendingIncoming,
|
||||
r.valueOutput).amount;
|
||||
addTo(balance, "pendingIncoming", r.valueOutput, r.exchangeBaseUrl);
|
||||
|
||||
return balance;
|
||||
}
|
||||
@ -1832,10 +1894,7 @@ export class Wallet {
|
||||
if (t.finished) {
|
||||
return balance;
|
||||
}
|
||||
const entry = ensureEntry(balance, t.contractTerms.amount.currency);
|
||||
entry.pendingPayment = Amounts.add(entry.pendingPayment,
|
||||
t.contractTerms.amount).amount;
|
||||
|
||||
addTo(balance, "pendingIncoming", t.contractTerms.amount, t.payReq.exchange);
|
||||
return balance;
|
||||
}
|
||||
|
||||
@ -1852,7 +1911,10 @@ export class Wallet {
|
||||
return sw;
|
||||
}
|
||||
|
||||
const balance = {};
|
||||
const balance = {
|
||||
byExchange: {},
|
||||
byCurrency: {},
|
||||
};
|
||||
// Mapping from exchange pub to smallest
|
||||
// possible amount we can withdraw
|
||||
let smallestWithdraw: {[baseUrl: string]: AmountJson} = {};
|
||||
@ -1876,7 +1938,6 @@ export class Wallet {
|
||||
.reduce(collectPayments, balance);
|
||||
await tx.finish();
|
||||
return balance;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -2347,4 +2408,156 @@ export class Wallet {
|
||||
stop() {
|
||||
this.timerGroup.stopCurrentAndFutureTimers();
|
||||
}
|
||||
|
||||
async getSenderWireInfos(): Promise<SenderWireInfos> {
|
||||
const m: { [url: string]: Set<string> } = {};
|
||||
await this.q().iter(Stores.exchangeWireFees).map((x) => {
|
||||
const s = m[x.exchangeBaseUrl] = m[x.exchangeBaseUrl] || new Set();
|
||||
Object.keys(x.feesForType).map((k) => s.add(k));
|
||||
}).run();
|
||||
console.log(m);
|
||||
const exchangeWireTypes: { [url: string]: string[] } = {};
|
||||
Object.keys(m).map((e) => { exchangeWireTypes[e] = Array.from(m[e]); });
|
||||
|
||||
const senderWiresSet = new Set();
|
||||
await this.q().iter(Stores.reserves).map((x) => {
|
||||
if (x.senderWire) {
|
||||
senderWiresSet.add(JSON.stringify(x.senderWire));
|
||||
}
|
||||
}).run();
|
||||
const senderWires = Array.from(senderWiresSet).map((x) => JSON.parse(x));
|
||||
|
||||
return {
|
||||
exchangeWireTypes,
|
||||
senderWires,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger paying coins back into the user's account.
|
||||
*/
|
||||
async returnCoins(req: ReturnCoinsRequest): Promise<void> {
|
||||
console.log("got returnCoins request", req);
|
||||
const wireType = (req.senderWire as any).type;
|
||||
console.log("wireType", wireType);
|
||||
if (!wireType || typeof wireType !== "string") {
|
||||
console.error(`wire type must be a non-empty string, not ${wireType}`);
|
||||
return;
|
||||
}
|
||||
const stampSecNow = Math.floor((new Date()).getTime() / 1000);
|
||||
const exchange = await this.q().get(Stores.exchanges, req.exchange);
|
||||
if (!exchange) {
|
||||
console.error(`Exchange ${req.exchange} not known to the wallet`);
|
||||
return;
|
||||
}
|
||||
const cds = await this.getCoinsForReturn(req.exchange, req.amount);
|
||||
console.log(cds);
|
||||
|
||||
if (!cds) {
|
||||
throw Error("coin return impossible, can't select coins");
|
||||
}
|
||||
|
||||
const { priv, pub } = await this.cryptoApi.createEddsaKeypair();
|
||||
|
||||
const wireHash = await this.cryptoApi.hashString(canonicalJson(req.senderWire));
|
||||
|
||||
const contractTerms: ContractTerms = {
|
||||
H_wire: wireHash,
|
||||
amount: req.amount,
|
||||
auditors: [],
|
||||
wire_method: wireType,
|
||||
pay_deadline: `/Date(${stampSecNow + 60 * 5})/`,
|
||||
locations: [],
|
||||
max_fee: req.amount,
|
||||
merchant: {},
|
||||
merchant_pub: pub,
|
||||
exchanges: [ { master_pub: exchange.masterPublicKey, url: exchange.baseUrl } ],
|
||||
products: [],
|
||||
refund_deadline: `/Date(${stampSecNow + 60 * 5})/`,
|
||||
timestamp: `/Date(${stampSecNow})/`,
|
||||
order_id: "none",
|
||||
pay_url: "",
|
||||
fulfillment_url: "",
|
||||
extra: {},
|
||||
};
|
||||
|
||||
const contractTermsHash = await this.cryptoApi.hashString(canonicalJson(contractTerms));
|
||||
|
||||
const payCoinInfo = await this.cryptoApi.signDeposit(contractTerms, cds);
|
||||
|
||||
console.log("pci", payCoinInfo);
|
||||
|
||||
const coins = payCoinInfo.map((pci) => ({ coinPaySig: pci.sig }));
|
||||
|
||||
const coinsReturnRecord: CoinsReturnRecord = {
|
||||
coins,
|
||||
exchange: exchange.baseUrl,
|
||||
contractTerms,
|
||||
contractTermsHash,
|
||||
merchantPriv: priv,
|
||||
wire: req.senderWire,
|
||||
}
|
||||
|
||||
await this.q()
|
||||
.put(Stores.coinsReturns, coinsReturnRecord)
|
||||
.putAll(Stores.coins, payCoinInfo.map((pci) => pci.updatedCoin))
|
||||
.finish();
|
||||
|
||||
this.depositReturnedCoins(coinsReturnRecord);
|
||||
}
|
||||
|
||||
async depositReturnedCoins(coinsReturnRecord: CoinsReturnRecord): Promise<void> {
|
||||
for (const c of coinsReturnRecord.coins) {
|
||||
if (c.depositedSig) {
|
||||
continue;
|
||||
}
|
||||
const req = {
|
||||
f: c.coinPaySig.f,
|
||||
wire: coinsReturnRecord.wire,
|
||||
H_wire: coinsReturnRecord.contractTerms.H_wire,
|
||||
h_contract_terms: coinsReturnRecord.contractTermsHash,
|
||||
coin_pub: c.coinPaySig.coin_pub,
|
||||
denom_pub: c.coinPaySig.denom_pub,
|
||||
ub_sig: c.coinPaySig.ub_sig,
|
||||
timestamp: coinsReturnRecord.contractTerms.timestamp,
|
||||
wire_transfer_deadline: coinsReturnRecord.contractTerms.pay_deadline,
|
||||
pay_deadline: coinsReturnRecord.contractTerms.pay_deadline,
|
||||
refund_deadline: coinsReturnRecord.contractTerms.refund_deadline,
|
||||
merchant_pub: coinsReturnRecord.contractTerms.merchant_pub,
|
||||
coin_sig: c.coinPaySig.coin_sig,
|
||||
};
|
||||
console.log("req", req);
|
||||
const reqUrl = (new URI("deposit")).absoluteTo(coinsReturnRecord.exchange);
|
||||
const resp = await this.http.postJson(reqUrl.href(), req);
|
||||
if (resp.status !== 200) {
|
||||
console.error("deposit failed due to status code", resp);
|
||||
continue;
|
||||
}
|
||||
const respJson = JSON.parse(resp.responseText);
|
||||
if (respJson.status !== "DEPOSIT_OK") {
|
||||
console.error("deposit failed", resp);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!respJson.sig) {
|
||||
console.error("invalid 'sig' field", resp);
|
||||
continue;
|
||||
}
|
||||
|
||||
// FIXME: verify signature
|
||||
|
||||
// For every successful deposit, we replace the old record with an updated one
|
||||
const currentCrr = await this.q().get(Stores.coinsReturns, coinsReturnRecord.contractTermsHash);
|
||||
if (!currentCrr) {
|
||||
console.error("database inconsistent");
|
||||
continue;
|
||||
}
|
||||
for (const nc of currentCrr.coins) {
|
||||
if (nc.coinPaySig.coin_pub === c.coinPaySig.coin_pub) {
|
||||
nc.depositedSig = respJson.sig;
|
||||
}
|
||||
}
|
||||
await this.q().put(Stores.coinsReturns, currentCrr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -168,6 +168,14 @@ export interface MessageMap {
|
||||
request: { };
|
||||
response: void;
|
||||
};
|
||||
"get-sender-wire-infos": {
|
||||
request: { };
|
||||
response: void;
|
||||
};
|
||||
"return-coins": {
|
||||
request: { };
|
||||
response: void;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -6,40 +6,12 @@
|
||||
<title>Taler Wallet: Select Taler Provider</title>
|
||||
|
||||
<link rel="icon" href="/img/icon.png">
|
||||
<link rel="stylesheet" type="text/css" href="../style/wallet.css">
|
||||
<link rel="stylesheet" type="text/css" href="../style/pure.css">
|
||||
<link rel="stylesheet" type="text/css" href="../style/wallet.css">
|
||||
|
||||
<script src="/dist/page-common-bundle.js"></script>
|
||||
<script src="/dist/confirm-create-reserve-bundle.js"></script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-size: 100%;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.button-success {
|
||||
background: rgb(28, 184, 65); /* this is a green */
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
.button-secondary {
|
||||
background: rgb(66, 184, 221); /* this is a light blue */
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
a.opener {
|
||||
color: black;
|
||||
}
|
||||
.opener-open::before {
|
||||
content: "\25bc"
|
||||
}
|
||||
.opener-collapsed::before {
|
||||
content: "\25b6 "
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
@ -219,22 +219,26 @@ class WalletBalanceView extends React.Component<any, any> {
|
||||
this.unmount = true;
|
||||
}
|
||||
|
||||
updateBalance() {
|
||||
chrome.runtime.sendMessage({type: "balances"}, (resp) => {
|
||||
async updateBalance() {
|
||||
let balance: WalletBalance;
|
||||
try {
|
||||
balance = await wxApi.getBalance();
|
||||
} catch (e) {
|
||||
if (this.unmount) {
|
||||
return;
|
||||
}
|
||||
if (resp.error) {
|
||||
this.gotError = true;
|
||||
console.error("could not retrieve balances", resp);
|
||||
this.setState({});
|
||||
return;
|
||||
}
|
||||
this.gotError = false;
|
||||
console.log("got wallet", resp);
|
||||
this.balance = resp;
|
||||
this.gotError = true;
|
||||
console.error("could not retrieve balances", e);
|
||||
this.setState({});
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (this.unmount) {
|
||||
return;
|
||||
}
|
||||
this.gotError = false;
|
||||
console.log("got balance", balance);
|
||||
this.balance = balance;
|
||||
this.setState({});
|
||||
}
|
||||
|
||||
renderEmpty(): JSX.Element {
|
||||
@ -308,8 +312,8 @@ class WalletBalanceView extends React.Component<any, any> {
|
||||
}
|
||||
console.log(wallet);
|
||||
let paybackAvailable = false;
|
||||
const listing = Object.keys(wallet).map((key) => {
|
||||
const entry: WalletBalanceEntry = wallet[key];
|
||||
const listing = Object.keys(wallet.byCurrency).map((key) => {
|
||||
const entry: WalletBalanceEntry = wallet.byCurrency[key];
|
||||
if (entry.paybackAmount.value !== 0 || entry.paybackAmount.fraction !== 0) {
|
||||
paybackAvailable = true;
|
||||
}
|
||||
@ -321,14 +325,16 @@ class WalletBalanceView extends React.Component<any, any> {
|
||||
</p>
|
||||
);
|
||||
});
|
||||
const link = chrome.extension.getURL("/src/webex/pages/auditors.html");
|
||||
const linkElem = <a className="actionLink" href={link} target="_blank">Trusted Auditors and Exchanges</a>;
|
||||
const paybackLinkElem = <a className="actionLink" href={link} target="_blank">Trusted Auditors and Exchanges</a>;
|
||||
const makeLink = (page: string, name: string) => {
|
||||
const url = chrome.extension.getURL(`/src/webex/pages/${page}`);
|
||||
return <div><a className="actionLink" href={url} target="_blank">{name}</a></div>;
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
{listing.length > 0 ? listing : this.renderEmpty()}
|
||||
{paybackAvailable && paybackLinkElem}
|
||||
{linkElem}
|
||||
{paybackAvailable && makeLink("payback", i18n.str`Payback`)}
|
||||
{makeLink("return-coins.html#dissolve", i18n.str`Return Electronic Cash to Bank Account`)}
|
||||
{makeLink("auditors.html", i18n.str`Manage Trusted Auditors and Exchanges`)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
19
src/webex/pages/return-coins.html
Normal file
19
src/webex/pages/return-coins.html
Normal file
@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Taler Wallet: Return Coins to Bank Account</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="../style/pure.css">
|
||||
<link rel="stylesheet" type="text/css" href="../style/wallet.css">
|
||||
|
||||
<link rel="icon" href="/img/icon.png">
|
||||
|
||||
<script src="/dist/page-common-bundle.js"></script>
|
||||
<script src="/dist/return-coins-bundle.js"></script>
|
||||
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
</body>
|
||||
</html>
|
271
src/webex/pages/return-coins.tsx
Normal file
271
src/webex/pages/return-coins.tsx
Normal file
@ -0,0 +1,271 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2017 Inria
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* View and edit auditors.
|
||||
*
|
||||
* @author Florian Dold
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Imports.
|
||||
*/
|
||||
|
||||
import {
|
||||
AmountJson,
|
||||
Amounts,
|
||||
SenderWireInfos,
|
||||
WalletBalance,
|
||||
} from "../../types";
|
||||
|
||||
import * as i18n from "../../i18n";
|
||||
|
||||
import * as wire from "../../wire";
|
||||
|
||||
import {
|
||||
getBalance,
|
||||
getSenderWireInfos,
|
||||
returnCoins,
|
||||
} from "../wxApi";
|
||||
|
||||
import { renderAmount } from "../renderHtml";
|
||||
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
|
||||
interface ReturnSelectionItemProps extends ReturnSelectionListProps {
|
||||
exchangeUrl: string;
|
||||
senderWireInfos: SenderWireInfos;
|
||||
}
|
||||
|
||||
interface ReturnSelectionItemState {
|
||||
selectedValue: string;
|
||||
supportedWires: object[];
|
||||
selectedWire: string;
|
||||
currency: string;
|
||||
}
|
||||
|
||||
class ReturnSelectionItem extends React.Component<ReturnSelectionItemProps, ReturnSelectionItemState> {
|
||||
constructor(props: ReturnSelectionItemProps) {
|
||||
super(props);
|
||||
const exchange = this.props.exchangeUrl;
|
||||
const wireTypes = this.props.senderWireInfos.exchangeWireTypes;
|
||||
const supportedWires = this.props.senderWireInfos.senderWires.filter((x) => {
|
||||
return wireTypes[exchange] && wireTypes[exchange].indexOf((x as any).type) >= 0;
|
||||
});
|
||||
this.state = {
|
||||
currency: props.balance.byExchange[props.exchangeUrl].available.currency,
|
||||
selectedValue: Amounts.toFloat(props.balance.byExchange[props.exchangeUrl].available).toString(),
|
||||
selectedWire: "",
|
||||
supportedWires,
|
||||
};
|
||||
}
|
||||
render(): JSX.Element {
|
||||
const exchange = this.props.exchangeUrl;
|
||||
const byExchange = this.props.balance.byExchange;
|
||||
const wireTypes = this.props.senderWireInfos.exchangeWireTypes;
|
||||
return (
|
||||
<div key={exchange}>
|
||||
<h2>Exchange {exchange}</h2>
|
||||
<p>Available amount: {renderAmount(byExchange[exchange].available)}</p>
|
||||
<p>Supported wire methods: {wireTypes[exchange].length ? wireTypes[exchange].join(", ") : "none"}</p>
|
||||
<p>Wire {""}
|
||||
<input
|
||||
type="text"
|
||||
size={this.state.selectedValue.length || 1}
|
||||
value={this.state.selectedValue}
|
||||
onChange={(evt) => this.setState({selectedValue: evt.target.value})}
|
||||
style={{textAlign: "center"}}
|
||||
/> {this.props.balance.byExchange[exchange].available.currency} {""}
|
||||
to account {""}
|
||||
<select value={this.state.selectedWire} onChange={(evt) => this.setState({selectedWire: evt.target.value})}>
|
||||
<option style={{display: "none"}}>Select account</option>
|
||||
{this.state.supportedWires.map((w, n) =>
|
||||
<option value={n.toString()} key={JSON.stringify(w)}>{n+1}: {wire.summarizeWire(w)}</option>
|
||||
)}
|
||||
</select>.
|
||||
</p>
|
||||
{this.state.selectedWire
|
||||
? <button className="pure-button button-success" onClick={() => this.select()}>
|
||||
{i18n.str`Wire to bank account`}
|
||||
</button>
|
||||
: null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
select() {
|
||||
let val: number;
|
||||
let selectedWire: number;
|
||||
try {
|
||||
val = Number.parseFloat(this.state.selectedValue);
|
||||
selectedWire = Number.parseInt(this.state.selectedWire);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return;
|
||||
}
|
||||
this.props.selectDetail({
|
||||
amount: Amounts.fromFloat(val, this.state.currency),
|
||||
exchange: this.props.exchangeUrl,
|
||||
senderWire: this.state.supportedWires[selectedWire],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
interface ReturnSelectionListProps {
|
||||
balance: WalletBalance;
|
||||
senderWireInfos: SenderWireInfos;
|
||||
selectDetail(d: SelectedDetail): void;
|
||||
}
|
||||
|
||||
class ReturnSelectionList extends React.Component<ReturnSelectionListProps, {}> {
|
||||
render(): JSX.Element {
|
||||
const byExchange = this.props.balance.byExchange;
|
||||
const exchanges = Object.keys(byExchange);
|
||||
if (!exchanges.length) {
|
||||
return <p className="errorbox">Currently no funds available to transfer.</p>;
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
{exchanges.map((e) => <ReturnSelectionItem key={e} exchangeUrl={e} {...this.props} />)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
interface SelectedDetail {
|
||||
amount: AmountJson;
|
||||
senderWire: any;
|
||||
exchange: string;
|
||||
}
|
||||
|
||||
|
||||
interface ReturnConfirmationProps {
|
||||
detail: SelectedDetail;
|
||||
cancel(): void;
|
||||
confirm(): void;
|
||||
}
|
||||
|
||||
class ReturnConfirmation extends React.Component<ReturnConfirmationProps, {}> {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<p>Please confirm if you want to transmit <strong>{renderAmount(this.props.detail.amount)}</strong> at {""}
|
||||
{this.props.detail.exchange} to account {""}
|
||||
<strong style={{whiteSpace: "nowrap"}}>{wire.summarizeWire(this.props.detail.senderWire)}</strong>.
|
||||
</p>
|
||||
<button className="pure-button button-success" onClick={() => this.props.confirm()}>
|
||||
{i18n.str`Confirm`}
|
||||
</button>
|
||||
<button className="pure-button" onClick={() => this.props.cancel()}>
|
||||
{i18n.str`Cancel`}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
interface ReturnCoinsState {
|
||||
balance: WalletBalance | undefined;
|
||||
senderWireInfos: SenderWireInfos | undefined;
|
||||
selectedReturn: SelectedDetail | undefined;
|
||||
/**
|
||||
* Last confirmed detail, so we can show a nice box.
|
||||
*/
|
||||
lastConfirmedDetail: SelectedDetail | undefined;
|
||||
}
|
||||
|
||||
class ReturnCoins extends React.Component<any, ReturnCoinsState> {
|
||||
constructor() {
|
||||
super();
|
||||
const port = chrome.runtime.connect();
|
||||
port.onMessage.addListener((msg: any) => {
|
||||
if (msg.notify) {
|
||||
console.log("got notified");
|
||||
this.update();
|
||||
}
|
||||
});
|
||||
this.update();
|
||||
this.state = {} as any;
|
||||
}
|
||||
|
||||
async update() {
|
||||
const balance = await getBalance();
|
||||
const senderWireInfos = await getSenderWireInfos();
|
||||
console.log("got swi", senderWireInfos);
|
||||
console.log("got bal", balance);
|
||||
this.setState({ balance, senderWireInfos });
|
||||
}
|
||||
|
||||
selectDetail(d: SelectedDetail) {
|
||||
this.setState({selectedReturn: d});
|
||||
}
|
||||
|
||||
async confirm() {
|
||||
const selectedReturn = this.state.selectedReturn;
|
||||
if (!selectedReturn) {
|
||||
return;
|
||||
}
|
||||
await returnCoins(selectedReturn);
|
||||
await this.update();
|
||||
this.setState({selectedReturn: undefined, lastConfirmedDetail: selectedReturn});
|
||||
}
|
||||
|
||||
async cancel() {
|
||||
this.setState({selectedReturn: undefined, lastConfirmedDetail: undefined});
|
||||
}
|
||||
|
||||
render() {
|
||||
const balance = this.state.balance;
|
||||
const senderWireInfos = this.state.senderWireInfos;
|
||||
if (!balance || !senderWireInfos) {
|
||||
return <span>...</span>;
|
||||
}
|
||||
if (this.state.selectedReturn) {
|
||||
return (
|
||||
<div id="main">
|
||||
<ReturnConfirmation
|
||||
detail={this.state.selectedReturn}
|
||||
cancel={() => this.cancel()}
|
||||
confirm={() => this.confirm()}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div id="main">
|
||||
<h1>Wire electronic cash back to own bank account</h1>
|
||||
<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>
|
||||
{this.state.lastConfirmedDetail
|
||||
? <p className="okaybox">Transfer of {renderAmount(this.state.lastConfirmedDetail.amount)} successfully initiated.</p>
|
||||
: null}
|
||||
<ReturnSelectionList
|
||||
selectDetail={(d) => this.selectDetail(d)}
|
||||
balance={balance}
|
||||
senderWireInfos={senderWireInfos} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function main() {
|
||||
ReactDOM.render(<ReturnCoins />, document.getElementById("container")!);
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", main);
|
@ -1,3 +1,8 @@
|
||||
body {
|
||||
font-size: 100%;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
#main {
|
||||
border: solid 1px black;
|
||||
border-radius: 10px;
|
||||
@ -235,3 +240,14 @@ a.actionLink {
|
||||
font-weight: bold;
|
||||
background: #00FA9A;
|
||||
}
|
||||
|
||||
|
||||
a.opener {
|
||||
color: black;
|
||||
}
|
||||
.opener-open::before {
|
||||
content: "\25bc"
|
||||
}
|
||||
.opener-collapsed::before {
|
||||
content: "\25b6 "
|
||||
}
|
||||
|
@ -31,9 +31,11 @@ import {
|
||||
DenominationRecord,
|
||||
ExchangeRecord,
|
||||
PreCoinRecord,
|
||||
QueryPaymentResult,
|
||||
ReserveCreationInfo,
|
||||
ReserveRecord,
|
||||
QueryPaymentResult,
|
||||
SenderWireInfos,
|
||||
WalletBalance,
|
||||
} from "../types";
|
||||
|
||||
import { MessageType, MessageMap } from "./messages";
|
||||
@ -296,3 +298,26 @@ export function createReserve(args: { amount: AmountJson, exchange: string, send
|
||||
export function resetDb(): Promise<void> {
|
||||
return callBackend("reset-db", { });
|
||||
}
|
||||
|
||||
/**
|
||||
* Get balances for all currencies/exchanges.
|
||||
*/
|
||||
export function getBalance(): Promise<WalletBalance> {
|
||||
return callBackend("balances", { });
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get possible sender wire infos for getting money
|
||||
* wired from an exchange.
|
||||
*/
|
||||
export function getSenderWireInfos(): Promise<SenderWireInfos> {
|
||||
return callBackend("get-sender-wire-infos", { });
|
||||
}
|
||||
|
||||
/**
|
||||
* Return coins to a bank account.
|
||||
*/
|
||||
export function returnCoins(args: { amount: AmountJson, exchange: string, senderWire: object }): Promise<void> {
|
||||
return callBackend("return-coins", args);
|
||||
}
|
||||
|
@ -32,12 +32,13 @@ import {
|
||||
} from "../query";
|
||||
import {
|
||||
AmountJson,
|
||||
Notifier,
|
||||
ProposalRecord,
|
||||
} from "../types";
|
||||
import {
|
||||
ConfirmReserveRequest,
|
||||
CreateReserveRequest,
|
||||
Notifier,
|
||||
ProposalRecord,
|
||||
ReturnCoinsRequest,
|
||||
} from "../types";
|
||||
import {
|
||||
Stores,
|
||||
WALLET_DB_VERSION,
|
||||
Wallet,
|
||||
@ -278,6 +279,18 @@ function handleMessage(sender: MessageSender,
|
||||
}
|
||||
return needsWallet().paymentSucceeded(contractTermsHash, merchantSig);
|
||||
}
|
||||
case "get-sender-wire-infos": {
|
||||
return needsWallet().getSenderWireInfos();
|
||||
}
|
||||
case "return-coins": {
|
||||
const d = {
|
||||
amount: detail.amount,
|
||||
exchange: detail.exchange,
|
||||
senderWire: detail.senderWire,
|
||||
};
|
||||
const req = ReturnCoinsRequest.checked(d);
|
||||
return needsWallet().returnCoins(req);
|
||||
}
|
||||
case "check-upgrade": {
|
||||
let dbResetRequired = false;
|
||||
if (!currentWallet) {
|
||||
|
53
src/wire.ts
Normal file
53
src/wire.ts
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2017 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Display and manipulate wire information.
|
||||
*
|
||||
* Right now, all types are hard-coded. In the future, there might be plugins / configurable
|
||||
* methods or support for the "payto://" URI scheme.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Imports.
|
||||
*/
|
||||
import * as i18n from "./i18n";
|
||||
|
||||
/**
|
||||
* Short summary of the wire information.
|
||||
*
|
||||
* Might abbreviate and return the same summary for different
|
||||
* wire details.
|
||||
*/
|
||||
export function summarizeWire(w: any): string {
|
||||
if (!w.type) {
|
||||
return i18n.str`Invalid Wire`;
|
||||
}
|
||||
switch (w.type.toLowerCase()) {
|
||||
case "test":
|
||||
if (!w.account_number && w.account_number !== 0) {
|
||||
return i18n.str`Invalid Test Wire Detail`;
|
||||
}
|
||||
if (!w.bank_uri) {
|
||||
return i18n.str`Invalid Test Wire Detail`;
|
||||
}
|
||||
return i18n.str`Test Wire Acct #${w.account_number} on ${w.bank_uri}`;
|
||||
default:
|
||||
return i18n.str`Unknown Wire Detail`;
|
||||
}
|
||||
}
|
||||
|
@ -64,6 +64,7 @@
|
||||
"src/webex/pages/payback.tsx",
|
||||
"src/webex/pages/popup.tsx",
|
||||
"src/webex/pages/reset-required.tsx",
|
||||
"src/webex/pages/return-coins.tsx",
|
||||
"src/webex/pages/show-db.ts",
|
||||
"src/webex/pages/tree.tsx",
|
||||
"src/webex/renderHtml.tsx",
|
||||
|
@ -69,11 +69,12 @@ module.exports = function (env) {
|
||||
"confirm-create-reserve": "./src/webex/pages/confirm-create-reserve.tsx",
|
||||
"error": "./src/webex/pages/error.tsx",
|
||||
"logs": "./src/webex/pages/logs.tsx",
|
||||
"payback": "./src/webex/pages/payback.tsx",
|
||||
"popup": "./src/webex/pages/popup.tsx",
|
||||
"reset-required": "./src/webex/pages/reset-required.tsx",
|
||||
"return-coins": "./src/webex/pages/return-coins.tsx",
|
||||
"show-db": "./src/webex/pages/show-db.ts",
|
||||
"tree": "./src/webex/pages/tree.tsx",
|
||||
"payback": "./src/webex/pages/payback.tsx",
|
||||
"reset-required": "./src/webex/pages/reset-required.tsx",
|
||||
},
|
||||
plugins: [
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
|
Loading…
Reference in New Issue
Block a user