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,
|
type: target,
|
||||||
}, ["(root)"]);
|
}, ["(root)"]);
|
||||||
if (opts.validate) {
|
if (opts.validate) {
|
||||||
const instance = new target();
|
if (target.validate !== "function") {
|
||||||
if (typeof instance.validate !== "function") {
|
|
||||||
throw Error("invalid Checkable annotion: validate method required");
|
throw Error("invalid Checkable annotion: validate method required");
|
||||||
}
|
}
|
||||||
// May throw exception
|
// May throw exception
|
||||||
instance.validate.call(cv);
|
target.validate(cv);
|
||||||
}
|
}
|
||||||
return cv;
|
return cv;
|
||||||
};
|
};
|
||||||
|
@ -26,8 +26,8 @@
|
|||||||
import {
|
import {
|
||||||
AmountJson,
|
AmountJson,
|
||||||
CoinRecord,
|
CoinRecord,
|
||||||
|
ContractTerms,
|
||||||
DenominationRecord,
|
DenominationRecord,
|
||||||
ProposalRecord,
|
|
||||||
PayCoinInfo,
|
PayCoinInfo,
|
||||||
PaybackRequest,
|
PaybackRequest,
|
||||||
PreCoinRecord,
|
PreCoinRecord,
|
||||||
@ -277,9 +277,9 @@ export class CryptoApi {
|
|||||||
return this.doRpc<PayCoinInfo>("isValidPaymentSignature", 1, sig, contractHash, merchantPub);
|
return this.doRpc<PayCoinInfo>("isValidPaymentSignature", 1, sig, contractHash, merchantPub);
|
||||||
}
|
}
|
||||||
|
|
||||||
signDeposit(proposal: ProposalRecord,
|
signDeposit(contractTerms: ContractTerms,
|
||||||
cds: CoinWithDenom[]): Promise<PayCoinInfo> {
|
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}> {
|
createEddsaKeypair(): Promise<{priv: string, pub: string}> {
|
||||||
|
@ -28,8 +28,8 @@ import {
|
|||||||
CoinPaySig,
|
CoinPaySig,
|
||||||
CoinRecord,
|
CoinRecord,
|
||||||
CoinStatus,
|
CoinStatus,
|
||||||
|
ContractTerms,
|
||||||
DenominationRecord,
|
DenominationRecord,
|
||||||
ProposalRecord,
|
|
||||||
PayCoinInfo,
|
PayCoinInfo,
|
||||||
PaybackRequest,
|
PaybackRequest,
|
||||||
PreCoinRecord,
|
PreCoinRecord,
|
||||||
@ -38,6 +38,9 @@ import {
|
|||||||
ReserveRecord,
|
ReserveRecord,
|
||||||
WireFee,
|
WireFee,
|
||||||
} from "../types";
|
} from "../types";
|
||||||
|
import {
|
||||||
|
canonicalJson,
|
||||||
|
} from "../helpers";
|
||||||
import {
|
import {
|
||||||
CoinWithDenom,
|
CoinWithDenom,
|
||||||
} from "../wallet";
|
} from "../wallet";
|
||||||
@ -227,16 +230,17 @@ namespace RpcFunctions {
|
|||||||
* Generate updated coins (to store in the database)
|
* Generate updated coins (to store in the database)
|
||||||
* and deposit permissions for each given coin.
|
* and deposit permissions for each given coin.
|
||||||
*/
|
*/
|
||||||
export function signDeposit(proposal: ProposalRecord,
|
export function signDeposit(contractTerms: ContractTerms,
|
||||||
cds: CoinWithDenom[]): PayCoinInfo {
|
cds: CoinWithDenom[]): PayCoinInfo {
|
||||||
const ret: PayCoinInfo = [];
|
const ret: PayCoinInfo = [];
|
||||||
|
|
||||||
|
const contractTermsHash = hashString(canonicalJson(contractTerms));
|
||||||
|
|
||||||
const feeList: AmountJson[] = cds.map((x) => x.denom.feeDeposit);
|
const feeList: AmountJson[] = cds.map((x) => x.denom.feeDeposit);
|
||||||
let fees = Amounts.add(Amounts.getZero(feeList[0].currency), ...feeList).amount;
|
let fees = Amounts.add(Amounts.getZero(feeList[0].currency), ...feeList).amount;
|
||||||
// okay if saturates
|
// okay if saturates
|
||||||
fees = Amounts.sub(fees, proposal.contractTerms.max_fee).amount;
|
fees = Amounts.sub(fees, contractTerms.max_fee).amount;
|
||||||
const total = Amounts.add(fees, proposal.contractTerms.amount).amount;
|
const total = Amounts.add(fees, contractTerms.amount).amount;
|
||||||
|
|
||||||
const amountSpent = native.Amount.getZero(cds[0].coin.currentAmount.currency);
|
const amountSpent = native.Amount.getZero(cds[0].coin.currentAmount.currency);
|
||||||
const amountRemaining = new native.Amount(total);
|
const amountRemaining = new native.Amount(total);
|
||||||
@ -273,11 +277,11 @@ namespace RpcFunctions {
|
|||||||
amount_with_fee: coinSpend.toNbo(),
|
amount_with_fee: coinSpend.toNbo(),
|
||||||
coin_pub: native.EddsaPublicKey.fromCrock(cd.coin.coinPub),
|
coin_pub: native.EddsaPublicKey.fromCrock(cd.coin.coinPub),
|
||||||
deposit_fee: new native.Amount(cd.denom.feeDeposit).toNbo(),
|
deposit_fee: new native.Amount(cd.denom.feeDeposit).toNbo(),
|
||||||
h_contract: native.HashCode.fromCrock(proposal.contractTermsHash),
|
h_contract: native.HashCode.fromCrock(contractTermsHash),
|
||||||
h_wire: native.HashCode.fromCrock(proposal.contractTerms.H_wire),
|
h_wire: native.HashCode.fromCrock(contractTerms.H_wire),
|
||||||
merchant: native.EddsaPublicKey.fromCrock(proposal.contractTerms.merchant_pub),
|
merchant: native.EddsaPublicKey.fromCrock(contractTerms.merchant_pub),
|
||||||
refund_deadline: native.AbsoluteTimeNbo.fromTalerString(proposal.contractTerms.refund_deadline),
|
refund_deadline: native.AbsoluteTimeNbo.fromTalerString(contractTerms.refund_deadline),
|
||||||
timestamp: native.AbsoluteTimeNbo.fromTalerString(proposal.contractTerms.timestamp),
|
timestamp: native.AbsoluteTimeNbo.fromTalerString(contractTerms.timestamp),
|
||||||
});
|
});
|
||||||
|
|
||||||
const coinSig = native.eddsaSign(d.toPurpose(),
|
const coinSig = native.eddsaSign(d.toPurpose(),
|
||||||
|
@ -56,67 +56,67 @@ msgid ""
|
|||||||
"wallet."
|
"wallet."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:212
|
#: src/webex/pages/confirm-create-reserve.tsx:213
|
||||||
#, fuzzy, c-format
|
#, fuzzy, c-format
|
||||||
msgid "Withdrawal fees:"
|
msgid "Withdrawal fees:"
|
||||||
msgstr "Abheben bei %1$s"
|
msgstr "Abheben bei %1$s"
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:213
|
#: src/webex/pages/confirm-create-reserve.tsx:214
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Rounding loss:"
|
msgid "Rounding loss:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:214
|
#: src/webex/pages/confirm-create-reserve.tsx:215
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Earliest expiration (for deposit): %1$s"
|
msgid "Earliest expiration (for deposit): %1$s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:219
|
#: src/webex/pages/confirm-create-reserve.tsx:220
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "# Coins"
|
msgid "# Coins"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:220
|
#: src/webex/pages/confirm-create-reserve.tsx:221
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Value"
|
msgid "Value"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:221
|
#: src/webex/pages/confirm-create-reserve.tsx:222
|
||||||
#, fuzzy, c-format
|
#, fuzzy, c-format
|
||||||
msgid "Withdraw Fee"
|
msgid "Withdraw Fee"
|
||||||
msgstr "Abheben bei %1$s"
|
msgstr "Abheben bei %1$s"
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:222
|
#: src/webex/pages/confirm-create-reserve.tsx:223
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Refresh Fee"
|
msgid "Refresh Fee"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:223
|
#: src/webex/pages/confirm-create-reserve.tsx:224
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Deposit Fee"
|
msgid "Deposit Fee"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:276
|
#: src/webex/pages/confirm-create-reserve.tsx:278
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Select"
|
msgid "Select"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:292
|
#: src/webex/pages/confirm-create-reserve.tsx:294
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Error: URL may not be relative"
|
msgid "Error: URL may not be relative"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:360
|
#: src/webex/pages/confirm-create-reserve.tsx:362
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "The exchange is trusted by the wallet.\n"
|
msgid "The exchange is trusted by the wallet.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:366
|
#: src/webex/pages/confirm-create-reserve.tsx:368
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "The exchange is audited by a trusted auditor.\n"
|
msgid "The exchange is audited by a trusted auditor.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:372
|
#: src/webex/pages/confirm-create-reserve.tsx:374
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Warning: The exchange is neither directly trusted nor audited by a trusted "
|
"Warning: The exchange is neither directly trusted nor audited by a trusted "
|
||||||
@ -124,7 +124,7 @@ msgid ""
|
|||||||
"If you withdraw from this exchange, it will be trusted in the future.\n"
|
"If you withdraw from this exchange, it will be trusted in the future.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:381
|
#: src/webex/pages/confirm-create-reserve.tsx:383
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Using exchange provider%1$s.\n"
|
"Using exchange provider%1$s.\n"
|
||||||
@ -132,151 +132,166 @@ msgid ""
|
|||||||
" %2$s in fees.\n"
|
" %2$s in fees.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:395
|
#: src/webex/pages/confirm-create-reserve.tsx:397
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Waiting for a response from\n"
|
"Waiting for a response from\n"
|
||||||
" %1$s"
|
" %1$s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:406
|
#: src/webex/pages/confirm-create-reserve.tsx:408
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "A problem occured, see below. %1$s"
|
msgid "A problem occured, see below. %1$s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:412
|
#: src/webex/pages/confirm-create-reserve.tsx:414
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Information about fees will be available when an exchange provider is "
|
"Information about fees will be available when an exchange provider is "
|
||||||
"selected."
|
"selected."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:455
|
#: src/webex/pages/confirm-create-reserve.tsx:457
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Accept fees and withdraw"
|
msgid "Accept fees and withdraw"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:460
|
#: src/webex/pages/confirm-create-reserve.tsx:462
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Change Exchange Provider"
|
msgid "Change Exchange Provider"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:517
|
#: src/webex/pages/confirm-create-reserve.tsx:519
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "You are about to withdraw %1$s from your bank account into your wallet."
|
msgid "You are about to withdraw %1$s from your bank account into your wallet."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:600
|
#: src/webex/pages/confirm-create-reserve.tsx:607
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Oops, something went wrong. The wallet responded with error status (%1$s)."
|
"Oops, something went wrong. The wallet responded with error status (%1$s)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:611
|
#: src/webex/pages/confirm-create-reserve.tsx:616
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Checking URL, please wait ..."
|
msgid "Checking URL, please wait ..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:625
|
#: src/webex/pages/confirm-create-reserve.tsx:630
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Can't parse amount: %1$s"
|
msgid "Can't parse amount: %1$s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:632
|
#: src/webex/pages/confirm-create-reserve.tsx:637
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Can't parse wire_types: %1$s"
|
msgid "Can't parse wire_types: %1$s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. TODO:generic error reporting function or component.
|
#. TODO:generic error reporting function or component.
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:652
|
#: src/webex/pages/confirm-create-reserve.tsx:663
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Fatal error: \"%1$s\"."
|
msgid "Fatal error: \"%1$s\"."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:160
|
#: src/webex/pages/popup.tsx:161
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Balance"
|
msgid "Balance"
|
||||||
msgstr "Saldo"
|
msgstr "Saldo"
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:163
|
#: src/webex/pages/popup.tsx:164
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "History"
|
msgid "History"
|
||||||
msgstr "Verlauf"
|
msgstr "Verlauf"
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:166
|
#: src/webex/pages/popup.tsx:167
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Debug"
|
msgid "Debug"
|
||||||
msgstr "Debug"
|
msgstr "Debug"
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:242
|
#: src/webex/pages/popup.tsx:247
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "help"
|
msgid "help"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:247
|
#: src/webex/pages/popup.tsx:252
|
||||||
#, fuzzy, c-format
|
#, fuzzy, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"You have no balance to show. Need some\n"
|
"You have no balance to show. Need some\n"
|
||||||
" %1$s getting started?\n"
|
" %1$s getting started?\n"
|
||||||
msgstr "Sie haben kein Digitalgeld. Wollen Sie %1$s? abheben?"
|
msgstr "Sie haben kein Digitalgeld. Wollen Sie %1$s? abheben?"
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:264
|
#: src/webex/pages/popup.tsx:269
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%1$s incoming\n"
|
msgid "%1$s incoming\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:277
|
#: src/webex/pages/popup.tsx:282
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%1$s being spent\n"
|
msgid "%1$s being spent\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:303
|
#: src/webex/pages/popup.tsx:308
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Error: could not retrieve balance information."
|
msgid "Error: could not retrieve balance information."
|
||||||
msgstr ""
|
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
|
#, fuzzy, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Bank requested reserve (%1$s) for\n"
|
"Bank requested reserve (%1$s) for\n"
|
||||||
" %2$s.\n"
|
" %2$s.\n"
|
||||||
msgstr "Bank bestätig anlegen der Reserve (%1$s) bei %2$s"
|
msgstr "Bank bestätig anlegen der Reserve (%1$s) bei %2$s"
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:353
|
#: src/webex/pages/popup.tsx:360
|
||||||
#, fuzzy, c-format
|
#, fuzzy, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Started to withdraw\n"
|
"Started to withdraw\n"
|
||||||
" %1$s from%2$s(%3$s).\n"
|
" %1$s from%2$s(%3$s).\n"
|
||||||
msgstr "Reserve (%1$s) mit %2$s bei %3$s erzeugt"
|
msgstr "Reserve (%1$s) mit %2$s bei %3$s erzeugt"
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:363
|
#: src/webex/pages/popup.tsx:370
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Merchant%1$soffered contract%2$s;\n"
|
msgid "Merchant%1$soffered contract%2$s;\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:373
|
#: src/webex/pages/popup.tsx:380
|
||||||
#, fuzzy, c-format
|
#, fuzzy, c-format
|
||||||
msgid "Withdrew%1$sfrom%2$s(%3$s).\n"
|
msgid "Withdrew%1$sfrom%2$s(%3$s).\n"
|
||||||
msgstr "Reserve (%1$s) mit %2$s bei %3$s erzeugt"
|
msgstr "Reserve (%1$s) mit %2$s bei %3$s erzeugt"
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:383
|
#: src/webex/pages/popup.tsx:390
|
||||||
#, fuzzy, c-format
|
#, fuzzy, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Paid%1$sto merchant%2$s.\n"
|
"Paid%1$sto merchant%2$s.\n"
|
||||||
" (%3$s)\n"
|
" (%3$s)\n"
|
||||||
msgstr "Reserve (%1$s) mit %2$s bei %3$s erzeugt"
|
msgstr "Reserve (%1$s) mit %2$s bei %3$s erzeugt"
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:392
|
#: src/webex/pages/popup.tsx:399
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Unknown event (%1$s)"
|
msgid "Unknown event (%1$s)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:435
|
#: src/webex/pages/popup.tsx:442
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Error: could not retrieve event history"
|
msgid "Error: could not retrieve event history"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:469
|
#: src/webex/pages/popup.tsx:476
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Your wallet has no events recorded."
|
msgid "Your wallet has no events recorded."
|
||||||
msgstr "Ihre Geldbörse verzeichnet keine Vorkommnisse."
|
msgstr "Ihre Geldbörse verzeichnet keine Vorkommnisse."
|
||||||
|
@ -56,67 +56,67 @@ msgid ""
|
|||||||
"wallet."
|
"wallet."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:212
|
#: src/webex/pages/confirm-create-reserve.tsx:213
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Withdrawal fees:"
|
msgid "Withdrawal fees:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:213
|
#: src/webex/pages/confirm-create-reserve.tsx:214
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Rounding loss:"
|
msgid "Rounding loss:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:214
|
#: src/webex/pages/confirm-create-reserve.tsx:215
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Earliest expiration (for deposit): %1$s"
|
msgid "Earliest expiration (for deposit): %1$s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:219
|
#: src/webex/pages/confirm-create-reserve.tsx:220
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "# Coins"
|
msgid "# Coins"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:220
|
#: src/webex/pages/confirm-create-reserve.tsx:221
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Value"
|
msgid "Value"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:221
|
#: src/webex/pages/confirm-create-reserve.tsx:222
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Withdraw Fee"
|
msgid "Withdraw Fee"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:222
|
#: src/webex/pages/confirm-create-reserve.tsx:223
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Refresh Fee"
|
msgid "Refresh Fee"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:223
|
#: src/webex/pages/confirm-create-reserve.tsx:224
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Deposit Fee"
|
msgid "Deposit Fee"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:276
|
#: src/webex/pages/confirm-create-reserve.tsx:278
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Select"
|
msgid "Select"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:292
|
#: src/webex/pages/confirm-create-reserve.tsx:294
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Error: URL may not be relative"
|
msgid "Error: URL may not be relative"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:360
|
#: src/webex/pages/confirm-create-reserve.tsx:362
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "The exchange is trusted by the wallet.\n"
|
msgid "The exchange is trusted by the wallet.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:366
|
#: src/webex/pages/confirm-create-reserve.tsx:368
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "The exchange is audited by a trusted auditor.\n"
|
msgid "The exchange is audited by a trusted auditor.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:372
|
#: src/webex/pages/confirm-create-reserve.tsx:374
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Warning: The exchange is neither directly trusted nor audited by a trusted "
|
"Warning: The exchange is neither directly trusted nor audited by a trusted "
|
||||||
@ -124,7 +124,7 @@ msgid ""
|
|||||||
"If you withdraw from this exchange, it will be trusted in the future.\n"
|
"If you withdraw from this exchange, it will be trusted in the future.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:381
|
#: src/webex/pages/confirm-create-reserve.tsx:383
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Using exchange provider%1$s.\n"
|
"Using exchange provider%1$s.\n"
|
||||||
@ -132,151 +132,166 @@ msgid ""
|
|||||||
" %2$s in fees.\n"
|
" %2$s in fees.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:395
|
#: src/webex/pages/confirm-create-reserve.tsx:397
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Waiting for a response from\n"
|
"Waiting for a response from\n"
|
||||||
" %1$s"
|
" %1$s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:406
|
#: src/webex/pages/confirm-create-reserve.tsx:408
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "A problem occured, see below. %1$s"
|
msgid "A problem occured, see below. %1$s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:412
|
#: src/webex/pages/confirm-create-reserve.tsx:414
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Information about fees will be available when an exchange provider is "
|
"Information about fees will be available when an exchange provider is "
|
||||||
"selected."
|
"selected."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:455
|
#: src/webex/pages/confirm-create-reserve.tsx:457
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Accept fees and withdraw"
|
msgid "Accept fees and withdraw"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:460
|
#: src/webex/pages/confirm-create-reserve.tsx:462
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Change Exchange Provider"
|
msgid "Change Exchange Provider"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:517
|
#: src/webex/pages/confirm-create-reserve.tsx:519
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "You are about to withdraw %1$s from your bank account into your wallet."
|
msgid "You are about to withdraw %1$s from your bank account into your wallet."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:600
|
#: src/webex/pages/confirm-create-reserve.tsx:607
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Oops, something went wrong. The wallet responded with error status (%1$s)."
|
"Oops, something went wrong. The wallet responded with error status (%1$s)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:611
|
#: src/webex/pages/confirm-create-reserve.tsx:616
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Checking URL, please wait ..."
|
msgid "Checking URL, please wait ..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:625
|
#: src/webex/pages/confirm-create-reserve.tsx:630
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Can't parse amount: %1$s"
|
msgid "Can't parse amount: %1$s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:632
|
#: src/webex/pages/confirm-create-reserve.tsx:637
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Can't parse wire_types: %1$s"
|
msgid "Can't parse wire_types: %1$s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. TODO:generic error reporting function or component.
|
#. TODO:generic error reporting function or component.
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:652
|
#: src/webex/pages/confirm-create-reserve.tsx:663
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Fatal error: \"%1$s\"."
|
msgid "Fatal error: \"%1$s\"."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:160
|
#: src/webex/pages/popup.tsx:161
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Balance"
|
msgid "Balance"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:163
|
#: src/webex/pages/popup.tsx:164
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "History"
|
msgid "History"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:166
|
#: src/webex/pages/popup.tsx:167
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Debug"
|
msgid "Debug"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:242
|
#: src/webex/pages/popup.tsx:247
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "help"
|
msgid "help"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:247
|
#: src/webex/pages/popup.tsx:252
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"You have no balance to show. Need some\n"
|
"You have no balance to show. Need some\n"
|
||||||
" %1$s getting started?\n"
|
" %1$s getting started?\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:264
|
#: src/webex/pages/popup.tsx:269
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%1$s incoming\n"
|
msgid "%1$s incoming\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:277
|
#: src/webex/pages/popup.tsx:282
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%1$s being spent\n"
|
msgid "%1$s being spent\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:303
|
#: src/webex/pages/popup.tsx:308
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Error: could not retrieve balance information."
|
msgid "Error: could not retrieve balance information."
|
||||||
msgstr ""
|
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
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Bank requested reserve (%1$s) for\n"
|
"Bank requested reserve (%1$s) for\n"
|
||||||
" %2$s.\n"
|
" %2$s.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:353
|
#: src/webex/pages/popup.tsx:360
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Started to withdraw\n"
|
"Started to withdraw\n"
|
||||||
" %1$s from%2$s(%3$s).\n"
|
" %1$s from%2$s(%3$s).\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:363
|
#: src/webex/pages/popup.tsx:370
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Merchant%1$soffered contract%2$s;\n"
|
msgid "Merchant%1$soffered contract%2$s;\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:373
|
#: src/webex/pages/popup.tsx:380
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Withdrew%1$sfrom%2$s(%3$s).\n"
|
msgid "Withdrew%1$sfrom%2$s(%3$s).\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:383
|
#: src/webex/pages/popup.tsx:390
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Paid%1$sto merchant%2$s.\n"
|
"Paid%1$sto merchant%2$s.\n"
|
||||||
" (%3$s)\n"
|
" (%3$s)\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:392
|
#: src/webex/pages/popup.tsx:399
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Unknown event (%1$s)"
|
msgid "Unknown event (%1$s)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:435
|
#: src/webex/pages/popup.tsx:442
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Error: could not retrieve event history"
|
msgid "Error: could not retrieve event history"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:469
|
#: src/webex/pages/popup.tsx:476
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Your wallet has no events recorded."
|
msgid "Your wallet has no events recorded."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -56,67 +56,67 @@ msgid ""
|
|||||||
"wallet."
|
"wallet."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:212
|
#: src/webex/pages/confirm-create-reserve.tsx:213
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Withdrawal fees:"
|
msgid "Withdrawal fees:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:213
|
#: src/webex/pages/confirm-create-reserve.tsx:214
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Rounding loss:"
|
msgid "Rounding loss:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:214
|
#: src/webex/pages/confirm-create-reserve.tsx:215
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Earliest expiration (for deposit): %1$s"
|
msgid "Earliest expiration (for deposit): %1$s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:219
|
#: src/webex/pages/confirm-create-reserve.tsx:220
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "# Coins"
|
msgid "# Coins"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:220
|
#: src/webex/pages/confirm-create-reserve.tsx:221
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Value"
|
msgid "Value"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:221
|
#: src/webex/pages/confirm-create-reserve.tsx:222
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Withdraw Fee"
|
msgid "Withdraw Fee"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:222
|
#: src/webex/pages/confirm-create-reserve.tsx:223
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Refresh Fee"
|
msgid "Refresh Fee"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:223
|
#: src/webex/pages/confirm-create-reserve.tsx:224
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Deposit Fee"
|
msgid "Deposit Fee"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:276
|
#: src/webex/pages/confirm-create-reserve.tsx:278
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Select"
|
msgid "Select"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:292
|
#: src/webex/pages/confirm-create-reserve.tsx:294
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Error: URL may not be relative"
|
msgid "Error: URL may not be relative"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:360
|
#: src/webex/pages/confirm-create-reserve.tsx:362
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "The exchange is trusted by the wallet.\n"
|
msgid "The exchange is trusted by the wallet.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:366
|
#: src/webex/pages/confirm-create-reserve.tsx:368
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "The exchange is audited by a trusted auditor.\n"
|
msgid "The exchange is audited by a trusted auditor.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:372
|
#: src/webex/pages/confirm-create-reserve.tsx:374
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Warning: The exchange is neither directly trusted nor audited by a trusted "
|
"Warning: The exchange is neither directly trusted nor audited by a trusted "
|
||||||
@ -124,7 +124,7 @@ msgid ""
|
|||||||
"If you withdraw from this exchange, it will be trusted in the future.\n"
|
"If you withdraw from this exchange, it will be trusted in the future.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:381
|
#: src/webex/pages/confirm-create-reserve.tsx:383
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Using exchange provider%1$s.\n"
|
"Using exchange provider%1$s.\n"
|
||||||
@ -132,151 +132,166 @@ msgid ""
|
|||||||
" %2$s in fees.\n"
|
" %2$s in fees.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:395
|
#: src/webex/pages/confirm-create-reserve.tsx:397
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Waiting for a response from\n"
|
"Waiting for a response from\n"
|
||||||
" %1$s"
|
" %1$s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:406
|
#: src/webex/pages/confirm-create-reserve.tsx:408
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "A problem occured, see below. %1$s"
|
msgid "A problem occured, see below. %1$s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:412
|
#: src/webex/pages/confirm-create-reserve.tsx:414
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Information about fees will be available when an exchange provider is "
|
"Information about fees will be available when an exchange provider is "
|
||||||
"selected."
|
"selected."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:455
|
#: src/webex/pages/confirm-create-reserve.tsx:457
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Accept fees and withdraw"
|
msgid "Accept fees and withdraw"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:460
|
#: src/webex/pages/confirm-create-reserve.tsx:462
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Change Exchange Provider"
|
msgid "Change Exchange Provider"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:517
|
#: src/webex/pages/confirm-create-reserve.tsx:519
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "You are about to withdraw %1$s from your bank account into your wallet."
|
msgid "You are about to withdraw %1$s from your bank account into your wallet."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:600
|
#: src/webex/pages/confirm-create-reserve.tsx:607
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Oops, something went wrong. The wallet responded with error status (%1$s)."
|
"Oops, something went wrong. The wallet responded with error status (%1$s)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:611
|
#: src/webex/pages/confirm-create-reserve.tsx:616
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Checking URL, please wait ..."
|
msgid "Checking URL, please wait ..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:625
|
#: src/webex/pages/confirm-create-reserve.tsx:630
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Can't parse amount: %1$s"
|
msgid "Can't parse amount: %1$s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:632
|
#: src/webex/pages/confirm-create-reserve.tsx:637
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Can't parse wire_types: %1$s"
|
msgid "Can't parse wire_types: %1$s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. TODO:generic error reporting function or component.
|
#. TODO:generic error reporting function or component.
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:652
|
#: src/webex/pages/confirm-create-reserve.tsx:663
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Fatal error: \"%1$s\"."
|
msgid "Fatal error: \"%1$s\"."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:160
|
#: src/webex/pages/popup.tsx:161
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Balance"
|
msgid "Balance"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:163
|
#: src/webex/pages/popup.tsx:164
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "History"
|
msgid "History"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:166
|
#: src/webex/pages/popup.tsx:167
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Debug"
|
msgid "Debug"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:242
|
#: src/webex/pages/popup.tsx:247
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "help"
|
msgid "help"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:247
|
#: src/webex/pages/popup.tsx:252
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"You have no balance to show. Need some\n"
|
"You have no balance to show. Need some\n"
|
||||||
" %1$s getting started?\n"
|
" %1$s getting started?\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:264
|
#: src/webex/pages/popup.tsx:269
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%1$s incoming\n"
|
msgid "%1$s incoming\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:277
|
#: src/webex/pages/popup.tsx:282
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%1$s being spent\n"
|
msgid "%1$s being spent\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:303
|
#: src/webex/pages/popup.tsx:308
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Error: could not retrieve balance information."
|
msgid "Error: could not retrieve balance information."
|
||||||
msgstr ""
|
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
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Bank requested reserve (%1$s) for\n"
|
"Bank requested reserve (%1$s) for\n"
|
||||||
" %2$s.\n"
|
" %2$s.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:353
|
#: src/webex/pages/popup.tsx:360
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Started to withdraw\n"
|
"Started to withdraw\n"
|
||||||
" %1$s from%2$s(%3$s).\n"
|
" %1$s from%2$s(%3$s).\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:363
|
#: src/webex/pages/popup.tsx:370
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Merchant%1$soffered contract%2$s;\n"
|
msgid "Merchant%1$soffered contract%2$s;\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:373
|
#: src/webex/pages/popup.tsx:380
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Withdrew%1$sfrom%2$s(%3$s).\n"
|
msgid "Withdrew%1$sfrom%2$s(%3$s).\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:383
|
#: src/webex/pages/popup.tsx:390
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Paid%1$sto merchant%2$s.\n"
|
"Paid%1$sto merchant%2$s.\n"
|
||||||
" (%3$s)\n"
|
" (%3$s)\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:392
|
#: src/webex/pages/popup.tsx:399
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Unknown event (%1$s)"
|
msgid "Unknown event (%1$s)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:435
|
#: src/webex/pages/popup.tsx:442
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Error: could not retrieve event history"
|
msgid "Error: could not retrieve event history"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:469
|
#: src/webex/pages/popup.tsx:476
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Your wallet has no events recorded."
|
msgid "Your wallet has no events recorded."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -56,67 +56,67 @@ msgid ""
|
|||||||
"wallet."
|
"wallet."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:212
|
#: src/webex/pages/confirm-create-reserve.tsx:213
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Withdrawal fees:"
|
msgid "Withdrawal fees:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:213
|
#: src/webex/pages/confirm-create-reserve.tsx:214
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Rounding loss:"
|
msgid "Rounding loss:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:214
|
#: src/webex/pages/confirm-create-reserve.tsx:215
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Earliest expiration (for deposit): %1$s"
|
msgid "Earliest expiration (for deposit): %1$s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:219
|
#: src/webex/pages/confirm-create-reserve.tsx:220
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "# Coins"
|
msgid "# Coins"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:220
|
#: src/webex/pages/confirm-create-reserve.tsx:221
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Value"
|
msgid "Value"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:221
|
#: src/webex/pages/confirm-create-reserve.tsx:222
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Withdraw Fee"
|
msgid "Withdraw Fee"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:222
|
#: src/webex/pages/confirm-create-reserve.tsx:223
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Refresh Fee"
|
msgid "Refresh Fee"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:223
|
#: src/webex/pages/confirm-create-reserve.tsx:224
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Deposit Fee"
|
msgid "Deposit Fee"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:276
|
#: src/webex/pages/confirm-create-reserve.tsx:278
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Select"
|
msgid "Select"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:292
|
#: src/webex/pages/confirm-create-reserve.tsx:294
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Error: URL may not be relative"
|
msgid "Error: URL may not be relative"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:360
|
#: src/webex/pages/confirm-create-reserve.tsx:362
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "The exchange is trusted by the wallet.\n"
|
msgid "The exchange is trusted by the wallet.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:366
|
#: src/webex/pages/confirm-create-reserve.tsx:368
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "The exchange is audited by a trusted auditor.\n"
|
msgid "The exchange is audited by a trusted auditor.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:372
|
#: src/webex/pages/confirm-create-reserve.tsx:374
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Warning: The exchange is neither directly trusted nor audited by a trusted "
|
"Warning: The exchange is neither directly trusted nor audited by a trusted "
|
||||||
@ -124,7 +124,7 @@ msgid ""
|
|||||||
"If you withdraw from this exchange, it will be trusted in the future.\n"
|
"If you withdraw from this exchange, it will be trusted in the future.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:381
|
#: src/webex/pages/confirm-create-reserve.tsx:383
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Using exchange provider%1$s.\n"
|
"Using exchange provider%1$s.\n"
|
||||||
@ -132,151 +132,166 @@ msgid ""
|
|||||||
" %2$s in fees.\n"
|
" %2$s in fees.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:395
|
#: src/webex/pages/confirm-create-reserve.tsx:397
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Waiting for a response from\n"
|
"Waiting for a response from\n"
|
||||||
" %1$s"
|
" %1$s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:406
|
#: src/webex/pages/confirm-create-reserve.tsx:408
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "A problem occured, see below. %1$s"
|
msgid "A problem occured, see below. %1$s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:412
|
#: src/webex/pages/confirm-create-reserve.tsx:414
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Information about fees will be available when an exchange provider is "
|
"Information about fees will be available when an exchange provider is "
|
||||||
"selected."
|
"selected."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:455
|
#: src/webex/pages/confirm-create-reserve.tsx:457
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Accept fees and withdraw"
|
msgid "Accept fees and withdraw"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:460
|
#: src/webex/pages/confirm-create-reserve.tsx:462
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Change Exchange Provider"
|
msgid "Change Exchange Provider"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:517
|
#: src/webex/pages/confirm-create-reserve.tsx:519
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "You are about to withdraw %1$s from your bank account into your wallet."
|
msgid "You are about to withdraw %1$s from your bank account into your wallet."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:600
|
#: src/webex/pages/confirm-create-reserve.tsx:607
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Oops, something went wrong. The wallet responded with error status (%1$s)."
|
"Oops, something went wrong. The wallet responded with error status (%1$s)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:611
|
#: src/webex/pages/confirm-create-reserve.tsx:616
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Checking URL, please wait ..."
|
msgid "Checking URL, please wait ..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:625
|
#: src/webex/pages/confirm-create-reserve.tsx:630
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Can't parse amount: %1$s"
|
msgid "Can't parse amount: %1$s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:632
|
#: src/webex/pages/confirm-create-reserve.tsx:637
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Can't parse wire_types: %1$s"
|
msgid "Can't parse wire_types: %1$s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. TODO:generic error reporting function or component.
|
#. TODO:generic error reporting function or component.
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:652
|
#: src/webex/pages/confirm-create-reserve.tsx:663
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Fatal error: \"%1$s\"."
|
msgid "Fatal error: \"%1$s\"."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:160
|
#: src/webex/pages/popup.tsx:161
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Balance"
|
msgid "Balance"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:163
|
#: src/webex/pages/popup.tsx:164
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "History"
|
msgid "History"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:166
|
#: src/webex/pages/popup.tsx:167
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Debug"
|
msgid "Debug"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:242
|
#: src/webex/pages/popup.tsx:247
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "help"
|
msgid "help"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:247
|
#: src/webex/pages/popup.tsx:252
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"You have no balance to show. Need some\n"
|
"You have no balance to show. Need some\n"
|
||||||
" %1$s getting started?\n"
|
" %1$s getting started?\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:264
|
#: src/webex/pages/popup.tsx:269
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%1$s incoming\n"
|
msgid "%1$s incoming\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:277
|
#: src/webex/pages/popup.tsx:282
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%1$s being spent\n"
|
msgid "%1$s being spent\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:303
|
#: src/webex/pages/popup.tsx:308
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Error: could not retrieve balance information."
|
msgid "Error: could not retrieve balance information."
|
||||||
msgstr ""
|
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
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Bank requested reserve (%1$s) for\n"
|
"Bank requested reserve (%1$s) for\n"
|
||||||
" %2$s.\n"
|
" %2$s.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:353
|
#: src/webex/pages/popup.tsx:360
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Started to withdraw\n"
|
"Started to withdraw\n"
|
||||||
" %1$s from%2$s(%3$s).\n"
|
" %1$s from%2$s(%3$s).\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:363
|
#: src/webex/pages/popup.tsx:370
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Merchant%1$soffered contract%2$s;\n"
|
msgid "Merchant%1$soffered contract%2$s;\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:373
|
#: src/webex/pages/popup.tsx:380
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Withdrew%1$sfrom%2$s(%3$s).\n"
|
msgid "Withdrew%1$sfrom%2$s(%3$s).\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:383
|
#: src/webex/pages/popup.tsx:390
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Paid%1$sto merchant%2$s.\n"
|
"Paid%1$sto merchant%2$s.\n"
|
||||||
" (%3$s)\n"
|
" (%3$s)\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:392
|
#: src/webex/pages/popup.tsx:399
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Unknown event (%1$s)"
|
msgid "Unknown event (%1$s)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:435
|
#: src/webex/pages/popup.tsx:442
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Error: could not retrieve event history"
|
msgid "Error: could not retrieve event history"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:469
|
#: src/webex/pages/popup.tsx:476
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Your wallet has no events recorded."
|
msgid "Your wallet has no events recorded."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -138,6 +138,15 @@ strings['de'] = {
|
|||||||
"Error: could not retrieve balance information.": [
|
"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 requested reserve (%1$s) for\n %2$s.\n": [
|
||||||
"Bank bestätig anlegen der Reserve (%1$s) bei %2$s"
|
"Bank bestätig anlegen der Reserve (%1$s) bei %2$s"
|
||||||
],
|
],
|
||||||
@ -294,6 +303,15 @@ strings['en-US'] = {
|
|||||||
"Error: could not retrieve balance information.": [
|
"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 requested reserve (%1$s) for\n %2$s.\n": [
|
||||||
""
|
""
|
||||||
],
|
],
|
||||||
@ -450,6 +468,15 @@ strings['fr'] = {
|
|||||||
"Error: could not retrieve balance information.": [
|
"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 requested reserve (%1$s) for\n %2$s.\n": [
|
||||||
""
|
""
|
||||||
],
|
],
|
||||||
@ -606,6 +633,15 @@ strings['it'] = {
|
|||||||
"Error: could not retrieve balance information.": [
|
"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 requested reserve (%1$s) for\n %2$s.\n": [
|
||||||
""
|
""
|
||||||
],
|
],
|
||||||
|
@ -56,67 +56,67 @@ msgid ""
|
|||||||
"wallet."
|
"wallet."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:212
|
#: src/webex/pages/confirm-create-reserve.tsx:213
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Withdrawal fees:"
|
msgid "Withdrawal fees:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:213
|
#: src/webex/pages/confirm-create-reserve.tsx:214
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Rounding loss:"
|
msgid "Rounding loss:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:214
|
#: src/webex/pages/confirm-create-reserve.tsx:215
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Earliest expiration (for deposit): %1$s"
|
msgid "Earliest expiration (for deposit): %1$s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:219
|
#: src/webex/pages/confirm-create-reserve.tsx:220
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "# Coins"
|
msgid "# Coins"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:220
|
#: src/webex/pages/confirm-create-reserve.tsx:221
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Value"
|
msgid "Value"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:221
|
#: src/webex/pages/confirm-create-reserve.tsx:222
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Withdraw Fee"
|
msgid "Withdraw Fee"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:222
|
#: src/webex/pages/confirm-create-reserve.tsx:223
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Refresh Fee"
|
msgid "Refresh Fee"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:223
|
#: src/webex/pages/confirm-create-reserve.tsx:224
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Deposit Fee"
|
msgid "Deposit Fee"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:276
|
#: src/webex/pages/confirm-create-reserve.tsx:278
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Select"
|
msgid "Select"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:292
|
#: src/webex/pages/confirm-create-reserve.tsx:294
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Error: URL may not be relative"
|
msgid "Error: URL may not be relative"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:360
|
#: src/webex/pages/confirm-create-reserve.tsx:362
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "The exchange is trusted by the wallet.\n"
|
msgid "The exchange is trusted by the wallet.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:366
|
#: src/webex/pages/confirm-create-reserve.tsx:368
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "The exchange is audited by a trusted auditor.\n"
|
msgid "The exchange is audited by a trusted auditor.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:372
|
#: src/webex/pages/confirm-create-reserve.tsx:374
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Warning: The exchange is neither directly trusted nor audited by a trusted "
|
"Warning: The exchange is neither directly trusted nor audited by a trusted "
|
||||||
@ -124,7 +124,7 @@ msgid ""
|
|||||||
"If you withdraw from this exchange, it will be trusted in the future.\n"
|
"If you withdraw from this exchange, it will be trusted in the future.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:381
|
#: src/webex/pages/confirm-create-reserve.tsx:383
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Using exchange provider%1$s.\n"
|
"Using exchange provider%1$s.\n"
|
||||||
@ -132,151 +132,166 @@ msgid ""
|
|||||||
" %2$s in fees.\n"
|
" %2$s in fees.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:395
|
#: src/webex/pages/confirm-create-reserve.tsx:397
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Waiting for a response from\n"
|
"Waiting for a response from\n"
|
||||||
" %1$s"
|
" %1$s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:406
|
#: src/webex/pages/confirm-create-reserve.tsx:408
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "A problem occured, see below. %1$s"
|
msgid "A problem occured, see below. %1$s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:412
|
#: src/webex/pages/confirm-create-reserve.tsx:414
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Information about fees will be available when an exchange provider is "
|
"Information about fees will be available when an exchange provider is "
|
||||||
"selected."
|
"selected."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:455
|
#: src/webex/pages/confirm-create-reserve.tsx:457
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Accept fees and withdraw"
|
msgid "Accept fees and withdraw"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:460
|
#: src/webex/pages/confirm-create-reserve.tsx:462
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Change Exchange Provider"
|
msgid "Change Exchange Provider"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:517
|
#: src/webex/pages/confirm-create-reserve.tsx:519
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "You are about to withdraw %1$s from your bank account into your wallet."
|
msgid "You are about to withdraw %1$s from your bank account into your wallet."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:600
|
#: src/webex/pages/confirm-create-reserve.tsx:607
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Oops, something went wrong. The wallet responded with error status (%1$s)."
|
"Oops, something went wrong. The wallet responded with error status (%1$s)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:611
|
#: src/webex/pages/confirm-create-reserve.tsx:616
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Checking URL, please wait ..."
|
msgid "Checking URL, please wait ..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:625
|
#: src/webex/pages/confirm-create-reserve.tsx:630
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Can't parse amount: %1$s"
|
msgid "Can't parse amount: %1$s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:632
|
#: src/webex/pages/confirm-create-reserve.tsx:637
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Can't parse wire_types: %1$s"
|
msgid "Can't parse wire_types: %1$s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. TODO:generic error reporting function or component.
|
#. TODO:generic error reporting function or component.
|
||||||
#: src/webex/pages/confirm-create-reserve.tsx:652
|
#: src/webex/pages/confirm-create-reserve.tsx:663
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Fatal error: \"%1$s\"."
|
msgid "Fatal error: \"%1$s\"."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:160
|
#: src/webex/pages/popup.tsx:161
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Balance"
|
msgid "Balance"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:163
|
#: src/webex/pages/popup.tsx:164
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "History"
|
msgid "History"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:166
|
#: src/webex/pages/popup.tsx:167
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Debug"
|
msgid "Debug"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:242
|
#: src/webex/pages/popup.tsx:247
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "help"
|
msgid "help"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:247
|
#: src/webex/pages/popup.tsx:252
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"You have no balance to show. Need some\n"
|
"You have no balance to show. Need some\n"
|
||||||
" %1$s getting started?\n"
|
" %1$s getting started?\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:264
|
#: src/webex/pages/popup.tsx:269
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%1$s incoming\n"
|
msgid "%1$s incoming\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:277
|
#: src/webex/pages/popup.tsx:282
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%1$s being spent\n"
|
msgid "%1$s being spent\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:303
|
#: src/webex/pages/popup.tsx:308
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Error: could not retrieve balance information."
|
msgid "Error: could not retrieve balance information."
|
||||||
msgstr ""
|
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
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Bank requested reserve (%1$s) for\n"
|
"Bank requested reserve (%1$s) for\n"
|
||||||
" %2$s.\n"
|
" %2$s.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:353
|
#: src/webex/pages/popup.tsx:360
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Started to withdraw\n"
|
"Started to withdraw\n"
|
||||||
" %1$s from%2$s(%3$s).\n"
|
" %1$s from%2$s(%3$s).\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:363
|
#: src/webex/pages/popup.tsx:370
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Merchant%1$soffered contract%2$s;\n"
|
msgid "Merchant%1$soffered contract%2$s;\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:373
|
#: src/webex/pages/popup.tsx:380
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Withdrew%1$sfrom%2$s(%3$s).\n"
|
msgid "Withdrew%1$sfrom%2$s(%3$s).\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:383
|
#: src/webex/pages/popup.tsx:390
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Paid%1$sto merchant%2$s.\n"
|
"Paid%1$sto merchant%2$s.\n"
|
||||||
" (%3$s)\n"
|
" (%3$s)\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:392
|
#: src/webex/pages/popup.tsx:399
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Unknown event (%1$s)"
|
msgid "Unknown event (%1$s)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:435
|
#: src/webex/pages/popup.tsx:442
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Error: could not retrieve event history"
|
msgid "Error: could not retrieve event history"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/webex/pages/popup.tsx:469
|
#: src/webex/pages/popup.tsx:476
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Your wallet has no events recorded."
|
msgid "Your wallet has no events recorded."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
40
src/query.ts
40
src/query.ts
@ -130,7 +130,11 @@ export interface QueryStream<T> {
|
|||||||
*/
|
*/
|
||||||
first(): QueryValue<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.
|
* function.
|
||||||
*/
|
*/
|
||||||
export function openPromise<T>(): any {
|
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;
|
let reject: ((reason?: any) => void) | null = null;
|
||||||
const promise = new Promise<T>((res, rej) => {
|
const promise = new Promise<T>((res, rej) => {
|
||||||
resolve = res;
|
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,
|
abstract subscribe(f: (isDone: boolean,
|
||||||
value: any,
|
value: any,
|
||||||
tx: IDBTransaction) => void): void;
|
tx: IDBTransaction) => void): void;
|
||||||
@ -250,11 +254,6 @@ abstract class QueryStreamBase<T> implements QueryStream<T>, PromiseLike<void> {
|
|||||||
return new FirstQueryValue(this);
|
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> {
|
flatMap<S>(f: (x: T) => S[]): QueryStream<S> {
|
||||||
return new QueryStreamFlatMap<T, S>(this, f);
|
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>> {
|
keyFn: (obj: T) => I): QueryStream<JoinResult<T, S>> {
|
||||||
this.root.addStoreAccess(store.name, false);
|
this.root.addStoreAccess(store.name, false);
|
||||||
return new QueryStreamKeyJoin<T, S>(this, store.name, keyFn);
|
return new QueryStreamKeyJoin<T, S>(this, store.name, keyFn);
|
||||||
}
|
}
|
||||||
|
|
||||||
filter(f: (x: any) => boolean): QueryStream<T> {
|
filter(f: (x: any) => boolean): QueryStream<T> {
|
||||||
return new QueryStreamFilter(this, f);
|
return new QueryStreamFilter(this, f);
|
||||||
}
|
}
|
||||||
@ -318,6 +316,21 @@ abstract class QueryStreamBase<T> implements QueryStream<T>, PromiseLike<void> {
|
|||||||
.then(() => this.root.finish())
|
.then(() => this.root.finish())
|
||||||
.then(() => promise);
|
.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;
|
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.
|
* 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 work: Array<((t: IDBTransaction) => void)> = [];
|
||||||
private stores = new Set();
|
private stores = new Set();
|
||||||
private kickoffPromise: Promise<void>;
|
private kickoffPromise: Promise<void>;
|
||||||
@ -537,11 +550,6 @@ export class QueryRoot implements PromiseLike<void> {
|
|||||||
constructor(public db: IDBDatabase) {
|
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() {
|
private checkFinished() {
|
||||||
if (this.finished) {
|
if (this.finished) {
|
||||||
throw Error("Can't add work to query after it was started");
|
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.
|
* withdraw money from it.
|
||||||
*/
|
*/
|
||||||
hasPayback: boolean;
|
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
|
* CoinRecord as stored in the "coins" data store
|
||||||
* of the wallet database.
|
* of the wallet database.
|
||||||
@ -903,14 +964,19 @@ export class ExchangeHandle {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mapping from currency names to detailed balance
|
* Mapping from currency/exchange to detailed balance
|
||||||
* information for that particular currency.
|
* information.
|
||||||
*/
|
*/
|
||||||
export interface WalletBalance {
|
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})
|
@Checkable.Class({validate: true})
|
||||||
export class ContractTerms {
|
export class ContractTerms {
|
||||||
validate() {
|
static validate(x: ContractTerms) {
|
||||||
if (this.exchanges.length === 0) {
|
if (x.exchanges.length === 0) {
|
||||||
throw Error("no exchanges in contract terms");
|
throw Error("no exchanges in contract terms");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1361,6 +1427,18 @@ export namespace Amounts {
|
|||||||
value: Number.parseInt(res[2]),
|
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;
|
order_id: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exchange that the coins are from.
|
* Exchange that the coins are from (base URL).
|
||||||
*/
|
*/
|
||||||
exchange: string;
|
exchange: string;
|
||||||
}
|
}
|
||||||
@ -1484,3 +1562,103 @@ export interface QueryPaymentFound {
|
|||||||
contractTerms: ContractTerms;
|
contractTerms: ContractTerms;
|
||||||
payReq: PayReq;
|
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,
|
Amounts,
|
||||||
Auditor,
|
Auditor,
|
||||||
CheckPayResult,
|
CheckPayResult,
|
||||||
|
CoinPaySig,
|
||||||
CoinRecord,
|
CoinRecord,
|
||||||
CoinStatus,
|
CoinStatus,
|
||||||
ConfirmPayResult,
|
ConfirmPayResult,
|
||||||
|
ConfirmReserveRequest,
|
||||||
ContractTerms,
|
ContractTerms,
|
||||||
|
CreateReserveRequest,
|
||||||
CreateReserveResponse,
|
CreateReserveResponse,
|
||||||
CurrencyRecord,
|
CurrencyRecord,
|
||||||
Denomination,
|
Denomination,
|
||||||
@ -73,6 +76,8 @@ import {
|
|||||||
RefreshSessionRecord,
|
RefreshSessionRecord,
|
||||||
ReserveCreationInfo,
|
ReserveCreationInfo,
|
||||||
ReserveRecord,
|
ReserveRecord,
|
||||||
|
ReturnCoinsRequest,
|
||||||
|
SenderWireInfos,
|
||||||
WalletBalance,
|
WalletBalance,
|
||||||
WalletBalanceEntry,
|
WalletBalanceEntry,
|
||||||
WireFee,
|
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 {
|
interface TransactionRecord {
|
||||||
contractTermsHash: string;
|
contractTermsHash: string;
|
||||||
contractTerms: ContractTerms;
|
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
|
* Wallet protocol version spoken with the exchange
|
||||||
* and merchant.
|
* and merchant.
|
||||||
@ -343,7 +345,7 @@ export const WALLET_PROTOCOL_VERSION = "0:0:0";
|
|||||||
* In the future we might consider adding migration functions for
|
* In the future we might consider adding migration functions for
|
||||||
* each version increment.
|
* each version increment.
|
||||||
*/
|
*/
|
||||||
export const WALLET_DB_VERSION = 18;
|
export const WALLET_DB_VERSION = 19;
|
||||||
|
|
||||||
const builtinCurrencies: CurrencyRecord[] = [
|
const builtinCurrencies: CurrencyRecord[] = [
|
||||||
{
|
{
|
||||||
@ -421,6 +423,7 @@ export function selectPayCoins(cds: CoinWithDenom[], paymentAmount: AmountJson,
|
|||||||
Amounts.add(paymentAmount,
|
Amounts.add(paymentAmount,
|
||||||
denom.feeDeposit).amount) >= 0;
|
denom.feeDeposit).amount) >= 0;
|
||||||
isBelowFee = Amounts.cmp(accFee, depositFeeLimit) <= 0;
|
isBelowFee = Amounts.cmp(accFee, depositFeeLimit) <= 0;
|
||||||
|
|
||||||
if ((coversAmount && isBelowFee) || coversAmountWithFee) {
|
if ((coversAmount && isBelowFee) || coversAmountWithFee) {
|
||||||
return cdsResult;
|
return cdsResult;
|
||||||
}
|
}
|
||||||
@ -553,6 +556,7 @@ export namespace Stores {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const coins = new CoinsStore();
|
export const coins = new CoinsStore();
|
||||||
|
export const coinsReturns = new Store<CoinsReturnRecord>("coinsReturns", {keyPath: "contractTermsHash"});
|
||||||
export const config = new ConfigStore();
|
export const config = new ConfigStore();
|
||||||
export const currencies = new CurrenciesStore();
|
export const currencies = new CurrenciesStore();
|
||||||
export const denominations = new DenominationsStore();
|
export const denominations = new DenominationsStore();
|
||||||
@ -700,6 +704,12 @@ export class Wallet {
|
|||||||
this.continueRefreshSession(r);
|
this.continueRefreshSession(r);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.q()
|
||||||
|
.iter(Stores.coinsReturns)
|
||||||
|
.reduce((r: CoinsReturnRecord) => {
|
||||||
|
this.depositReturnedCoins(r);
|
||||||
|
});
|
||||||
|
|
||||||
// FIXME: optimize via index
|
// FIXME: optimize via index
|
||||||
this.q()
|
this.q()
|
||||||
.iter(Stores.coins)
|
.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,
|
* Get exchanges and associated coins that are still spendable,
|
||||||
* but only if the sum the coins' remaining value exceeds the payment amount.
|
* 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) {
|
if (!coins || coins.length === 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Denomination of the first coin, we assume that all other
|
// Denomination of the first coin, we assume that all other
|
||||||
// coins have the same currency
|
// coins have the same currency
|
||||||
const firstDenom = await this.q().get(Stores.denominations,
|
const firstDenom = await this.q().get(Stores.denominations,
|
||||||
@ -903,7 +966,7 @@ export class Wallet {
|
|||||||
*/
|
*/
|
||||||
async confirmPay(proposalId: number): Promise<ConfirmPayResult> {
|
async confirmPay(proposalId: number): Promise<ConfirmPayResult> {
|
||||||
console.log("executing confirmPay");
|
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) {
|
if (!proposal) {
|
||||||
throw Error(`proposal with id ${proposalId} not found`);
|
throw Error(`proposal with id ${proposalId} not found`);
|
||||||
@ -936,7 +999,7 @@ export class Wallet {
|
|||||||
}
|
}
|
||||||
const {exchangeUrl, cds} = res;
|
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);
|
await this.recordConfirmPay(proposal, ds, exchangeUrl);
|
||||||
return "paid";
|
return "paid";
|
||||||
}
|
}
|
||||||
@ -1138,6 +1201,7 @@ export class Wallet {
|
|||||||
requested_amount: req.amount,
|
requested_amount: req.amount,
|
||||||
reserve_priv: keypair.priv,
|
reserve_priv: keypair.priv,
|
||||||
reserve_pub: keypair.pub,
|
reserve_pub: keypair.pub,
|
||||||
|
senderWire: req.senderWire,
|
||||||
};
|
};
|
||||||
|
|
||||||
const historyEntry = {
|
const historyEntry = {
|
||||||
@ -1755,22 +1819,26 @@ export class Wallet {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve a mapping from currency name to the amount
|
* Get detailed balance information, sliced by exchange and by currency.
|
||||||
* that is currenctly available for spending in the wallet.
|
|
||||||
*/
|
*/
|
||||||
async getBalances(): Promise<WalletBalance> {
|
async getBalances(): Promise<WalletBalance> {
|
||||||
function ensureEntry(balance: WalletBalance, currency: string) {
|
/**
|
||||||
let entry: WalletBalanceEntry|undefined = balance[currency];
|
* Add amount to a balance field, both for
|
||||||
const z = Amounts.getZero(currency);
|
* the slicing by exchange and currency.
|
||||||
if (!entry) {
|
*/
|
||||||
balance[currency] = entry = {
|
function addTo(balance: WalletBalance, field: keyof WalletBalanceEntry, amount: AmountJson, exchange: string): void {
|
||||||
available: z,
|
const z = Amounts.getZero(amount.currency);
|
||||||
paybackAmount: z,
|
const balanceIdentity = {available: z, paybackAmount: z, pendingIncoming: z, pendingPayment: z};
|
||||||
pendingIncoming: z,
|
let entryCurr = balance.byCurrency[amount.currency];
|
||||||
pendingPayment: z,
|
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) {
|
function collectBalances(c: CoinRecord, balance: WalletBalance) {
|
||||||
@ -1780,9 +1848,8 @@ export class Wallet {
|
|||||||
if (!(c.status === CoinStatus.Dirty || c.status === CoinStatus.Fresh)) {
|
if (!(c.status === CoinStatus.Dirty || c.status === CoinStatus.Fresh)) {
|
||||||
return balance;
|
return balance;
|
||||||
}
|
}
|
||||||
const currency = c.currentAmount.currency;
|
console.log("collecting balance");
|
||||||
const entry = ensureEntry(balance, currency);
|
addTo(balance, "available", c.currentAmount, c.exchangeBaseUrl);
|
||||||
entry.available = Amounts.add(entry.available, c.currentAmount).amount;
|
|
||||||
return balance;
|
return balance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1790,15 +1857,13 @@ export class Wallet {
|
|||||||
if (!r.confirmed) {
|
if (!r.confirmed) {
|
||||||
return balance;
|
return balance;
|
||||||
}
|
}
|
||||||
const entry = ensureEntry(balance, r.requested_amount.currency);
|
|
||||||
let amount = r.current_amount;
|
let amount = r.current_amount;
|
||||||
if (!amount) {
|
if (!amount) {
|
||||||
amount = r.requested_amount;
|
amount = r.requested_amount;
|
||||||
}
|
}
|
||||||
amount = Amounts.add(amount, r.precoin_amount).amount;
|
amount = Amounts.add(amount, r.precoin_amount).amount;
|
||||||
if (Amounts.cmp(smallestWithdraw[r.exchange_base_url], amount) < 0) {
|
if (Amounts.cmp(smallestWithdraw[r.exchange_base_url], amount) < 0) {
|
||||||
entry.pendingIncoming = Amounts.add(entry.pendingIncoming,
|
addTo(balance, "pendingIncoming", amount, r.exchange_base_url);
|
||||||
amount).amount;
|
|
||||||
}
|
}
|
||||||
return balance;
|
return balance;
|
||||||
}
|
}
|
||||||
@ -1807,9 +1872,8 @@ export class Wallet {
|
|||||||
if (!r.hasPayback) {
|
if (!r.hasPayback) {
|
||||||
return balance;
|
return balance;
|
||||||
}
|
}
|
||||||
const entry = ensureEntry(balance, r.requested_amount.currency);
|
|
||||||
if (Amounts.cmp(smallestWithdraw[r.exchange_base_url], r.current_amount!) < 0) {
|
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;
|
return balance;
|
||||||
}
|
}
|
||||||
@ -1821,9 +1885,7 @@ export class Wallet {
|
|||||||
if (r.finished) {
|
if (r.finished) {
|
||||||
return balance;
|
return balance;
|
||||||
}
|
}
|
||||||
const entry = ensureEntry(balance, r.valueWithFee.currency);
|
addTo(balance, "pendingIncoming", r.valueOutput, r.exchangeBaseUrl);
|
||||||
entry.pendingIncoming = Amounts.add(entry.pendingIncoming,
|
|
||||||
r.valueOutput).amount;
|
|
||||||
|
|
||||||
return balance;
|
return balance;
|
||||||
}
|
}
|
||||||
@ -1832,10 +1894,7 @@ export class Wallet {
|
|||||||
if (t.finished) {
|
if (t.finished) {
|
||||||
return balance;
|
return balance;
|
||||||
}
|
}
|
||||||
const entry = ensureEntry(balance, t.contractTerms.amount.currency);
|
addTo(balance, "pendingIncoming", t.contractTerms.amount, t.payReq.exchange);
|
||||||
entry.pendingPayment = Amounts.add(entry.pendingPayment,
|
|
||||||
t.contractTerms.amount).amount;
|
|
||||||
|
|
||||||
return balance;
|
return balance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1852,7 +1911,10 @@ export class Wallet {
|
|||||||
return sw;
|
return sw;
|
||||||
}
|
}
|
||||||
|
|
||||||
const balance = {};
|
const balance = {
|
||||||
|
byExchange: {},
|
||||||
|
byCurrency: {},
|
||||||
|
};
|
||||||
// Mapping from exchange pub to smallest
|
// Mapping from exchange pub to smallest
|
||||||
// possible amount we can withdraw
|
// possible amount we can withdraw
|
||||||
let smallestWithdraw: {[baseUrl: string]: AmountJson} = {};
|
let smallestWithdraw: {[baseUrl: string]: AmountJson} = {};
|
||||||
@ -1876,7 +1938,6 @@ export class Wallet {
|
|||||||
.reduce(collectPayments, balance);
|
.reduce(collectPayments, balance);
|
||||||
await tx.finish();
|
await tx.finish();
|
||||||
return balance;
|
return balance;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2347,4 +2408,156 @@ export class Wallet {
|
|||||||
stop() {
|
stop() {
|
||||||
this.timerGroup.stopCurrentAndFutureTimers();
|
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: { };
|
request: { };
|
||||||
response: void;
|
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>
|
<title>Taler Wallet: Select Taler Provider</title>
|
||||||
|
|
||||||
<link rel="icon" href="/img/icon.png">
|
<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/pure.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../style/wallet.css">
|
||||||
|
|
||||||
<script src="/dist/page-common-bundle.js"></script>
|
<script src="/dist/page-common-bundle.js"></script>
|
||||||
<script src="/dist/confirm-create-reserve-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>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
@ -219,22 +219,26 @@ class WalletBalanceView extends React.Component<any, any> {
|
|||||||
this.unmount = true;
|
this.unmount = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateBalance() {
|
async updateBalance() {
|
||||||
chrome.runtime.sendMessage({type: "balances"}, (resp) => {
|
let balance: WalletBalance;
|
||||||
|
try {
|
||||||
|
balance = await wxApi.getBalance();
|
||||||
|
} catch (e) {
|
||||||
if (this.unmount) {
|
if (this.unmount) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (resp.error) {
|
this.gotError = true;
|
||||||
this.gotError = true;
|
console.error("could not retrieve balances", e);
|
||||||
console.error("could not retrieve balances", resp);
|
|
||||||
this.setState({});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.gotError = false;
|
|
||||||
console.log("got wallet", resp);
|
|
||||||
this.balance = resp;
|
|
||||||
this.setState({});
|
this.setState({});
|
||||||
});
|
return;
|
||||||
|
}
|
||||||
|
if (this.unmount) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.gotError = false;
|
||||||
|
console.log("got balance", balance);
|
||||||
|
this.balance = balance;
|
||||||
|
this.setState({});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderEmpty(): JSX.Element {
|
renderEmpty(): JSX.Element {
|
||||||
@ -308,8 +312,8 @@ class WalletBalanceView extends React.Component<any, any> {
|
|||||||
}
|
}
|
||||||
console.log(wallet);
|
console.log(wallet);
|
||||||
let paybackAvailable = false;
|
let paybackAvailable = false;
|
||||||
const listing = Object.keys(wallet).map((key) => {
|
const listing = Object.keys(wallet.byCurrency).map((key) => {
|
||||||
const entry: WalletBalanceEntry = wallet[key];
|
const entry: WalletBalanceEntry = wallet.byCurrency[key];
|
||||||
if (entry.paybackAmount.value !== 0 || entry.paybackAmount.fraction !== 0) {
|
if (entry.paybackAmount.value !== 0 || entry.paybackAmount.fraction !== 0) {
|
||||||
paybackAvailable = true;
|
paybackAvailable = true;
|
||||||
}
|
}
|
||||||
@ -321,14 +325,16 @@ class WalletBalanceView extends React.Component<any, any> {
|
|||||||
</p>
|
</p>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
const link = chrome.extension.getURL("/src/webex/pages/auditors.html");
|
const makeLink = (page: string, name: string) => {
|
||||||
const linkElem = <a className="actionLink" href={link} target="_blank">Trusted Auditors and Exchanges</a>;
|
const url = chrome.extension.getURL(`/src/webex/pages/${page}`);
|
||||||
const paybackLinkElem = <a className="actionLink" href={link} target="_blank">Trusted Auditors and Exchanges</a>;
|
return <div><a className="actionLink" href={url} target="_blank">{name}</a></div>;
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{listing.length > 0 ? listing : this.renderEmpty()}
|
{listing.length > 0 ? listing : this.renderEmpty()}
|
||||||
{paybackAvailable && paybackLinkElem}
|
{paybackAvailable && makeLink("payback", i18n.str`Payback`)}
|
||||||
{linkElem}
|
{makeLink("return-coins.html#dissolve", i18n.str`Return Electronic Cash to Bank Account`)}
|
||||||
|
{makeLink("auditors.html", i18n.str`Manage Trusted Auditors and Exchanges`)}
|
||||||
</div>
|
</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 {
|
#main {
|
||||||
border: solid 1px black;
|
border: solid 1px black;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
@ -235,3 +240,14 @@ a.actionLink {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
background: #00FA9A;
|
background: #00FA9A;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
a.opener {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
.opener-open::before {
|
||||||
|
content: "\25bc"
|
||||||
|
}
|
||||||
|
.opener-collapsed::before {
|
||||||
|
content: "\25b6 "
|
||||||
|
}
|
||||||
|
@ -31,9 +31,11 @@ import {
|
|||||||
DenominationRecord,
|
DenominationRecord,
|
||||||
ExchangeRecord,
|
ExchangeRecord,
|
||||||
PreCoinRecord,
|
PreCoinRecord,
|
||||||
|
QueryPaymentResult,
|
||||||
ReserveCreationInfo,
|
ReserveCreationInfo,
|
||||||
ReserveRecord,
|
ReserveRecord,
|
||||||
QueryPaymentResult,
|
SenderWireInfos,
|
||||||
|
WalletBalance,
|
||||||
} from "../types";
|
} from "../types";
|
||||||
|
|
||||||
import { MessageType, MessageMap } from "./messages";
|
import { MessageType, MessageMap } from "./messages";
|
||||||
@ -296,3 +298,26 @@ export function createReserve(args: { amount: AmountJson, exchange: string, send
|
|||||||
export function resetDb(): Promise<void> {
|
export function resetDb(): Promise<void> {
|
||||||
return callBackend("reset-db", { });
|
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";
|
} from "../query";
|
||||||
import {
|
import {
|
||||||
AmountJson,
|
AmountJson,
|
||||||
Notifier,
|
|
||||||
ProposalRecord,
|
|
||||||
} from "../types";
|
|
||||||
import {
|
|
||||||
ConfirmReserveRequest,
|
ConfirmReserveRequest,
|
||||||
CreateReserveRequest,
|
CreateReserveRequest,
|
||||||
|
Notifier,
|
||||||
|
ProposalRecord,
|
||||||
|
ReturnCoinsRequest,
|
||||||
|
} from "../types";
|
||||||
|
import {
|
||||||
Stores,
|
Stores,
|
||||||
WALLET_DB_VERSION,
|
WALLET_DB_VERSION,
|
||||||
Wallet,
|
Wallet,
|
||||||
@ -278,6 +279,18 @@ function handleMessage(sender: MessageSender,
|
|||||||
}
|
}
|
||||||
return needsWallet().paymentSucceeded(contractTermsHash, merchantSig);
|
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": {
|
case "check-upgrade": {
|
||||||
let dbResetRequired = false;
|
let dbResetRequired = false;
|
||||||
if (!currentWallet) {
|
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/payback.tsx",
|
||||||
"src/webex/pages/popup.tsx",
|
"src/webex/pages/popup.tsx",
|
||||||
"src/webex/pages/reset-required.tsx",
|
"src/webex/pages/reset-required.tsx",
|
||||||
|
"src/webex/pages/return-coins.tsx",
|
||||||
"src/webex/pages/show-db.ts",
|
"src/webex/pages/show-db.ts",
|
||||||
"src/webex/pages/tree.tsx",
|
"src/webex/pages/tree.tsx",
|
||||||
"src/webex/renderHtml.tsx",
|
"src/webex/renderHtml.tsx",
|
||||||
|
@ -69,11 +69,12 @@ module.exports = function (env) {
|
|||||||
"confirm-create-reserve": "./src/webex/pages/confirm-create-reserve.tsx",
|
"confirm-create-reserve": "./src/webex/pages/confirm-create-reserve.tsx",
|
||||||
"error": "./src/webex/pages/error.tsx",
|
"error": "./src/webex/pages/error.tsx",
|
||||||
"logs": "./src/webex/pages/logs.tsx",
|
"logs": "./src/webex/pages/logs.tsx",
|
||||||
|
"payback": "./src/webex/pages/payback.tsx",
|
||||||
"popup": "./src/webex/pages/popup.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",
|
"show-db": "./src/webex/pages/show-db.ts",
|
||||||
"tree": "./src/webex/pages/tree.tsx",
|
"tree": "./src/webex/pages/tree.tsx",
|
||||||
"payback": "./src/webex/pages/payback.tsx",
|
|
||||||
"reset-required": "./src/webex/pages/reset-required.tsx",
|
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.optimize.CommonsChunkPlugin({
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
|
Loading…
Reference in New Issue
Block a user