[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] [taler-wallet-webex] branch master updated: Revert "add con
From: |
gnunet |
Subject: |
[GNUnet-SVN] [taler-wallet-webex] branch master updated: Revert "add config for code formatter (prettier)" |
Date: |
Wed, 26 Jun 2019 15:23:19 +0200 |
This is an automated email from the git hooks/post-receive script.
dold pushed a commit to branch master
in repository wallet-webex.
The following commit(s) were added to refs/heads/master by this push:
new 87f4a14b Revert "add config for code formatter (prettier)"
87f4a14b is described below
commit 87f4a14b42be20ba30bcc68e79f5fa7d42e8f55f
Author: Florian Dold <address@hidden>
AuthorDate: Wed Jun 26 15:23:06 2019 +0200
Revert "add config for code formatter (prettier)"
This reverts commit 0e1836aefffce4e636d2b5f1bfacf7c47c5843d1.
---
.prettierrc | 6 -
packages/idb-bridge/src/MemoryBackend.ts | 2 +
src/crypto/cryptoApi.ts | 147 ++-
src/crypto/cryptoWorker.ts | 299 +++----
src/crypto/emscInterface.ts | 32 +-
src/wallet.ts | 1436 +++++++++++-------------------
6 files changed, 698 insertions(+), 1224 deletions(-)
diff --git a/.prettierrc b/.prettierrc
deleted file mode 100644
index 50063da9..00000000
--- a/.prettierrc
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "trailingComma": "all",
- "tabWidth": 2,
- "semi": true,
- "singleQuote": false
-}
\ No newline at end of file
diff --git a/packages/idb-bridge/src/MemoryBackend.ts
b/packages/idb-bridge/src/MemoryBackend.ts
index 1a85a739..bd9b8996 100644
--- a/packages/idb-bridge/src/MemoryBackend.ts
+++ b/packages/idb-bridge/src/MemoryBackend.ts
@@ -881,6 +881,8 @@ export class MemoryBackend implements Backend {
// if requested.
if (req.resultLevel === ResultLevel.Full) {
for (let i = 0; i < numResults; i++) {
+ console.log("getting value for index", i);
+ console.log("with key", primaryKeys[i]);
const result = storeData.get(primaryKeys[i]);
if (!result) {
throw Error("invariant violated");
diff --git a/src/crypto/cryptoApi.ts b/src/crypto/cryptoApi.ts
index 43a3bc22..03c2a675 100644
--- a/src/crypto/cryptoApi.ts
+++ b/src/crypto/cryptoApi.ts
@@ -14,6 +14,7 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
+
/**
* API to access the Taler crypto worker thread.
* @author Florian Dold
@@ -34,14 +35,22 @@ import {
WireFee,
} from "../dbTypes";
-import { ContractTerms, PaybackRequest } from "../talerTypes";
+import {
+ ContractTerms,
+ PaybackRequest,
+} from "../talerTypes";
-import { BenchmarkResult, CoinWithDenom, PayCoinInfo } from "../walletTypes";
+import {
+ BenchmarkResult,
+ CoinWithDenom,
+ PayCoinInfo,
+} from "../walletTypes";
import * as timer from "../timer";
import { startWorker } from "./startWorker";
+
/**
* State of a crypto worker.
*/
@@ -49,17 +58,17 @@ interface WorkerState {
/**
* The actual worker thread.
*/
- w: Worker | null;
+ w: Worker|null;
/**
* Work we're currently executing or null if not busy.
*/
- currentWorkItem: WorkItem | null;
+ currentWorkItem: WorkItem|null;
/**
* Timer to terminate the worker if it's not busy enough.
*/
- terminationTimerHandle: timer.TimerHandle | null;
+ terminationTimerHandle: timer.TimerHandle|null;
}
interface WorkItem {
@@ -79,6 +88,7 @@ interface WorkItem {
startTime: number;
}
+
/**
* Number of different priorities. Each priority p
* must be 0 <= p < NUM_PRIO.
@@ -141,10 +151,8 @@ export class CryptoApi {
handleWorkerError(ws: WorkerState, e: ErrorEvent) {
if (ws.currentWorkItem) {
- console.error(
- `error in worker during ${ws.currentWorkItem!.operation}`,
- e,
- );
+ console.error(`error in worker during ${ws.currentWorkItem!.operation}`,
+ e);
} else {
console.error("error in worker", e);
}
@@ -193,10 +201,7 @@ export class CryptoApi {
console.error(`RPC with id ${id} has no registry entry`);
return;
}
- console.log(
- `rpc ${currentWorkItem.operation} took ${timer.performanceNow() -
- currentWorkItem.startTime}ms`,
- );
+ console.log(`rpc ${currentWorkItem.operation} took
${timer.performanceNow() - currentWorkItem.startTime}ms`);
currentWorkItem.resolve(msg.data.result);
}
@@ -225,21 +230,12 @@ export class CryptoApi {
}
}
- private doRpc<T>(
- operation: string,
- priority: number,
- ...args: any[]
- ): Promise<T> {
+ private doRpc<T>(operation: string, priority: number,
+ ...args: any[]): Promise<T> {
+
const p: Promise<T> = new Promise<T>((resolve, reject) => {
const rpcId = this.nextRpcId++;
- const workItem: WorkItem = {
- operation,
- args,
- resolve,
- reject,
- rpcId,
- startTime: 0,
- };
+ const workItem: WorkItem = {operation, args, resolve, reject, rpcId,
startTime: 0};
if (this.numBusy === this.workers.length) {
const q = this.workQueues[priority];
@@ -267,10 +263,8 @@ export class CryptoApi {
});
}
- createPreCoin(
- denom: DenominationRecord,
- reserve: ReserveRecord,
- ): Promise<PreCoinRecord> {
+
+ createPreCoin(denom: DenominationRecord, reserve: ReserveRecord):
Promise<PreCoinRecord> {
return this.doRpc<PreCoinRecord>("createPreCoin", 1, denom, reserve);
}
@@ -286,48 +280,27 @@ export class CryptoApi {
return this.doRpc<string>("hashDenomPub", 1, denomPub);
}
- isValidDenom(denom: DenominationRecord, masterPub: string): Promise<boolean>
{
+ isValidDenom(denom: DenominationRecord,
+ masterPub: string): Promise<boolean> {
return this.doRpc<boolean>("isValidDenom", 2, denom, masterPub);
}
- isValidWireFee(
- type: string,
- wf: WireFee,
- masterPub: string,
- ): Promise<boolean> {
+ isValidWireFee(type: string, wf: WireFee, masterPub: string):
Promise<boolean> {
return this.doRpc<boolean>("isValidWireFee", 2, type, wf, masterPub);
}
- isValidPaymentSignature(
- sig: string,
- contractHash: string,
- merchantPub: string,
- ): Promise<boolean> {
- return this.doRpc<boolean>(
- "isValidPaymentSignature",
- 1,
- sig,
- contractHash,
- merchantPub,
- );
+ isValidPaymentSignature(sig: string, contractHash: string, merchantPub:
string): Promise<boolean> {
+ return this.doRpc<boolean>("isValidPaymentSignature", 1, sig,
contractHash, merchantPub);
}
- signDeposit(
- contractTerms: ContractTerms,
- cds: CoinWithDenom[],
- totalAmount: AmountJson,
- ): Promise<PayCoinInfo> {
- return this.doRpc<PayCoinInfo>(
- "signDeposit",
- 3,
- contractTerms,
- cds,
- totalAmount,
- );
+ signDeposit(contractTerms: ContractTerms,
+ cds: CoinWithDenom[],
+ totalAmount: AmountJson): Promise<PayCoinInfo> {
+ return this.doRpc<PayCoinInfo>("signDeposit", 3, contractTerms, cds,
totalAmount);
}
- createEddsaKeypair(): Promise<{ priv: string; pub: string }> {
- return this.doRpc<{ priv: string; pub: string }>("createEddsaKeypair", 1);
+ createEddsaKeypair(): Promise<{priv: string, pub: string}> {
+ return this.doRpc<{priv: string, pub: string}>("createEddsaKeypair", 1);
}
rsaUnblind(sig: string, bk: string, pk: string): Promise<string> {
@@ -338,43 +311,23 @@ export class CryptoApi {
return this.doRpc<PaybackRequest>("createPaybackRequest", 1, coin);
}
- createRefreshSession(
- exchangeBaseUrl: string,
- kappa: number,
- meltCoin: CoinRecord,
- newCoinDenoms: DenominationRecord[],
- meltFee: AmountJson,
- ): Promise<RefreshSessionRecord> {
- return this.doRpc<RefreshSessionRecord>(
- "createRefreshSession",
- 4,
- exchangeBaseUrl,
- kappa,
- meltCoin,
- newCoinDenoms,
- meltFee,
- );
- }
-
- signCoinLink(
- oldCoinPriv: string,
- newDenomHash: string,
- oldCoinPub: string,
- transferPub: string,
- coinEv: string,
- ): Promise<string> {
- return this.doRpc<string>(
- "signCoinLink",
- 4,
- oldCoinPriv,
- newDenomHash,
- oldCoinPub,
- transferPub,
- coinEv,
- );
+ createRefreshSession(exchangeBaseUrl: string,
+ kappa: number,
+ meltCoin: CoinRecord,
+ newCoinDenoms: DenominationRecord[],
+ meltFee: AmountJson): Promise<RefreshSessionRecord> {
+ return this.doRpc<RefreshSessionRecord>("createRefreshSession",
+ 4,
+ exchangeBaseUrl,
+ kappa,
+ meltCoin,
+ newCoinDenoms,
+ meltFee);
}
benchmark(repetitions: number): Promise<BenchmarkResult> {
- return this.doRpc<BenchmarkResult>("benchmark", 1, repetitions);
+ return this.doRpc<BenchmarkResult>("benchmark",
+ 1,
+ repetitions);
}
}
diff --git a/src/crypto/cryptoWorker.ts b/src/crypto/cryptoWorker.ts
index 9c5263a6..5013e3ac 100644
--- a/src/crypto/cryptoWorker.ts
+++ b/src/crypto/cryptoWorker.ts
@@ -18,6 +18,7 @@
* Web worker for crypto operations.
*/
+
/**
* Imports.
*/
@@ -38,9 +39,17 @@ import {
WireFee,
} from "../dbTypes";
-import { CoinPaySig, ContractTerms, PaybackRequest } from "../talerTypes";
+import {
+ CoinPaySig,
+ ContractTerms,
+ PaybackRequest,
+} from "../talerTypes";
-import { BenchmarkResult, CoinWithDenom, PayCoinInfo } from "../walletTypes";
+import {
+ BenchmarkResult,
+ CoinWithDenom,
+ PayCoinInfo,
+} from "../walletTypes";
import { canonicalJson } from "../helpers";
@@ -55,15 +64,15 @@ import {
} from "./emscInterface";
import * as native from "./emscInterface";
+
namespace RpcFunctions {
+
/**
* Create a pre-coin of the given denomination to be withdrawn from then
given
* reserve.
*/
- export function createPreCoin(
- denom: DenominationRecord,
- reserve: ReserveRecord,
- ): PreCoinRecord {
+ export function createPreCoin(denom: DenominationRecord,
+ reserve: ReserveRecord): PreCoinRecord {
const reservePriv = new native.EddsaPrivateKey();
reservePriv.loadCrock(reserve.reserve_priv);
const reservePub = new native.EddsaPublicKey();
@@ -116,6 +125,7 @@ namespace RpcFunctions {
return preCoin;
}
+
/**
* Create a planchet used for tipping, including the private keys.
*/
@@ -142,14 +152,12 @@ namespace RpcFunctions {
coinPub: coinPub.toCrock(),
coinValue: denom.value,
denomPub: denomPub.encode().toCrock(),
- denomPubHash: denomPub
- .encode()
- .hash()
- .toCrock(),
+ denomPubHash: denomPub.encode().hash().toCrock(),
};
return tipPlanchet;
}
+
/**
* Create and sign a message to request payback for a coin.
*/
@@ -157,9 +165,7 @@ namespace RpcFunctions {
const p = new native.PaybackRequestPS({
coin_blind: native.RsaBlindingKeySecret.fromCrock(coin.blindingKey),
coin_pub: native.EddsaPublicKey.fromCrock(coin.coinPub),
- h_denom_pub: native.RsaPublicKey.fromCrock(coin.denomPub)
- .encode()
- .hash(),
+ h_denom_pub:
native.RsaPublicKey.fromCrock(coin.denomPub).encode().hash(),
});
const coinPriv = native.EddsaPrivateKey.fromCrock(coin.coinPriv);
const coinSig = native.eddsaSign(p.toPurpose(), coinPriv);
@@ -173,83 +179,63 @@ namespace RpcFunctions {
return paybackRequest;
}
+
/**
* Check if a payment signature is valid.
*/
- export function isValidPaymentSignature(
- sig: string,
- contractHash: string,
- merchantPub: string,
- ): boolean {
+ export function isValidPaymentSignature(sig: string, contractHash: string,
merchantPub: string): boolean {
const p = new native.PaymentSignaturePS({
contract_hash: native.HashCode.fromCrock(contractHash),
});
const nativeSig = new native.EddsaSignature();
nativeSig.loadCrock(sig);
const nativePub = native.EddsaPublicKey.fromCrock(merchantPub);
- return native.eddsaVerify(
- native.SignaturePurpose.MERCHANT_PAYMENT_OK,
- p.toPurpose(),
- nativeSig,
- nativePub,
- );
+ return native.eddsaVerify(native.SignaturePurpose.MERCHANT_PAYMENT_OK,
+ p.toPurpose(),
+ nativeSig,
+ nativePub);
}
/**
* Check if a wire fee is correctly signed.
*/
- export function isValidWireFee(
- type: string,
- wf: WireFee,
- masterPub: string,
- ): boolean {
+ export function isValidWireFee(type: string, wf: WireFee, masterPub:
string): boolean {
const p = new native.MasterWireFeePS({
- closing_fee: new native.Amount(wf.closingFee).toNbo(),
+ closing_fee: (new native.Amount(wf.closingFee)).toNbo(),
end_date: native.AbsoluteTimeNbo.fromStampSeconds(wf.endStamp),
h_wire_method: native.ByteArray.fromStringWithNull(type).hash(),
start_date: native.AbsoluteTimeNbo.fromStampSeconds(wf.startStamp),
- wire_fee: new native.Amount(wf.wireFee).toNbo(),
+ wire_fee: (new native.Amount(wf.wireFee)).toNbo(),
});
const nativeSig = new native.EddsaSignature();
nativeSig.loadCrock(wf.sig);
const nativePub = native.EddsaPublicKey.fromCrock(masterPub);
- return native.eddsaVerify(
- native.SignaturePurpose.MASTER_WIRE_FEES,
- p.toPurpose(),
- nativeSig,
- nativePub,
- );
+ return native.eddsaVerify(native.SignaturePurpose.MASTER_WIRE_FEES,
+ p.toPurpose(),
+ nativeSig,
+ nativePub);
}
+
/**
* Check if the signature of a denomination is valid.
*/
- export function isValidDenom(
- denom: DenominationRecord,
- masterPub: string,
- ): boolean {
+ export function isValidDenom(denom: DenominationRecord,
+ masterPub: string): boolean {
const p = new native.DenominationKeyValidityPS({
- denom_hash: native.RsaPublicKey.fromCrock(denom.denomPub)
- .encode()
- .hash(),
- expire_legal: native.AbsoluteTimeNbo.fromTalerString(
- denom.stampExpireLegal,
- ),
- expire_spend: native.AbsoluteTimeNbo.fromTalerString(
- denom.stampExpireDeposit,
- ),
- expire_withdraw: native.AbsoluteTimeNbo.fromTalerString(
- denom.stampExpireWithdraw,
- ),
- fee_deposit: new native.Amount(denom.feeDeposit).toNbo(),
- fee_refresh: new native.Amount(denom.feeRefresh).toNbo(),
- fee_refund: new native.Amount(denom.feeRefund).toNbo(),
- fee_withdraw: new native.Amount(denom.feeWithdraw).toNbo(),
+ denom_hash: native.RsaPublicKey.fromCrock(denom.denomPub) .encode()
.hash(),
+ expire_legal:
native.AbsoluteTimeNbo.fromTalerString(denom.stampExpireLegal),
+ expire_spend:
native.AbsoluteTimeNbo.fromTalerString(denom.stampExpireDeposit),
+ expire_withdraw:
native.AbsoluteTimeNbo.fromTalerString(denom.stampExpireWithdraw),
+ fee_deposit: (new native.Amount(denom.feeDeposit)).toNbo(),
+ fee_refresh: (new native.Amount(denom.feeRefresh)).toNbo(),
+ fee_refund: (new native.Amount(denom.feeRefund)).toNbo(),
+ fee_withdraw: (new native.Amount(denom.feeWithdraw)).toNbo(),
master: native.EddsaPublicKey.fromCrock(masterPub),
start: native.AbsoluteTimeNbo.fromTalerString(denom.stampStart),
- value: new native.Amount(denom.value).toNbo(),
+ value: (new native.Amount(denom.value)).toNbo(),
});
const nativeSig = new native.EddsaSignature();
@@ -257,44 +243,42 @@ namespace RpcFunctions {
const nativePub = native.EddsaPublicKey.fromCrock(masterPub);
- return native.eddsaVerify(
- native.SignaturePurpose.MASTER_DENOMINATION_KEY_VALIDITY,
- p.toPurpose(),
- nativeSig,
- nativePub,
- );
+ return
native.eddsaVerify(native.SignaturePurpose.MASTER_DENOMINATION_KEY_VALIDITY,
+ p.toPurpose(),
+ nativeSig,
+ nativePub);
+
}
+
/**
* Create a new EdDSA key pair.
*/
- export function createEddsaKeypair(): { priv: string; pub: string } {
+ export function createEddsaKeypair(): {priv: string, pub: string} {
const priv = native.EddsaPrivateKey.create();
const pub = priv.getPublicKey();
- return { priv: priv.toCrock(), pub: pub.toCrock() };
+ return {priv: priv.toCrock(), pub: pub.toCrock()};
}
+
/**
* Unblind a blindly signed value.
*/
export function rsaUnblind(sig: string, bk: string, pk: string): string {
- const denomSig = native.rsaUnblind(
- native.RsaSignature.fromCrock(sig),
- native.RsaBlindingKeySecret.fromCrock(bk),
- native.RsaPublicKey.fromCrock(pk),
- );
+ const denomSig = native.rsaUnblind(native.RsaSignature.fromCrock(sig),
+ native.RsaBlindingKeySecret.fromCrock(bk),
+ native.RsaPublicKey.fromCrock(pk));
return denomSig.encode().toCrock();
}
+
/**
* Generate updated coins (to store in the database)
* and deposit permissions for each given coin.
*/
- export function signDeposit(
- contractTerms: ContractTerms,
- cds: CoinWithDenom[],
- totalAmount: AmountJson,
- ): PayCoinInfo {
+ export function signDeposit(contractTerms: ContractTerms,
+ cds: CoinWithDenom[],
+ totalAmount: AmountJson): PayCoinInfo {
const ret: PayCoinInfo = {
originalCoins: [],
sigs: [],
@@ -303,21 +287,17 @@ namespace RpcFunctions {
const contractTermsHash = hashString(canonicalJson(contractTerms));
- const feeList: AmountJson[] = cds.map(x => x.denom.feeDeposit);
- let fees = Amounts.add(Amounts.getZero(feeList[0].currency), ...feeList)
- .amount;
+ const feeList: AmountJson[] = cds.map((x) => x.denom.feeDeposit);
+ let fees = Amounts.add(Amounts.getZero(feeList[0].currency),
...feeList).amount;
// okay if saturates
- fees = Amounts.sub(fees, Amounts.parseOrThrow(contractTerms.max_fee))
- .amount;
+ fees = Amounts.sub(fees,
Amounts.parseOrThrow(contractTerms.max_fee)).amount;
const total = Amounts.add(fees, totalAmount).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);
for (const cd of cds) {
let coinSpend: Amount;
- const originalCoin = { ...cd.coin };
+ const originalCoin = { ...(cd.coin) };
if (amountRemaining.value === 0 && amountRemaining.fraction === 0) {
break;
@@ -352,20 +332,13 @@ namespace RpcFunctions {
h_contract: native.HashCode.fromCrock(contractTermsHash),
h_wire: native.HashCode.fromCrock(contractTerms.H_wire),
merchant: native.EddsaPublicKey.fromCrock(contractTerms.merchant_pub),
- refund_deadline: native.AbsoluteTimeNbo.fromTalerString(
- contractTerms.refund_deadline,
- ),
- timestamp: native.AbsoluteTimeNbo.fromTalerString(
- contractTerms.timestamp,
- ),
+ refund_deadline:
native.AbsoluteTimeNbo.fromTalerString(contractTerms.refund_deadline),
+ timestamp:
native.AbsoluteTimeNbo.fromTalerString(contractTerms.timestamp),
});
- const coinSig = native
- .eddsaSign(
- d.toPurpose(),
- native.EddsaPrivateKey.fromCrock(cd.coin.coinPriv),
- )
- .toCrock();
+ const coinSig = native.eddsaSign(d.toPurpose(),
+
native.EddsaPrivateKey.fromCrock(cd.coin.coinPriv))
+ .toCrock();
const s: CoinPaySig = {
coin_pub: cd.coin.coinPub,
@@ -382,21 +355,22 @@ namespace RpcFunctions {
return ret;
}
+
/**
* Create a new refresh session.
*/
- export function createRefreshSession(
- exchangeBaseUrl: string,
- kappa: number,
- meltCoin: CoinRecord,
- newCoinDenoms: DenominationRecord[],
- meltFee: AmountJson,
- ): RefreshSessionRecord {
+ export function createRefreshSession(exchangeBaseUrl: string,
+ kappa: number,
+ meltCoin: CoinRecord,
+ newCoinDenoms: DenominationRecord[],
+ meltFee: AmountJson):
RefreshSessionRecord {
+
let valueWithFee = Amounts.getZero(newCoinDenoms[0].value.currency);
for (const ncd of newCoinDenoms) {
- valueWithFee = Amounts.add(valueWithFee, ncd.value, ncd.feeWithdraw)
- .amount;
+ valueWithFee = Amounts.add(valueWithFee,
+ ncd.value,
+ ncd.feeWithdraw).amount;
}
// melt fee
@@ -423,11 +397,12 @@ namespace RpcFunctions {
}
sessionHc.read(native.EddsaPublicKey.fromCrock(meltCoin.coinPub));
- sessionHc.read(new native.Amount(valueWithFee).toNbo());
+ sessionHc.read((new native.Amount(valueWithFee)).toNbo());
for (let i = 0; i < kappa; i++) {
const preCoins: RefreshPreCoinRecord[] = [];
for (let j = 0; j < newCoinDenoms.length; j++) {
+
const transferPriv =
native.EcdhePrivateKey.fromCrock(transferPrivs[i]);
const oldCoinPub = native.EddsaPublicKey.fromCrock(meltCoin.coinPub);
const transferSecret = native.ecdhEddsa(transferPriv, oldCoinPub);
@@ -438,10 +413,10 @@ namespace RpcFunctions {
const coinPub = coinPriv.getPublicKey();
const blindingFactor = fresh.blindingKey;
const pubHash: native.HashCode = coinPub.hash();
- const denomPub = native.RsaPublicKey.fromCrock(
- newCoinDenoms[j].denomPub,
- );
- const ev = native.rsaBlind(pubHash, blindingFactor, denomPub);
+ const denomPub =
native.RsaPublicKey.fromCrock(newCoinDenoms[j].denomPub);
+ const ev = native.rsaBlind(pubHash,
+ blindingFactor,
+ denomPub);
if (!ev) {
throw Error("couldn't blind (malicious exchange key?)");
}
@@ -462,18 +437,16 @@ namespace RpcFunctions {
sessionHc.finish(sessionHash);
const confirmData = new RefreshMeltCoinAffirmationPS({
- amount_with_fee: new Amount(valueWithFee).toNbo(),
+ amount_with_fee: (new Amount(valueWithFee)).toNbo(),
coin_pub: EddsaPublicKey.fromCrock(meltCoin.coinPub),
- melt_fee: new Amount(meltFee).toNbo(),
+ melt_fee: (new Amount(meltFee)).toNbo(),
session_hash: sessionHash,
});
- const confirmSig: string = native
- .eddsaSign(
- confirmData.toPurpose(),
- native.EddsaPrivateKey.fromCrock(meltCoin.coinPriv),
- )
- .toCrock();
+
+ const confirmSig: string = native.eddsaSign(confirmData.toPurpose(),
+
native.EddsaPrivateKey.fromCrock(
+ meltCoin.coinPriv)).toCrock();
let valueOutput = Amounts.getZero(newCoinDenoms[0].value.currency);
for (const denom of newCoinDenoms) {
@@ -486,8 +459,8 @@ namespace RpcFunctions {
finished: false,
hash: sessionHash.toCrock(),
meltCoinPub: meltCoin.coinPub,
- newDenomHashes: newCoinDenoms.map(d => d.denomPubHash),
- newDenoms: newCoinDenoms.map(d => d.denomPub),
+ newDenomHashes: newCoinDenoms.map((d) => d.denomPubHash),
+ newDenoms: newCoinDenoms.map((d) => d.denomPub),
norevealIndex: undefined,
preCoinsForGammas,
transferPrivs,
@@ -511,33 +484,7 @@ namespace RpcFunctions {
* Hash a denomination public key.
*/
export function hashDenomPub(denomPub: string): string {
- return native.RsaPublicKey.fromCrock(denomPub)
- .encode()
- .hash()
- .toCrock();
- }
-
- export function signCoinLink(
- oldCoinPriv: string,
- newDenomHash: string,
- oldCoinPub: string,
- transferPub: string,
- coinEv: string,
- ): string {
- const coinEvHash = native.ByteArray.fromCrock(coinEv).hash();
-
- const coinLink = new native.CoinLinkSignaturePS({
- coin_envelope_hash: coinEvHash,
- h_denom_pub: native.HashCode.fromCrock(newDenomHash),
- old_coin_pub: native.EddsaPublicKey.fromCrock(oldCoinPub),
- transfer_pub: native.EcdhePublicKey.fromCrock(transferPub),
- });
-
- const coinPriv = native.EddsaPrivateKey.fromCrock(oldCoinPriv);
-
- const sig = native.eddsaSign(coinLink.toPurpose(), coinPriv);
-
- return sig.toCrock();
+ return native.RsaPublicKey.fromCrock(denomPub).encode().hash().toCrock();
}
export function benchmark(repetitions: number): BenchmarkResult {
@@ -553,7 +500,7 @@ namespace RpcFunctions {
for (let i = 0; i < repetitions; i++) {
ba.randomize(native.RandomQuality.WEAK);
const start = timer.performanceNow();
- ba.hash();
+ ba.hash();
time_hash_big += timer.performanceNow() - start;
}
@@ -561,7 +508,7 @@ namespace RpcFunctions {
for (let i = 0; i < repetitions; i++) {
const start = timer.performanceNow();
const priv: native.EddsaPrivateKey = native.EddsaPrivateKey.create();
- time_eddsa_create += timer.performanceNow() - start;
+ time_eddsa_create += timer.performanceNow() - start;
priv.destroy();
}
@@ -594,15 +541,14 @@ namespace RpcFunctions {
priv.destroy();
}
+
let time_eddsa_verify = 0;
for (let i = 0; i < repetitions; i++) {
const start = timer.performanceNow();
- native.eddsaVerify(
- native.SignaturePurpose.MERCHANT_PAYMENT_OK,
- p,
- eddsaSig,
- eddsaPub,
- );
+ native.eddsaVerify(native.SignaturePurpose.MERCHANT_PAYMENT_OK,
+ p,
+ eddsaSig,
+ eddsaPub);
time_eddsa_verify += timer.performanceNow() - start;
}
@@ -618,18 +564,11 @@ namespace RpcFunctions {
time_rsa_2048_blind += timer.performanceNow() - start;
}
- const blindedMessage2048 = native.rsaBlind(
- h,
- blindingSecret2048,
- rsaPub2048,
- );
+ const blindedMessage2048 = native.rsaBlind(h, blindingSecret2048,
rsaPub2048);
if (!blindedMessage2048) {
throw Error("should not happen");
}
- const rsaBlindSig2048 = native.rsaSignBlinded(
- rsaPriv2048,
- blindedMessage2048,
- );
+ const rsaBlindSig2048 = native.rsaSignBlinded(rsaPriv2048,
blindedMessage2048);
let time_rsa_2048_unblind = 0;
for (let i = 0; i < repetitions; i++) {
@@ -638,11 +577,7 @@ namespace RpcFunctions {
time_rsa_2048_unblind += timer.performanceNow() - start;
}
- const unblindedSig2048 = native.rsaUnblind(
- rsaBlindSig2048,
- blindingSecret2048,
- rsaPub2048,
- );
+ const unblindedSig2048 = native.rsaUnblind(rsaBlindSig2048,
blindingSecret2048, rsaPub2048);
let time_rsa_2048_verify = 0;
for (let i = 0; i < repetitions; i++) {
@@ -651,6 +586,7 @@ namespace RpcFunctions {
time_rsa_2048_verify += timer.performanceNow() - start;
}
+
/* rsa 4096 */
let time_rsa_4096_blind = 0;
@@ -663,18 +599,11 @@ namespace RpcFunctions {
time_rsa_4096_blind += timer.performanceNow() - start;
}
- const blindedMessage4096 = native.rsaBlind(
- h,
- blindingSecret4096,
- rsaPub4096,
- );
+ const blindedMessage4096 = native.rsaBlind(h, blindingSecret4096,
rsaPub4096);
if (!blindedMessage4096) {
throw Error("should not happen");
}
- const rsaBlindSig4096 = native.rsaSignBlinded(
- rsaPriv4096,
- blindedMessage4096,
- );
+ const rsaBlindSig4096 = native.rsaSignBlinded(rsaPriv4096,
blindedMessage4096);
let time_rsa_4096_unblind = 0;
for (let i = 0; i < repetitions; i++) {
@@ -683,11 +612,7 @@ namespace RpcFunctions {
time_rsa_4096_unblind += timer.performanceNow() - start;
}
- const unblindedSig4096 = native.rsaUnblind(
- rsaBlindSig4096,
- blindingSecret4096,
- rsaPub4096,
- );
+ const unblindedSig4096 = native.rsaUnblind(rsaBlindSig4096,
blindingSecret4096, rsaPub4096);
let time_rsa_4096_verify = 0;
for (let i = 0; i < repetitions; i++) {
@@ -696,6 +621,7 @@ namespace RpcFunctions {
time_rsa_4096_verify += timer.performanceNow() - start;
}
+
return {
repetitions,
time: {
@@ -711,11 +637,12 @@ namespace RpcFunctions {
rsa_4096_blind: time_rsa_4096_blind,
rsa_4096_unblind: time_rsa_4096_unblind,
rsa_4096_verify: time_rsa_4096_verify,
- },
+ }
};
}
}
+
const worker: Worker = (self as any) as Worker;
worker.onmessage = (msg: MessageEvent) => {
@@ -738,7 +665,7 @@ worker.onmessage = (msg: MessageEvent) => {
console.log("onmessage with", msg.data.operation);
console.log("foo");
- emscLoader.getLib().then(p => {
+ emscLoader.getLib().then((p) => {
const lib = p.lib;
if (!native.isInitialized()) {
console.log("initializing emscripten for then first time with lib");
diff --git a/src/crypto/emscInterface.ts b/src/crypto/emscInterface.ts
index 2ddc15a3..dcd16e63 100644
--- a/src/crypto/emscInterface.ts
+++ b/src/crypto/emscInterface.ts
@@ -223,7 +223,6 @@ export enum SignaturePurpose {
MERCHANT_PAYMENT_OK = 1104,
MASTER_WIRE_FEES = 1028,
WALLET_COIN_PAYBACK = 1203,
- WALLET_COIN_LINK = 1204,
}
@@ -971,7 +970,7 @@ abstract class SignatureStruct {
throw Error(`Key ${name} not found`);
}
if (!(value instanceof typemap[name])) {
- throw Error(`Wrong type for ${name}`);
+ throw Error("Wrong type for ${name}");
}
this.members[name] = value;
}
@@ -1294,35 +1293,6 @@ export class DepositRequestPS extends SignatureStruct {
}
}
-
-interface CoinLinkSignaturePS_args {
- h_denom_pub: HashCode;
- old_coin_pub: EddsaPublicKey;
- transfer_pub: EcdhePublicKey;
- coin_envelope_hash: HashCode;
-}
-
-
-export class CoinLinkSignaturePS extends SignatureStruct {
- constructor(w: CoinLinkSignaturePS_args) {
- super(w);
- }
-
- purpose() {
- return SignaturePurpose.WALLET_COIN_LINK;
- }
-
- fieldTypes() {
- return [
- ["h_denom_pub", HashCode],
- ["old_coin_pub", EddsaPublicKey],
- ["transfer_pub", EcdhePublicKey],
- ["coin_envelope_hash", HashCode],
- ];
- }
-}
-
-
/**
* Arguments for constuctor of [[DenominationKeyValidityPS]].
*/
diff --git a/src/wallet.ts b/src/wallet.ts
index 0dfb7755..4c7e8c18 100644
--- a/src/wallet.ts
+++ b/src/wallet.ts
@@ -30,7 +30,10 @@ import {
getTalerStampSec,
strcmp,
} from "./helpers";
-import { HttpRequestLibrary, RequestException } from "./http";
+import {
+ HttpRequestLibrary,
+ RequestException,
+} from "./http";
import * as LibtoolVersion from "./libtoolVersion";
import {
AbortTransaction,
@@ -106,6 +109,7 @@ import {
WalletBalanceEntry,
} from "./walletTypes";
+
interface SpeculativePayData {
payCoinInfo: PayCoinInfo;
exchangeUrl: string;
@@ -113,6 +117,7 @@ interface SpeculativePayData {
proposal: ProposalDownloadRecord;
}
+
/**
* Wallet protocol version spoken with the exchange
* and merchant.
@@ -127,7 +132,7 @@ const builtinCurrencies: CurrencyRecord[] = [
{
auditorPub: "BW9DC48PHQY4NH011SHHX36DZZ3Q22Y6X7FZ1VD1CMZ2PTFZ6PN0",
baseUrl: "https://auditor.demo.taler.net/",
- expirationStamp: new Date(2027, 1).getTime(),
+ expirationStamp: (new Date(2027, 1)).getTime(),
},
],
exchanges: [],
@@ -136,8 +141,9 @@ const builtinCurrencies: CurrencyRecord[] = [
},
];
+
function isWithdrawableDenom(d: DenominationRecord) {
- const nowSec = new Date().getTime() / 1000;
+ const nowSec = (new Date()).getTime() / 1000;
const stampWithdrawSec = getTalerStampSec(d.stampExpireWithdraw);
if (stampWithdrawSec === null) {
return false;
@@ -147,17 +153,19 @@ function isWithdrawableDenom(d: DenominationRecord) {
return false;
}
// Withdraw if still possible to withdraw within a minute
- if (stampWithdrawSec + 60 > nowSec && nowSec >= stampStartSec) {
+ if ((stampWithdrawSec + 60 > nowSec) && (nowSec >= stampStartSec)) {
return true;
}
return false;
}
+
interface SelectPayCoinsResult {
cds: CoinWithDenom[];
totalFees: AmountJson;
}
+
/**
* Get the amount that we lose when refreshing a coin of the given denomination
* with a certain amount left.
@@ -169,54 +177,38 @@ interface SelectPayCoinsResult {
* Considers refresh fees, withdrawal fees after refresh and amounts too small
* to refresh.
*/
-export function getTotalRefreshCost(
- denoms: DenominationRecord[],
- refreshedDenom: DenominationRecord,
- amountLeft: AmountJson,
-): AmountJson {
- const withdrawAmount = Amounts.sub(amountLeft, refreshedDenom.feeRefresh)
- .amount;
+export function getTotalRefreshCost(denoms: DenominationRecord[],
+ refreshedDenom: DenominationRecord,
+ amountLeft: AmountJson): AmountJson {
+ const withdrawAmount = Amounts.sub(amountLeft,
refreshedDenom.feeRefresh).amount;
const withdrawDenoms = getWithdrawDenomList(withdrawAmount, denoms);
- const resultingAmount = Amounts.add(
- Amounts.getZero(withdrawAmount.currency),
- ...withdrawDenoms.map(d => d.value),
- ).amount;
+ const resultingAmount = Amounts.add(Amounts.getZero(withdrawAmount.currency),
+ ...withdrawDenoms.map((d) =>
d.value)).amount;
const totalCost = Amounts.sub(amountLeft, resultingAmount).amount;
- console.log(
- "total refresh cost for",
- amountToPretty(amountLeft),
- "is",
- amountToPretty(totalCost),
- );
+ console.log("total refresh cost for", amountToPretty(amountLeft), "is",
amountToPretty(totalCost));
return totalCost;
}
+
/**
* Select coins for a payment under the merchant's constraints.
*
* @param denoms all available denoms, used to compute refresh fees
*/
-export function selectPayCoins(
- denoms: DenominationRecord[],
- cds: CoinWithDenom[],
- paymentAmount: AmountJson,
- depositFeeLimit: AmountJson,
-): SelectPayCoinsResult | undefined {
+export function selectPayCoins(denoms: DenominationRecord[], cds:
CoinWithDenom[], paymentAmount: AmountJson,
+ depositFeeLimit: AmountJson):
SelectPayCoinsResult|undefined {
if (cds.length === 0) {
return undefined;
}
// Sort by ascending deposit fee and denomPub if deposit fee is the same
// (to guarantee deterministic results)
- cds.sort(
- (o1, o2) =>
- Amounts.cmp(o1.denom.feeDeposit, o2.denom.feeDeposit) ||
- strcmp(o1.denom.denomPub, o2.denom.denomPub),
- );
+ cds.sort((o1, o2) => Amounts.cmp(o1.denom.feeDeposit, o2.denom.feeDeposit) ||
+ strcmp(o1.denom.denomPub,
o2.denom.denomPub));
const currency = cds[0].denom.value.currency;
const cdsResult: CoinWithDenom[] = [];
let accDepositFee: AmountJson = Amounts.getZero(currency);
let accAmount: AmountJson = Amounts.getZero(currency);
- for (const { coin, denom } of cds) {
+ for (const {coin, denom} of cds) {
if (coin.suspended) {
continue;
}
@@ -226,32 +218,20 @@ export function selectPayCoins(
if (Amounts.cmp(denom.feeDeposit, coin.currentAmount) >= 0) {
continue;
}
- cdsResult.push({ coin, denom });
+ cdsResult.push({coin, denom});
accDepositFee = Amounts.add(denom.feeDeposit, accDepositFee).amount;
- let leftAmount = Amounts.sub(
- coin.currentAmount,
- Amounts.sub(paymentAmount, accAmount).amount,
- ).amount;
+ let leftAmount = Amounts.sub(coin.currentAmount,
Amounts.sub(paymentAmount, accAmount).amount).amount;
accAmount = Amounts.add(coin.currentAmount, accAmount).amount;
const coversAmount = Amounts.cmp(accAmount, paymentAmount) >= 0;
- const coversAmountWithFee =
- Amounts.cmp(
- accAmount,
- Amounts.add(paymentAmount, denom.feeDeposit).amount,
- ) >= 0;
+ const coversAmountWithFee = Amounts.cmp(accAmount,
+ Amounts.add(paymentAmount,
+ denom.feeDeposit).amount) >=
0;
const isBelowFee = Amounts.cmp(accDepositFee, depositFeeLimit) <= 0;
- console.log("coin selection", {
- coversAmount,
- isBelowFee,
- accDepositFee,
- accAmount,
- paymentAmount,
- });
+ console.log("coin selection", { coversAmount, isBelowFee, accDepositFee,
accAmount, paymentAmount });
if ((coversAmount && isBelowFee) || coversAmountWithFee) {
- const depositFeeToCover = Amounts.sub(accDepositFee, depositFeeLimit)
- .amount;
+ const depositFeeToCover = Amounts.sub(accDepositFee,
depositFeeLimit).amount;
leftAmount = Amounts.sub(leftAmount, depositFeeToCover).amount;
console.log("deposit fee to cover", amountToPretty(depositFeeToCover));
@@ -261,25 +241,21 @@ export function selectPayCoins(
// because the merchant doesn't cover them
totalFees = Amounts.sub(depositFeeLimit, accDepositFee).amount;
}
- totalFees = Amounts.add(
- totalFees,
- getTotalRefreshCost(denoms, denom, leftAmount),
- ).amount;
+ totalFees = Amounts.add(totalFees, getTotalRefreshCost(denoms, denom,
leftAmount)).amount;
return { cds: cdsResult, totalFees };
}
}
return undefined;
}
+
/**
* Get a list of denominations (with repetitions possible)
* whose total value is as close as possible to the available
* amount, but never larger.
*/
-function getWithdrawDenomList(
- amountAvailable: AmountJson,
- denoms: DenominationRecord[],
-): DenominationRecord[] {
+function getWithdrawDenomList(amountAvailable: AmountJson,
+ denoms: DenominationRecord[]):
DenominationRecord[] {
let remaining = Amounts.copy(amountAvailable);
const ds: DenominationRecord[] = [];
@@ -308,6 +284,7 @@ function getWithdrawDenomList(
return ds;
}
+
interface CoinsForPaymentArgs {
allowedAuditors: Auditor[];
allowedExchanges: ExchangeHandle[];
@@ -319,6 +296,7 @@ interface CoinsForPaymentArgs {
wireMethod: string;
}
+
/**
* The platform-independent wallet implementation.
*/
@@ -332,7 +310,7 @@ export class Wallet {
private notifier: Notifier;
private cryptoApi: CryptoApi;
private processPreCoinConcurrent = 0;
- private processPreCoinThrottle: { [url: string]: number } = {};
+ private processPreCoinThrottle: {[url: string]: number} = {};
private timerGroup: TimerGroup;
private speculativePayData: SpeculativePayData | undefined;
private cachedNextUrl: { [fulfillmentUrl: string]: NextUrlResult } = {};
@@ -347,12 +325,10 @@ export class Wallet {
return new QueryRoot(this.db);
}
- constructor(
- db: IDBDatabase,
- http: HttpRequestLibrary,
- badge: Badge,
- notifier: Notifier,
- ) {
+ constructor(db: IDBDatabase,
+ http: HttpRequestLibrary,
+ badge: Badge,
+ notifier: Notifier) {
this.db = db;
this.http = http;
this.badge = badge;
@@ -361,8 +337,8 @@ export class Wallet {
this.timerGroup = new TimerGroup();
const init = async () => {
- await this.fillDefaults().catch(e => console.log(e));
- await this.collectGarbage().catch(e => console.log(e));
+ await this.fillDefaults().catch((e) => console.log(e));
+ await this.collectGarbage().catch((e) => console.log(e));
this.updateExchanges();
this.resumePendingFromDb();
this.timerGroup.every(1000 * 60 * 15, () => this.updateExchanges());
@@ -377,17 +353,20 @@ export class Wallet {
};
const onFalse = (r: QueryRoot) => {
console.log("applying defaults");
- r.put(Stores.config, { key: "currencyDefaultsApplied", value: true })
+ r.put(Stores.config, {key: "currencyDefaultsApplied", value: true})
.putAll(Stores.currencies, builtinCurrencies)
.finish();
};
- await this.q()
- .iter(Stores.config)
- .filter(x => x.key === "currencyDefaultsApplied")
- .first()
- .cond(x => x && x.value, onTrue, onFalse);
+ await (
+ this.q()
+ .iter(Stores.config)
+ .filter((x) => x.key === "currencyDefaultsApplied")
+ .first()
+ .cond((x) => x && x.value, onTrue, onFalse)
+ );
}
+
private startOperation(operationId: string) {
this.runningOperations.add(operationId);
this.badge.startBusy();
@@ -404,14 +383,15 @@ export class Wallet {
console.log("updating exchanges");
const exchangesUrls = await this.q()
- .iter(Stores.exchanges)
- .map(e => e.baseUrl)
- .toArray();
+ .iter(Stores.exchanges)
+ .map((e) => e.baseUrl)
+ .toArray();
for (const url of exchangesUrls) {
- this.updateExchangeFromUrl(url).catch(e => {
- console.error("updating exchange failed", e);
- });
+ this.updateExchangeFromUrl(url)
+ .catch((e) => {
+ console.error("updating exchange failed", e);
+ });
}
}
@@ -423,69 +403,68 @@ export class Wallet {
console.log("resuming pending operations from db");
this.q()
- .iter(Stores.reserves)
- .forEach(reserve => {
- console.log("resuming reserve", reserve.reserve_pub);
- this.processReserve(reserve);
- });
+ .iter(Stores.reserves)
+ .forEach((reserve) => {
+ console.log("resuming reserve", reserve.reserve_pub);
+ this.processReserve(reserve);
+ });
this.q()
- .iter(Stores.precoins)
- .forEach(preCoin => {
- console.log("resuming precoin");
- this.processPreCoin(preCoin);
- });
+ .iter(Stores.precoins)
+ .forEach((preCoin) => {
+ console.log("resuming precoin");
+ this.processPreCoin(preCoin);
+ });
this.q()
- .iter(Stores.refresh)
- .forEach((r: RefreshSessionRecord) => {
- this.continueRefreshSession(r);
- });
+ .iter(Stores.refresh)
+ .forEach((r: RefreshSessionRecord) => {
+ this.continueRefreshSession(r);
+ });
this.q()
- .iter(Stores.coinsReturns)
- .forEach((r: CoinsReturnRecord) => {
- this.depositReturnedCoins(r);
- });
+ .iter(Stores.coinsReturns)
+ .forEach((r: CoinsReturnRecord) => {
+ this.depositReturnedCoins(r);
+ });
// FIXME: optimize via index
this.q()
- .iter(Stores.coins)
- .forEach((c: CoinRecord) => {
- if (c.status === CoinStatus.Dirty) {
- console.log("resuming pending refresh for coin", c);
- this.refresh(c.coinPub);
- }
- });
+ .iter(Stores.coins)
+ .forEach((c: CoinRecord) => {
+ if (c.status === CoinStatus.Dirty) {
+ console.log("resuming pending refresh for coin", c);
+ this.refresh(c.coinPub);
+ }
+ });
}
- private async getCoinsForReturn(
- exchangeBaseUrl: string,
- amount: AmountJson,
- ): Promise<CoinWithDenom[] | undefined> {
+
+ 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();
+ const coins: CoinRecord[] = await (
+ this.q()
+ .iterIndex(Stores.coins.exchangeBaseUrlIndex, exchange.baseUrl)
+ .toArray()
+ );
if (!coins || !coins.length) {
return [];
}
- const denoms = await this.q()
- .iterIndex(Stores.denominations.exchangeBaseUrlIndex, exchange.baseUrl)
- .toArray();
+ const denoms = await
this.q().iterIndex(Stores.denominations.exchangeBaseUrlIndex,
exchange.baseUrl).toArray();
// 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,
- ]);
+ const firstDenom = await this.q().get(Stores.denominations,
+ [
+ exchange.baseUrl,
+ coins[0].denomPub,
+ ]);
if (!firstDenom) {
throw Error("db inconsistent");
}
@@ -493,19 +472,13 @@ export class Wallet {
const cds: CoinWithDenom[] = [];
for (const coin of coins) {
- const denom = await this.q().get(Stores.denominations, [
- exchange.baseUrl,
- coin.denomPub,
- ]);
+ 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
- }`,
- );
+ console.warn(`same pubkey for different currencies at exchange
${exchange.baseUrl}`);
continue;
}
if (coin.suspended) {
@@ -514,10 +487,10 @@ export class Wallet {
if (coin.status !== CoinStatus.Fresh) {
continue;
}
- cds.push({ coin, denom });
+ cds.push({coin, denom});
}
- console.log("coin return: selecting from possible coins", { cds, amount
});
+ console.log("coin return: selecting from possible coins", { cds, amount }
);
const res = selectPayCoins(denoms, cds, amount, amount);
if (res) {
@@ -526,13 +499,12 @@ export class Wallet {
return undefined;
}
+
/**
* Get exchanges and associated coins that are still spendable,
* but only if the sum the coins' remaining value exceeds the payment amount.
*/
- private async getCoinsForPayment(
- args: CoinsForPaymentArgs,
- ): Promise<CoinSelectionResult | undefined> {
+ private async getCoinsForPayment(args: CoinsForPaymentArgs):
Promise<CoinSelectionResult|undefined> {
const {
allowedAuditors,
allowedExchanges,
@@ -546,9 +518,7 @@ export class Wallet {
let remainingAmount = paymentAmount;
- const exchanges = await this.q()
- .iter(Stores.exchanges)
- .toArray();
+ const exchanges = await this.q().iter(Stores.exchanges).toArray();
for (const exchange of exchanges) {
let isOkay: boolean = false;
@@ -581,40 +551,34 @@ export class Wallet {
}
const coins: CoinRecord[] = await this.q()
- .iterIndex(Stores.coins.exchangeBaseUrlIndex, exchange.baseUrl)
- .toArray();
- const denoms = await this.q()
- .iterIndex(Stores.denominations.exchangeBaseUrlIndex, exchange.baseUrl)
- .toArray();
+
.iterIndex(Stores.coins.exchangeBaseUrlIndex,
+ exchange.baseUrl)
+ .toArray();
+ const denoms = await
this.q().iterIndex(Stores.denominations.exchangeBaseUrlIndex,
exchange.baseUrl).toArray();
if (!coins || coins.length === 0) {
continue;
}
// Denomination of the first coin, we assume that all other
// coins have the same currency
- const firstDenom = await this.q().get(Stores.denominations, [
- exchange.baseUrl,
- coins[0].denomPub,
- ]);
+ 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,
- ]);
+ 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
- }`,
- );
+ console.warn(`same pubkey for different currencies at exchange
${exchange.baseUrl}`);
continue;
}
if (coin.suspended) {
@@ -623,13 +587,10 @@ export class Wallet {
if (coin.status !== CoinStatus.Fresh) {
continue;
}
- cds.push({ coin, denom });
+ cds.push({coin, denom});
}
- const fees = await this.q().get(
- Stores.exchangeWireFees,
- exchange.baseUrl,
- );
+ const fees = await this.q().get(Stores.exchangeWireFees,
exchange.baseUrl);
if (!fees) {
console.error("no fees found for exchange", exchange);
continue;
@@ -642,8 +603,8 @@ export class Wallet {
console.log("payment coins: wireFeeTime", wireFeeTime);
let totalFees = Amounts.getZero(currency);
- let wireFee: AmountJson | undefined;
- for (const fee of fees.feesForType[wireMethod] || []) {
+ let wireFee: AmountJson|undefined;
+ for (const fee of (fees.feesForType[wireMethod] || [])) {
if (fee.startStamp <= wireFeeTime && fee.endStamp >= wireFeeTime) {
wireFee = fee.wireFee;
break;
@@ -656,8 +617,7 @@ export class Wallet {
const amortizedWireFee = Amounts.divide(wireFee, wireFeeAmortization);
if (Amounts.cmp(wireFeeLimit, amortizedWireFee) < 0) {
totalFees = Amounts.add(amortizedWireFee, totalFees).amount;
- remainingAmount = Amounts.add(amortizedWireFee, remainingAmount)
- .amount;
+ remainingAmount = Amounts.add(amortizedWireFee,
remainingAmount).amount;
}
}
@@ -675,15 +635,14 @@ export class Wallet {
return undefined;
}
+
/**
* Record all information that is necessary to
* pay for a proposal in the wallet's database.
*/
- private async recordConfirmPay(
- proposal: ProposalDownloadRecord,
- payCoinInfo: PayCoinInfo,
- chosenExchange: string,
- ): Promise<PurchaseRecord> {
+ private async recordConfirmPay(proposal: ProposalDownloadRecord,
+ payCoinInfo: PayCoinInfo,
+ chosenExchange: string):
Promise<PurchaseRecord> {
const payReq: PayReq = {
coins: payCoinInfo.sigs,
merchant_pub: proposal.contractTerms.merchant_pub,
@@ -702,28 +661,26 @@ export class Wallet {
payReq,
refundsDone: {},
refundsPending: {},
- timestamp: new Date().getTime(),
+ timestamp: (new Date()).getTime(),
timestamp_refund: 0,
};
await this.q()
- .put(Stores.purchases, t)
- .putAll(Stores.coins, payCoinInfo.updatedCoins)
- .finish();
+ .put(Stores.purchases, t)
+ .putAll(Stores.coins, payCoinInfo.updatedCoins)
+ .finish();
this.badge.showNotification();
this.notifier.notify();
return t;
}
+
/**
* Download a proposal and store it in the database.
* Returns an id for it to retrieve it later.
*/
async downloadProposal(url: string): Promise<number> {
- const oldProposal = await this.q().getIndexed(
- Stores.proposals.urlIndex,
- url,
- );
+ const oldProposal = await this.q().getIndexed(Stores.proposals.urlIndex,
url);
if (oldProposal) {
return oldProposal.id!;
}
@@ -734,7 +691,7 @@ export class Wallet {
console.log("downloading contract from '" + urlWithNonce + "'");
let resp;
try {
- resp = await axios.get(urlWithNonce, { validateStatus: s => s === 200 });
+ resp = await axios.get(urlWithNonce, { validateStatus: (s) => s === 200
});
} catch (e) {
console.log("contract download failed", e);
throw e;
@@ -750,7 +707,7 @@ export class Wallet {
contractTermsHash,
merchantSig: proposal.sig,
noncePriv: priv,
- timestamp: new Date().getTime(),
+ timestamp: (new Date()).getTime(),
url,
};
@@ -762,21 +719,16 @@ export class Wallet {
return id;
}
+
async refundFailedPay(proposalId: number) {
console.log(`refunding failed payment with proposal id ${proposalId}`);
- const proposal: ProposalDownloadRecord | undefined = await this.q().get(
- Stores.proposals,
- proposalId,
- );
+ const proposal: ProposalDownloadRecord|undefined = await
this.q().get(Stores.proposals, proposalId);
if (!proposal) {
throw Error(`proposal with id ${proposalId} not found`);
}
- const purchase = await this.q().get(
- Stores.purchases,
- proposal.contractTermsHash,
- );
+ const purchase = await this.q().get(Stores.purchases,
proposal.contractTermsHash);
if (!purchase) {
throw Error("purchase not found for proposal");
}
@@ -786,10 +738,8 @@ export class Wallet {
}
}
- async submitPay(
- contractTermsHash: string,
- sessionId: string | undefined,
- ): Promise<ConfirmPayResult> {
+
+ async submitPay(contractTermsHash: string, sessionId: string | undefined):
Promise<ConfirmPayResult> {
const purchase = await this.q().get(Stores.purchases, contractTermsHash);
if (!purchase) {
throw Error("Purchase not found: " + contractTermsHash);
@@ -803,7 +753,7 @@ export class Wallet {
try {
const config = {
headers: { "Content-Type": "application/json;charset=UTF-8" },
- timeout: 5000 /* 5 seconds */,
+ timeout: 5000, /* 5 seconds */
validateStatus: (s: number) => s === 200,
};
resp = await axios.post(purchase.contractTerms.pay_url, payReq, config);
@@ -816,10 +766,8 @@ export class Wallet {
console.log("got success from pay_url");
const merchantPub = purchase.contractTerms.merchant_pub;
- const valid: boolean = await this.cryptoApi.isValidPaymentSignature(
- merchantResp.sig,
- contractTermsHash,
- merchantPub,
+ const valid: boolean = await (
+ this.cryptoApi.isValidPaymentSignature(merchantResp.sig,
contractTermsHash, merchantPub)
);
if (!valid) {
console.error("merchant payment signature invalid");
@@ -847,44 +795,31 @@ export class Wallet {
}
await this.q()
- .putAll(Stores.coins, modifiedCoins)
- .put(Stores.purchases, purchase)
- .finish();
+ .putAll(Stores.coins, modifiedCoins)
+ .put(Stores.purchases, purchase)
+ .finish();
for (const c of purchase.payReq.coins) {
this.refresh(c.coin_pub);
}
const nextUrl = fu.href();
- this.cachedNextUrl[purchase.contractTerms.fulfillment_url] = {
- nextUrl,
- lastSessionId: sessionId,
- };
+ this.cachedNextUrl[purchase.contractTerms.fulfillment_url] = { nextUrl,
lastSessionId: sessionId };
return { nextUrl };
}
+
/**
* Add a contract to the wallet and sign coins, and send them.
*/
- async confirmPay(
- proposalId: number,
- sessionId: string | undefined,
- ): Promise<ConfirmPayResult> {
- console.log(
- `executing confirmPay with proposalId ${proposalId} and sessionId
${sessionId}`,
- );
- const proposal: ProposalDownloadRecord | undefined = await this.q().get(
- Stores.proposals,
- proposalId,
- );
+ async confirmPay(proposalId: number, sessionId: string | undefined):
Promise<ConfirmPayResult> {
+ console.log(`executing confirmPay with proposalId ${proposalId} and
sessionId ${sessionId}`);
+ const proposal: ProposalDownloadRecord|undefined = await
this.q().get(Stores.proposals, proposalId);
if (!proposal) {
throw Error(`proposal with id ${proposalId} not found`);
}
- let purchase = await this.q().get(
- Stores.purchases,
- proposal.contractTermsHash,
- );
+ let purchase = await this.q().get(Stores.purchases,
proposal.contractTermsHash);
if (purchase) {
return this.submitPay(purchase.contractTermsHash, sessionId);
@@ -922,33 +857,20 @@ export class Wallet {
const sd = await this.getSpeculativePayData(proposalId);
if (!sd) {
const { exchangeUrl, cds, totalAmount } = res;
- const payCoinInfo = await this.cryptoApi.signDeposit(
- proposal.contractTerms,
- cds,
- totalAmount,
- );
- purchase = await this.recordConfirmPay(
- proposal,
- payCoinInfo,
- exchangeUrl,
- );
+ const payCoinInfo = await
this.cryptoApi.signDeposit(proposal.contractTerms, cds, totalAmount);
+ purchase = await this.recordConfirmPay(proposal, payCoinInfo,
exchangeUrl);
} else {
- purchase = await this.recordConfirmPay(
- sd.proposal,
- sd.payCoinInfo,
- sd.exchangeUrl,
- );
+ purchase = await this.recordConfirmPay(sd.proposal, sd.payCoinInfo,
sd.exchangeUrl);
}
return this.submitPay(purchase.contractTermsHash, sessionId);
}
+
/**
* Get the speculative pay data, but only if coins have not changed in
between.
*/
- async getSpeculativePayData(
- proposalId: number,
- ): Promise<SpeculativePayData | undefined> {
+ async getSpeculativePayData(proposalId: number): Promise<SpeculativePayData
| undefined> {
const sp = this.speculativePayData;
if (!sp) {
return;
@@ -966,15 +888,14 @@ export class Wallet {
if (!currentCoin) {
return;
}
- if (
- Amounts.cmp(specCoin.currentAmount, currentCoin.currentAmount) !== 0
- ) {
+ if (Amounts.cmp(specCoin.currentAmount, currentCoin.currentAmount) !==
0) {
return;
}
}
return sp;
}
+
/**
* Check if payment for an offer is possible, or if the offer has already
* been payed for.
@@ -990,10 +911,7 @@ export class Wallet {
}
// First check if we already payed for it.
- const purchase = await this.q().get(
- Stores.purchases,
- proposal.contractTermsHash,
- );
+ const purchase = await this.q().get(Stores.purchases,
proposal.contractTermsHash);
if (purchase) {
return { status: "paid" };
}
@@ -1025,17 +943,9 @@ export class Wallet {
}
// Only create speculative signature if we don't already have one for this
proposal
- if (
- !this.speculativePayData ||
- (this.speculativePayData &&
- this.speculativePayData.proposalId !== proposalId)
- ) {
+ if ((!this.speculativePayData) || (this.speculativePayData &&
this.speculativePayData.proposalId !== proposalId)) {
const { exchangeUrl, cds, totalAmount } = res;
- const payCoinInfo = await this.cryptoApi.signDeposit(
- proposal.contractTerms,
- cds,
- totalAmount,
- );
+ const payCoinInfo = await
this.cryptoApi.signDeposit(proposal.contractTerms, cds, totalAmount);
this.speculativePayData = {
exchangeUrl,
payCoinInfo,
@@ -1047,19 +957,15 @@ export class Wallet {
return { status: "payment-possible", coinSelection: res };
}
+
/**
* Retrieve information required to pay for a contract, where the
* contract is identified via the fulfillment url.
*/
- async queryPaymentByFulfillmentUrl(
- url: string,
- ): Promise<PurchaseRecord | undefined> {
+ async queryPaymentByFulfillmentUrl(url: string): Promise<PurchaseRecord |
undefined> {
console.log("query for payment", url);
- const t = await this.q().getIndexed(
- Stores.purchases.fulfillmentUrlIndex,
- url,
- );
+ const t = await this.q().getIndexed(Stores.purchases.fulfillmentUrlIndex,
url);
if (!t) {
console.log("query for payment failed");
@@ -1069,14 +975,13 @@ export class Wallet {
return t;
}
+
/**
* First fetch information requred to withdraw from the reserve,
* then deplete the reserve, withdrawing coins until it is empty.
*/
- private async processReserve(
- reserveRecord: ReserveRecord,
- retryDelayMs: number = 250,
- ): Promise<void> {
+ private async processReserve(reserveRecord: ReserveRecord,
+ retryDelayMs: number = 250): Promise<void> {
const opId = "reserve-" + reserveRecord.reserve_pub;
this.startOperation(opId);
@@ -1085,54 +990,38 @@ export class Wallet {
await this.depleteReserve(reserve);
} catch (e) {
// random, exponential backoff truncated at 3 minutes
- const nextDelay = Math.min(
- 2 * retryDelayMs + retryDelayMs * Math.random(),
- 3000 * 60,
- );
- console.warn(
- `Failed to deplete reserve, trying again in ${retryDelayMs} ms`,
- );
- this.timerGroup.after(retryDelayMs, () =>
- this.processReserve(reserveRecord, nextDelay),
- );
+ const nextDelay = Math.min(2 * retryDelayMs + retryDelayMs *
Math.random(), 3000 * 60);
+ console.warn(`Failed to deplete reserve, trying again in ${retryDelayMs}
ms`);
+ this.timerGroup.after(retryDelayMs, () =>
this.processReserve(reserveRecord, nextDelay));
} finally {
this.stopOperation(opId);
}
}
+
/**
* Given a planchet, withdraw a coin from the exchange.
*/
- private async processPreCoin(
- preCoin: PreCoinRecord,
- retryDelayMs = 200,
- ): Promise<void> {
+ private async processPreCoin(preCoin: PreCoinRecord,
+ retryDelayMs = 200): Promise<void> {
// Throttle concurrent executions of this function, so we don't withdraw
too many coins at once.
- if (
- this.processPreCoinConcurrent >= 4 ||
- this.processPreCoinThrottle[preCoin.exchangeBaseUrl]
- ) {
+ if (this.processPreCoinConcurrent >= 4 ||
this.processPreCoinThrottle[preCoin.exchangeBaseUrl]) {
console.log("delaying processPreCoin");
- this.timerGroup.after(retryDelayMs, () =>
- this.processPreCoin(preCoin, Math.min(retryDelayMs * 2, 5 * 60 *
1000)),
- );
+ this.timerGroup.after(retryDelayMs,
+ () => this.processPreCoin(preCoin,
Math.min(retryDelayMs * 2, 5 * 60 * 1000)));
return;
}
console.log("executing processPreCoin", preCoin);
this.processPreCoinConcurrent++;
try {
- const exchange = await this.q().get(
- Stores.exchanges,
- preCoin.exchangeBaseUrl,
- );
+ const exchange = await this.q().get(Stores.exchanges,
+ preCoin.exchangeBaseUrl);
if (!exchange) {
console.error("db inconsistent: exchange for precoin not found");
return;
}
- const denom = await this.q().get(Stores.denominations, [
- preCoin.exchangeBaseUrl,
- preCoin.denomPub,
- ]);
+ const denom = await this.q().get(Stores.denominations,
+ [preCoin.exchangeBaseUrl,
preCoin.denomPub]);
if (!denom) {
console.error("db inconsistent: denom for precoin not found");
return;
@@ -1142,17 +1031,11 @@ export class Wallet {
console.log("processPreCoin: got coin", coin);
const mutateReserve = (r: ReserveRecord) => {
- console.log(
- `before committing coin: current ${amountToPretty(
- r.current_amount!,
- )}, precoin: ${amountToPretty(r.precoin_amount)})}`,
- );
- const x = Amounts.sub(
- r.precoin_amount,
- preCoin.coinValue,
- denom.feeWithdraw,
- );
+ console.log(`before committing coin: current
${amountToPretty(r.current_amount!)}, precoin: ${amountToPretty(
+ r.precoin_amount)})}`);
+
+ const x = Amounts.sub(r.precoin_amount, preCoin.coinValue,
denom.feeWithdraw);
if (x.saturated) {
console.error("database inconsistent");
throw AbortTransaction;
@@ -1162,20 +1045,15 @@ export class Wallet {
};
await this.q()
- .mutate(Stores.reserves, preCoin.reservePub, mutateReserve)
- .delete(Stores.precoins, coin.coinPub)
- .add(Stores.coins, coin)
- .finish();
+ .mutate(Stores.reserves, preCoin.reservePub, mutateReserve)
+ .delete(Stores.precoins, coin.coinPub)
+ .add(Stores.coins, coin)
+ .finish();
if (coin.status === CoinStatus.TainedByTip) {
- const tip = await this.q().getIndexed(
- Stores.tips.coinPubIndex,
- coin.coinPub,
- );
+ const tip = await this.q().getIndexed(Stores.tips.coinPubIndex,
coin.coinPub);
if (!tip) {
- throw Error(
- `inconsistent DB: tip for coin pub ${coin.coinPub} not found.`,
- );
+ throw Error(`inconsistent DB: tip for coin pub ${coin.coinPub} not
found.`);
}
if (tip.accepted) {
@@ -1197,55 +1075,44 @@ export class Wallet {
this.notifier.notify();
} catch (e) {
- console.error(
- "Failed to withdraw coin from precoin, retrying in",
- retryDelayMs,
- "ms",
- e,
- );
+ console.error("Failed to withdraw coin from precoin, retrying in",
+ retryDelayMs,
+ "ms", e);
// exponential backoff truncated at one minute
const nextRetryDelayMs = Math.min(retryDelayMs * 2, 5 * 60 * 1000);
- this.timerGroup.after(retryDelayMs, () =>
- this.processPreCoin(preCoin, nextRetryDelayMs),
- );
-
- const currentThrottle =
- this.processPreCoinThrottle[preCoin.exchangeBaseUrl] || 0;
- this.processPreCoinThrottle[preCoin.exchangeBaseUrl] =
- currentThrottle + 1;
- this.timerGroup.after(retryDelayMs, () => {
- this.processPreCoinThrottle[preCoin.exchangeBaseUrl]--;
- });
+ this.timerGroup.after(retryDelayMs, () => this.processPreCoin(preCoin,
nextRetryDelayMs));
+
+ const currentThrottle =
this.processPreCoinThrottle[preCoin.exchangeBaseUrl] || 0;
+ this.processPreCoinThrottle[preCoin.exchangeBaseUrl] = currentThrottle +
1;
+ this.timerGroup.after(retryDelayMs, () =>
{this.processPreCoinThrottle[preCoin.exchangeBaseUrl]--; });
} finally {
this.processPreCoinConcurrent--;
}
}
+
/**
* Update the timestamp of when an exchange was used.
*/
async updateExchangeUsedTime(exchangeBaseUrl: string): Promise<void> {
- const now = new Date().getTime();
+ const now = (new Date()).getTime();
const update = (r: ExchangeRecord) => {
r.lastUsedTime = now;
return r;
};
- await this.q()
- .mutate(Stores.exchanges, exchangeBaseUrl, update)
- .finish();
+ await this.q().mutate(Stores.exchanges, exchangeBaseUrl, update).finish();
}
+
/**
* Create a reserve, but do not flag it as confirmed yet.
*
* Adds the corresponding exchange as a trusted exchange if it is neither
* audited nor trusted already.
*/
- async createReserve(
- req: CreateReserveRequest,
- ): Promise<CreateReserveResponse> {
+ async createReserve(req: CreateReserveRequest):
Promise<CreateReserveResponse> {
const keypair = await this.cryptoApi.createEddsaKeypair();
- const now = new Date().getTime();
+ const now = (new Date()).getTime();
const canonExchange = canonicalizeBaseUrl(req.exchange);
const reserveRecord: ReserveRecord = {
@@ -1267,18 +1134,13 @@ export class Wallet {
const rec = {
paytoUri: senderWire,
};
- await this.q()
- .put(Stores.senderWires, rec)
- .finish();
+ await this.q().put(Stores.senderWires, rec).finish();
}
await this.updateExchangeUsedTime(req.exchange);
const exchangeInfo = await this.updateExchangeFromUrl(req.exchange);
- const { isAudited, isTrusted } = await this.getExchangeTrust(exchangeInfo);
- let currencyRecord = await this.q().get(
- Stores.currencies,
- exchangeInfo.currency,
- );
+ const {isAudited, isTrusted} = await this.getExchangeTrust(exchangeInfo);
+ let currencyRecord = await this.q().get(Stores.currencies,
exchangeInfo.currency);
if (!currencyRecord) {
currencyRecord = {
auditors: [],
@@ -1289,16 +1151,13 @@ export class Wallet {
}
if (!isAudited && !isTrusted) {
- currencyRecord.exchanges.push({
- baseUrl: req.exchange,
- exchangePub: exchangeInfo.masterPublicKey,
- });
+ currencyRecord.exchanges.push({baseUrl: req.exchange, exchangePub:
exchangeInfo.masterPublicKey});
}
await this.q()
- .put(Stores.currencies, currencyRecord)
- .put(Stores.reserves, reserveRecord)
- .finish();
+ .put(Stores.currencies, currencyRecord)
+ .put(Stores.reserves, reserveRecord)
+ .finish();
const r: CreateReserveResponse = {
exchange: canonExchange,
@@ -1307,6 +1166,7 @@ export class Wallet {
return r;
}
+
/**
* Mark an existing reserve as confirmed. The wallet will start trying
* to withdraw from that reserve. This may not immediately succeed,
@@ -1317,10 +1177,10 @@ export class Wallet {
* an unconfirmed reserve should be hidden.
*/
async confirmReserve(req: ConfirmReserveRequest): Promise<void> {
- const now = new Date().getTime();
- const reserve: ReserveRecord | undefined = await this.q().get<
- ReserveRecord
- >(Stores.reserves, req.reservePub);
+ const now = (new Date()).getTime();
+ const reserve: ReserveRecord|undefined = await (
+ this.q().get<ReserveRecord>(Stores.reserves,
+ req.reservePub));
if (!reserve) {
console.error("Unable to confirm reserve, not found in DB");
return;
@@ -1328,20 +1188,21 @@ export class Wallet {
console.log("reserve confirmed");
reserve.timestamp_confirmed = now;
await this.q()
- .put(Stores.reserves, reserve)
- .finish();
+ .put(Stores.reserves, reserve)
+ .finish();
this.notifier.notify();
this.processReserve(reserve);
}
+
private async withdrawExecute(pc: PreCoinRecord): Promise<CoinRecord> {
const wd: any = {};
wd.denom_pub_hash = pc.denomPubHash;
wd.reserve_pub = pc.reservePub;
wd.reserve_sig = pc.withdrawSig;
wd.coin_ev = pc.coinEv;
- const reqUrl = new URI("reserve/withdraw").absoluteTo(pc.exchangeBaseUrl);
+ const reqUrl = (new
URI("reserve/withdraw")).absoluteTo(pc.exchangeBaseUrl);
const resp = await this.http.postJson(reqUrl.href(), wd);
if (resp.status !== 200) {
@@ -1351,11 +1212,9 @@ export class Wallet {
});
}
const r = JSON.parse(resp.responseText);
- const denomSig = await this.cryptoApi.rsaUnblind(
- r.ev_sig,
- pc.blindingKey,
- pc.denomPub,
- );
+ const denomSig = await this.cryptoApi.rsaUnblind(r.ev_sig,
+ pc.blindingKey,
+ pc.denomPub);
const coin: CoinRecord = {
blindingKey: pc.blindingKey,
coinPriv: pc.coinPriv,
@@ -1371,6 +1230,7 @@ export class Wallet {
return coin;
}
+
/**
* Withdraw coins from a reserve until it is empty.
*
@@ -1386,32 +1246,23 @@ export class Wallet {
if (!withdrawAmount) {
throw Error("can't withdraw when amount is unknown");
}
- const denomsForWithdraw = await this.getVerifiedWithdrawDenomList(
- reserve.exchange_base_url,
- withdrawAmount,
- );
- const smallestAmount = await this.getVerifiedSmallestWithdrawAmount(
- reserve.exchange_base_url,
- );
+ const denomsForWithdraw = await
this.getVerifiedWithdrawDenomList(reserve.exchange_base_url, withdrawAmount);
+ const smallestAmount = await
this.getVerifiedSmallestWithdrawAmount(reserve.exchange_base_url);
console.log(`withdrawing ${denomsForWithdraw.length} coins`);
- const ps = denomsForWithdraw.map(async denom => {
+ const ps = denomsForWithdraw.map(async(denom) => {
function mutateReserve(r: ReserveRecord): ReserveRecord {
const currentAmount = r.current_amount;
if (!currentAmount) {
throw Error("can't withdraw when amount is unknown");
}
- r.precoin_amount = Amounts.add(
- r.precoin_amount,
- denom.value,
- denom.feeWithdraw,
- ).amount;
- const result = Amounts.sub(
- currentAmount,
- denom.value,
- denom.feeWithdraw,
- );
+ r.precoin_amount = Amounts.add(r.precoin_amount,
+ denom.value,
+ denom.feeWithdraw).amount;
+ const result = Amounts.sub(currentAmount,
+ denom.value,
+ denom.feeWithdraw);
if (result.saturated) {
console.error("can't create precoin, saturated");
throw AbortTransaction;
@@ -1420,44 +1271,39 @@ export class Wallet {
// Reserve is depleted if the amount left is too small to withdraw
if (Amounts.cmp(r.current_amount, smallestAmount) < 0) {
- r.timestamp_depleted = new Date().getTime();
+ r.timestamp_depleted = (new Date()).getTime();
}
- console.log(
- `after creating precoin: current ${amountToPretty(
- r.current_amount,
- )}, precoin: ${amountToPretty(r.precoin_amount)})}`,
- );
+ console.log(`after creating precoin: current
${amountToPretty(r.current_amount)}, precoin: ${amountToPretty(
+ r.precoin_amount)})}`);
return r;
}
- const preCoin = await this.cryptoApi.createPreCoin(denom, reserve);
+ const preCoin = await this.cryptoApi
+ .createPreCoin(denom, reserve);
await this.q()
- .put(Stores.precoins, preCoin)
- .mutate(Stores.reserves, reserve.reserve_pub, mutateReserve);
+ .put(Stores.precoins, preCoin)
+ .mutate(Stores.reserves, reserve.reserve_pub, mutateReserve);
await this.processPreCoin(preCoin);
});
await Promise.all(ps);
}
+
/**
* Update the information about a reserve that is stored in the wallet
* by quering the reserve's exchange.
*/
private async updateReserve(reservePub: string): Promise<ReserveRecord> {
- const reserve = await this.q().get<ReserveRecord>(
- Stores.reserves,
- reservePub,
- );
+ const reserve = await this.q()
+ .get<ReserveRecord>(Stores.reserves, reservePub);
if (!reserve) {
throw Error("reserve not in db");
}
- const reqUrl = new URI("reserve/status").absoluteTo(
- reserve.exchange_base_url,
- );
- reqUrl.query({ reserve_pub: reservePub });
+ const reqUrl = new
URI("reserve/status").absoluteTo(reserve.exchange_base_url);
+ reqUrl.query({reserve_pub: reservePub});
const resp = await this.http.get(reqUrl.href());
if (resp.status !== 200) {
throw Error();
@@ -1468,12 +1314,13 @@ export class Wallet {
}
reserve.current_amount = Amounts.parseOrThrow(reserveInfo.balance);
await this.q()
- .put(Stores.reserves, reserve)
- .finish();
+ .put(Stores.reserves, reserve)
+ .finish();
this.notifier.notify();
return reserve;
}
+
/**
* Get the wire information for the exchange with the given base URL.
*/
@@ -1494,39 +1341,35 @@ export class Wallet {
return ExchangeWireJson.checked(wiJson);
}
+
async getPossibleDenoms(exchangeBaseUrl: string) {
- return this.q()
- .iterIndex(Stores.denominations.exchangeBaseUrlIndex, exchangeBaseUrl)
- .filter(
- d =>
- d.status === DenominationStatus.Unverified ||
- d.status === DenominationStatus.VerifiedGood,
- )
- .toArray();
+ return (
+ this.q().iterIndex(Stores.denominations.exchangeBaseUrlIndex,
+ exchangeBaseUrl)
+ .filter((d) => d.status === DenominationStatus.Unverified ||
d.status === DenominationStatus.VerifiedGood)
+ .toArray()
+ );
}
+
/**
* Compute the smallest withdrawable amount possible, based on verified
denominations.
*
* Writes to the DB in order to record the result from verifying
* denominations.
*/
- async getVerifiedSmallestWithdrawAmount(
- exchangeBaseUrl: string,
- ): Promise<AmountJson> {
+ async getVerifiedSmallestWithdrawAmount(exchangeBaseUrl: string):
Promise<AmountJson> {
const exchange = await this.q().get(Stores.exchanges, exchangeBaseUrl);
if (!exchange) {
throw Error(`exchange ${exchangeBaseUrl} not found`);
}
- const possibleDenoms = await this.q()
- .iterIndex(Stores.denominations.exchangeBaseUrlIndex, exchange.baseUrl)
- .filter(
- d =>
- d.status === DenominationStatus.Unverified ||
- d.status === DenominationStatus.VerifiedGood,
- )
- .toArray();
+ const possibleDenoms = await (
+ this.q().iterIndex(Stores.denominations.exchangeBaseUrlIndex,
+ exchange.baseUrl)
+ .filter((d) => d.status === DenominationStatus.Unverified ||
d.status === DenominationStatus.VerifiedGood)
+ .toArray()
+ );
possibleDenoms.sort((d1, d2) => {
const a1 = Amounts.add(d1.feeWithdraw, d1.value).amount;
const a2 = Amounts.add(d2.feeWithdraw, d2.value).amount;
@@ -1538,18 +1381,14 @@ export class Wallet {
return Amounts.add(denom.feeWithdraw, denom.value).amount;
}
console.log(`verifying denom ${denom.denomPub.substr(0, 15)}`);
- const valid = await this.cryptoApi.isValidDenom(
- denom,
- exchange.masterPublicKey,
- );
+ const valid = await this.cryptoApi.isValidDenom(denom,
+
exchange.masterPublicKey);
if (!valid) {
denom.status = DenominationStatus.VerifiedBad;
} else {
denom.status = DenominationStatus.VerifiedGood;
}
- await this.q()
- .put(Stores.denominations, denom)
- .finish();
+ await this.q().put(Stores.denominations, denom).finish();
if (valid) {
return Amounts.add(denom.feeWithdraw, denom.value).amount;
}
@@ -1557,6 +1396,7 @@ export class Wallet {
return Amounts.getZero(exchange.currency);
}
+
/**
* Get a list of denominations to withdraw from the given exchange for the
* given amount, making sure that all denominations' signatures are verified.
@@ -1564,23 +1404,19 @@ export class Wallet {
* Writes to the DB in order to record the result from verifying
* denominations.
*/
- async getVerifiedWithdrawDenomList(
- exchangeBaseUrl: string,
- amount: AmountJson,
- ): Promise<DenominationRecord[]> {
+ async getVerifiedWithdrawDenomList(exchangeBaseUrl: string,
+ amount: AmountJson):
Promise<DenominationRecord[]> {
const exchange = await this.q().get(Stores.exchanges, exchangeBaseUrl);
if (!exchange) {
throw Error(`exchange ${exchangeBaseUrl} not found`);
}
- const possibleDenoms = await this.q()
- .iterIndex(Stores.denominations.exchangeBaseUrlIndex, exchange.baseUrl)
- .filter(
- d =>
- d.status === DenominationStatus.Unverified ||
- d.status === DenominationStatus.VerifiedGood,
- )
- .toArray();
+ const possibleDenoms = await (
+ this.q().iterIndex(Stores.denominations.exchangeBaseUrlIndex,
+ exchange.baseUrl)
+ .filter((d) => d.status === DenominationStatus.Unverified ||
d.status === DenominationStatus.VerifiedGood)
+ .toArray()
+ );
let allValid = false;
@@ -1593,10 +1429,8 @@ export class Wallet {
for (const denom of selectedDenoms || []) {
if (denom.status === DenominationStatus.Unverified) {
console.log(`verifying denom ${denom.denomPub.substr(0, 15)}`);
- const valid = await this.cryptoApi.isValidDenom(
- denom,
- exchange.masterPublicKey,
- );
+ const valid = await this.cryptoApi.isValidDenom(denom,
+
exchange.masterPublicKey);
if (!valid) {
denom.status = DenominationStatus.VerifiedBad;
allValid = false;
@@ -1604,9 +1438,7 @@ export class Wallet {
denom.status = DenominationStatus.VerifiedGood;
nextPossibleDenoms.push(denom);
}
- await this.q()
- .put(Stores.denominations, denom)
- .finish();
+ await this.q().put(Stores.denominations, denom).finish();
} else {
nextPossibleDenoms.push(denom);
}
@@ -1616,18 +1448,14 @@ export class Wallet {
return selectedDenoms;
}
+
/**
* Check if and how an exchange is trusted and/or audited.
*/
- async getExchangeTrust(
- exchangeInfo: ExchangeRecord,
- ): Promise<{ isTrusted: boolean; isAudited: boolean }> {
+ async getExchangeTrust(exchangeInfo: ExchangeRecord): Promise<{isTrusted:
boolean, isAudited: boolean}> {
let isTrusted = false;
let isAudited = false;
- const currencyRecord = await this.q().get(
- Stores.currencies,
- exchangeInfo.currency,
- );
+ const currencyRecord = await this.q().get(Stores.currencies,
exchangeInfo.currency);
if (currencyRecord) {
for (const trustedExchange of currencyRecord.exchanges) {
if (trustedExchange.exchangePub === exchangeInfo.masterPublicKey) {
@@ -1644,27 +1472,22 @@ export class Wallet {
}
}
}
- return { isTrusted, isAudited };
+ return {isTrusted, isAudited};
}
- async getReserveCreationInfo(
- baseUrl: string,
- amount: AmountJson,
- ): Promise<ReserveCreationInfo> {
+ async getReserveCreationInfo(baseUrl: string,
+ amount: AmountJson):
Promise<ReserveCreationInfo> {
const exchangeInfo = await this.updateExchangeFromUrl(baseUrl);
- const selectedDenoms = await this.getVerifiedWithdrawDenomList(
- baseUrl,
- amount,
- );
+ const selectedDenoms = await this.getVerifiedWithdrawDenomList(baseUrl,
+ amount);
let acc = Amounts.getZero(amount.currency);
for (const d of selectedDenoms) {
acc = Amounts.add(acc, d.feeWithdraw).amount;
}
const actualCoinCost = selectedDenoms
- .map(
- (d: DenominationRecord) => Amounts.add(d.value, d.feeWithdraw).amount,
- )
+ .map((d: DenominationRecord) => Amounts.add(d.value,
+ d.feeWithdraw).amount)
.reduce((a, b) => Amounts.add(a, b).amount);
const wireInfo = await this.getWireInfo(baseUrl);
@@ -1680,7 +1503,7 @@ export class Wallet {
exchangeWireAccounts.push(account.url);
}
- const { isTrusted, isAudited } = await this.getExchangeTrust(exchangeInfo);
+ const {isTrusted, isAudited} = await this.getExchangeTrust(exchangeInfo);
let earliestDepositExpiration = Infinity;
for (const denom of selectedDenoms) {
@@ -1690,35 +1513,23 @@ export class Wallet {
}
}
- const possibleDenoms =
- (await this.q()
- .iterIndex(Stores.denominations.exchangeBaseUrlIndex, baseUrl)
- .filter(d => d.isOffered)
- .toArray()) || [];
+ const possibleDenoms = await (
+ this.q().iterIndex(Stores.denominations.exchangeBaseUrlIndex, baseUrl)
+ .filter((d) => d.isOffered)
+ .toArray()
+ ) || [];
const trustedAuditorPubs = [];
- const currencyRecord = await this.q().get<CurrencyRecord>(
- Stores.currencies,
- amount.currency,
- );
+ const currencyRecord = await
this.q().get<CurrencyRecord>(Stores.currencies, amount.currency);
if (currencyRecord) {
- trustedAuditorPubs.push(
- ...currencyRecord.auditors.map(a => a.auditorPub),
- );
+ trustedAuditorPubs.push(...currencyRecord.auditors.map((a) =>
a.auditorPub));
}
let versionMatch;
if (exchangeInfo.protocolVersion) {
- versionMatch = LibtoolVersion.compare(
- WALLET_PROTOCOL_VERSION,
- exchangeInfo.protocolVersion,
- );
-
- if (
- versionMatch &&
- !versionMatch.compatible &&
- versionMatch.currentCmp === -1
- ) {
+ versionMatch = LibtoolVersion.compare(WALLET_PROTOCOL_VERSION,
exchangeInfo.protocolVersion);
+
+ if (versionMatch && !versionMatch.compatible && versionMatch.currentCmp
=== -1) {
console.log("wallet version might be outdated, checking for updates");
chrome.runtime.requestUpdateCheck((status, details) => {
console.log("update check status:", status);
@@ -1745,6 +1556,7 @@ export class Wallet {
return ret;
}
+
/**
* Update or add exchange DB entry by fetching the /keys information.
* Optionally link the reserve entry to the new or existing
@@ -1757,32 +1569,25 @@ export class Wallet {
if (keysResp.status !== 200) {
throw Error("/keys request failed");
}
- const exchangeKeysJson = KeysJson.checked(
- JSON.parse(keysResp.responseText),
- );
+ const exchangeKeysJson =
KeysJson.checked(JSON.parse(keysResp.responseText));
const exchangeWire = await this.getWireInfo(baseUrl);
return this.updateExchangeFromJson(baseUrl, exchangeKeysJson,
exchangeWire);
}
+
private async suspendCoins(exchangeInfo: ExchangeRecord): Promise<void> {
- const resultSuspendedCoins = await this.q()
- .iterIndex(Stores.coins.exchangeBaseUrlIndex, exchangeInfo.baseUrl)
- .indexJoinLeft(
- Stores.denominations.exchangeBaseUrlIndex,
- e => e.exchangeBaseUrl,
- )
- .fold(
- (
- cd: JoinLeftResult<CoinRecord, DenominationRecord>,
- suspendedCoins: CoinRecord[],
- ) => {
- if (!cd.right || !cd.right.isOffered) {
- return Array.prototype.concat(suspendedCoins, [cd.left]);
- }
- return Array.prototype.concat(suspendedCoins);
- },
- [],
- );
+ const resultSuspendedCoins = await (
+ this.q()
+ .iterIndex(Stores.coins.exchangeBaseUrlIndex, exchangeInfo.baseUrl)
+ .indexJoinLeft(Stores.denominations.exchangeBaseUrlIndex,
+ (e) => e.exchangeBaseUrl)
+ .fold((cd: JoinLeftResult<CoinRecord, DenominationRecord>,
+ suspendedCoins: CoinRecord[]) => {
+ if ((!cd.right) || (!cd.right.isOffered)) {
+ return Array.prototype.concat(suspendedCoins, [cd.left]);
+ }
+ return Array.prototype.concat(suspendedCoins);
+ }, []));
const q = this.q();
resultSuspendedCoins.map((c: CoinRecord) => {
@@ -1795,11 +1600,11 @@ export class Wallet {
await q.finish();
}
- private async updateExchangeFromJson(
- baseUrl: string,
- exchangeKeysJson: KeysJson,
- wireMethodDetails: ExchangeWireJson,
- ): Promise<ExchangeRecord> {
+
+ private async updateExchangeFromJson(baseUrl: string,
+ exchangeKeysJson: KeysJson,
+ wireMethodDetails: ExchangeWireJson):
Promise<ExchangeRecord> {
+
// FIXME: all this should probably be commited atomically
const updateTimeSec = getTalerStampSec(exchangeKeysJson.list_issue_date);
if (updateTimeSec === null) {
@@ -1820,8 +1625,7 @@ export class Wallet {
exchangeInfo = {
auditors: exchangeKeysJson.auditors,
baseUrl,
- currency: Amounts.parseOrThrow(exchangeKeysJson.denoms[0].value)
- .currency,
+ currency:
Amounts.parseOrThrow(exchangeKeysJson.denoms[0].value).currency,
lastUpdateTime: updateTimeSec,
lastUsedTime: 0,
masterPublicKey: exchangeKeysJson.master_public_key,
@@ -1837,16 +1641,14 @@ export class Wallet {
console.log("updating old exchange");
}
- const updatedExchangeInfo = await this.updateExchangeInfo(
- exchangeInfo,
- exchangeKeysJson,
- );
+ const updatedExchangeInfo = await this.updateExchangeInfo(exchangeInfo,
+
exchangeKeysJson);
await this.suspendCoins(updatedExchangeInfo);
updatedExchangeInfo.protocolVersion = exchangeKeysJson.version;
await this.q()
- .put(Stores.exchanges, updatedExchangeInfo)
- .finish();
+ .put(Stores.exchanges, updatedExchangeInfo)
+ .finish();
let oldWireFees = await this.q().get(Stores.exchangeWireFees, baseUrl);
if (!oldWireFees) {
@@ -1887,11 +1689,7 @@ export class Wallet {
startStamp: start,
wireFee: Amounts.parseOrThrow(fee.wire_fee),
};
- const valid: boolean = await this.cryptoApi.isValidWireFee(
- paytoTargetType,
- wf,
- exchangeInfo.masterPublicKey,
- );
+ const valid: boolean = await
this.cryptoApi.isValidWireFee(paytoTargetType, wf,
exchangeInfo.masterPublicKey);
if (!valid) {
console.error("fee signature invalid", fee);
throw Error("fee signature invalid");
@@ -1904,17 +1702,12 @@ export class Wallet {
if (exchangeKeysJson.payback) {
for (const payback of exchangeKeysJson.payback) {
- const denom = await this.q().getIndexed(
- Stores.denominations.denomPubHashIndex,
- payback.h_denom_pub,
- );
+ const denom = await
this.q().getIndexed(Stores.denominations.denomPubHashIndex,
payback.h_denom_pub);
if (!denom) {
continue;
}
console.log(`cashing back denom`, denom);
- const coins = await this.q()
- .iterIndex(Stores.coins.denomPubIndex, denom.denomPub)
- .toArray();
+ const coins = await this.q().iterIndex(Stores.coins.denomPubIndex,
denom.denomPub).toArray();
for (const coin of coins) {
this.payback(coin.coinPub);
}
@@ -1924,27 +1717,19 @@ export class Wallet {
return updatedExchangeInfo;
}
- private async updateExchangeInfo(
- exchangeInfo: ExchangeRecord,
- newKeys: KeysJson,
- ): Promise<ExchangeRecord> {
+
+ private async updateExchangeInfo(exchangeInfo: ExchangeRecord,
+ newKeys: KeysJson): Promise<ExchangeRecord>
{
if (exchangeInfo.masterPublicKey !== newKeys.master_public_key) {
throw Error("public keys do not match");
}
- const existingDenoms: {
- [denomPub: string]: DenominationRecord;
- } = await this.q()
- .iterIndex(
- Stores.denominations.exchangeBaseUrlIndex,
- exchangeInfo.baseUrl,
- )
- .fold(
- (x: DenominationRecord, acc: typeof existingDenoms) => (
- (acc[x.denomPub] = x), acc
- ),
- {},
- );
+ const existingDenoms: {[denomPub: string]: DenominationRecord} = await (
+ this.q().iterIndex(Stores.denominations.exchangeBaseUrlIndex,
+ exchangeInfo.baseUrl)
+ .fold((x: DenominationRecord,
+ acc: typeof existingDenoms) => (acc[x.denomPub] = x, acc), {})
+ );
const newDenoms: typeof existingDenoms = {};
const newAndUnseenDenoms: typeof existingDenoms = {};
@@ -1965,18 +1750,15 @@ export class Wallet {
}
await this.q()
- .putAll(
- Stores.denominations,
- Object.keys(newAndUnseenDenoms).map(d => newAndUnseenDenoms[d]),
- )
- .putAll(
- Stores.denominations,
- Object.keys(existingDenoms).map(d => existingDenoms[d]),
- )
- .finish();
+ .putAll(Stores.denominations,
+ Object.keys(newAndUnseenDenoms).map((d) =>
newAndUnseenDenoms[d]))
+ .putAll(Stores.denominations,
+ Object.keys(existingDenoms).map((d) =>
existingDenoms[d]))
+ .finish();
return exchangeInfo;
}
+
/**
* Get detailed balance information, sliced by exchange and by currency.
*/
@@ -1985,24 +1767,15 @@ export class Wallet {
* Add amount to a balance field, both for
* the slicing by exchange and currency.
*/
- function addTo(
- balance: WalletBalance,
- field: keyof WalletBalanceEntry,
- amount: AmountJson,
- exchange: string,
- ): void {
+ function addTo(balance: WalletBalance,
+ field: keyof WalletBalanceEntry,
+ amount: AmountJson,
+ exchange: string): void {
const z = Amounts.getZero(amount.currency);
- const balanceIdentity = {
- available: z,
- paybackAmount: z,
- pendingIncoming: z,
- pendingPayment: z,
- };
+ const balanceIdentity = {available: z, paybackAmount: z,
pendingIncoming: z, pendingPayment: z};
let entryCurr = balance.byCurrency[amount.currency];
if (!entryCurr) {
- balance.byCurrency[amount.currency] = entryCurr = {
- ...balanceIdentity,
- };
+ balance.byCurrency[amount.currency] = entryCurr = { ...balanceIdentity
};
}
let entryEx = balance.byExchange[exchange];
if (!entryEx) {
@@ -2046,19 +1819,14 @@ export class Wallet {
if (!r.hasPayback) {
return balance;
}
- if (
- Amounts.cmp(smallestWithdraw[r.exchange_base_url], r.current_amount!) <
- 0
- ) {
+ if (Amounts.cmp(smallestWithdraw[r.exchange_base_url],
r.current_amount!) < 0) {
addTo(balance, "paybackAmount", r.current_amount!,
r.exchange_base_url);
}
return balance;
}
- function collectPendingRefresh(
- r: RefreshSessionRecord,
- balance: WalletBalance,
- ) {
+ function collectPendingRefresh(r: RefreshSessionRecord,
+ balance: WalletBalance) {
// Don't count finished refreshes, since the refresh already resulted
// in coins being added to the wallet.
if (r.finished) {
@@ -2074,20 +1842,13 @@ export class Wallet {
return balance;
}
for (const c of t.payReq.coins) {
- addTo(
- balance,
- "pendingPayment",
- Amounts.parseOrThrow(c.contribution),
- c.exchange_url,
- );
+ addTo(balance, "pendingPayment", Amounts.parseOrThrow(c.contribution),
c.exchange_url);
}
return balance;
}
- function collectSmallestWithdraw(
- e: JoinResult<ExchangeRecord, DenominationRecord>,
- sw: any,
- ) {
+ function collectSmallestWithdraw(e: JoinResult<ExchangeRecord,
DenominationRecord>,
+ sw: any) {
let min = sw[e.left.baseUrl];
const v = Amounts.add(e.right.value, e.right.feeWithdraw).amount;
if (!min) {
@@ -2105,26 +1866,31 @@ export class Wallet {
};
// Mapping from exchange pub to smallest
// possible amount we can withdraw
- let smallestWithdraw: { [baseUrl: string]: AmountJson } = {};
+ let smallestWithdraw: {[baseUrl: string]: AmountJson} = {};
- smallestWithdraw = await this.q()
- .iter(Stores.exchanges)
- .indexJoin(Stores.denominations.exchangeBaseUrlIndex, x => x.baseUrl)
- .fold(collectSmallestWithdraw, {});
+ smallestWithdraw = await (this.q()
+ .iter(Stores.exchanges)
+
.indexJoin(Stores.denominations.exchangeBaseUrlIndex,
+ (x) => x.baseUrl)
+ .fold(collectSmallestWithdraw, {}));
const tx = this.q();
- tx.iter(Stores.coins).fold(collectBalances, balanceStore);
- tx.iter(Stores.refresh).fold(collectPendingRefresh, balanceStore);
- tx.iter(Stores.reserves).fold(collectPendingWithdraw, balanceStore);
- tx.iter(Stores.reserves).fold(collectPaybacks, balanceStore);
- tx.iter(Stores.purchases).fold(collectPayments, balanceStore);
+ tx.iter(Stores.coins)
+ .fold(collectBalances, balanceStore);
+ tx.iter(Stores.refresh)
+ .fold(collectPendingRefresh, balanceStore);
+ tx.iter(Stores.reserves)
+ .fold(collectPendingWithdraw, balanceStore);
+ tx.iter(Stores.reserves)
+ .fold(collectPaybacks, balanceStore);
+ tx.iter(Stores.purchases)
+ .fold(collectPayments, balanceStore);
await tx.finish();
return balanceStore;
}
- async createRefreshSession(
- oldCoinPub: string,
- ): Promise<RefreshSessionRecord | undefined> {
+
+ async createRefreshSession(oldCoinPub: string):
Promise<RefreshSessionRecord|undefined> {
const coin = await this.q().get<CoinRecord>(Stores.coins, oldCoinPub);
if (!coin) {
@@ -2141,52 +1907,48 @@ export class Wallet {
throw Error("db inconsistent");
}
- const oldDenom = await this.q().get(Stores.denominations, [
- exchange.baseUrl,
- coin.denomPub,
- ]);
+ const oldDenom = await this.q().get(Stores.denominations,
+ [exchange.baseUrl, coin.denomPub]);
if (!oldDenom) {
throw Error("db inconsistent");
}
- const availableDenoms: DenominationRecord[] = await this.q()
- .iterIndex(Stores.denominations.exchangeBaseUrlIndex, exchange.baseUrl)
- .toArray();
+ const availableDenoms: DenominationRecord[] = await (
+ this.q()
+ .iterIndex(Stores.denominations.exchangeBaseUrlIndex,
+ exchange.baseUrl)
+ .toArray()
+ );
- const availableAmount = Amounts.sub(coin.currentAmount,
oldDenom.feeRefresh)
- .amount;
+ const availableAmount = Amounts.sub(coin.currentAmount,
+ oldDenom.feeRefresh).amount;
- const newCoinDenoms = getWithdrawDenomList(
- availableAmount,
- availableDenoms,
- );
+ const newCoinDenoms = getWithdrawDenomList(availableAmount,
+ availableDenoms);
console.log("refreshing coin", coin);
console.log("refreshing into", newCoinDenoms);
if (newCoinDenoms.length === 0) {
- console.log(
- `not refreshing, available amount ${amountToPretty(
- availableAmount,
- )} too small`,
- );
+ console.log(`not refreshing, available amount
${amountToPretty(availableAmount)} too small`);
coin.status = CoinStatus.Useless;
await this.q().put(Stores.coins, coin);
this.notifier.notify();
return undefined;
}
- const refreshSession: RefreshSessionRecord = await
this.cryptoApi.createRefreshSession(
- exchange.baseUrl,
- 3,
- coin,
- newCoinDenoms,
- oldDenom.feeRefresh,
- );
+
+ const refreshSession: RefreshSessionRecord = await (
+ this.cryptoApi.createRefreshSession(exchange.baseUrl,
+ 3,
+ coin,
+ newCoinDenoms,
+ oldDenom.feeRefresh));
function mutateCoin(c: CoinRecord): CoinRecord {
- const r = Amounts.sub(c.currentAmount, refreshSession.valueWithFee);
+ const r = Amounts.sub(c.currentAmount,
+ refreshSession.valueWithFee);
if (r.saturated) {
// Something else must have written the coin value
throw AbortTransaction;
@@ -2199,9 +1961,8 @@ export class Wallet {
// Store refresh session and subtract refreshed amount from
// coin in the same transaction.
const query = this.q();
- query
- .put(Stores.refresh, refreshSession, "refreshKey")
- .mutate(Stores.coins, coin.coinPub, mutateCoin);
+ query.put(Stores.refresh, refreshSession, "refreshKey")
+ .mutate(Stores.coins, coin.coinPub, mutateCoin);
await query.finish();
this.notifier.notify();
@@ -2215,10 +1976,10 @@ export class Wallet {
return refreshSession;
}
+
async refresh(oldCoinPub: string): Promise<void> {
- const oldRefreshSessions = await this.q()
- .iter(Stores.refresh)
- .toArray();
+
+ const oldRefreshSessions = await this.q().iter(Stores.refresh).toArray();
for (const session of oldRefreshSessions) {
console.log("got old session for", oldCoinPub, session);
this.continueRefreshSession(session);
@@ -2228,10 +1989,7 @@ export class Wallet {
console.warn("can't refresh, coin not in database");
return;
}
- if (
- coin.status === CoinStatus.Useless ||
- coin.status === CoinStatus.Fresh
- ) {
+ if (coin.status === CoinStatus.Useless || coin.status ===
CoinStatus.Fresh) {
return;
}
const refreshSession = await this.createRefreshSession(oldCoinPub);
@@ -2249,10 +2007,7 @@ export class Wallet {
}
if (typeof refreshSession.norevealIndex !== "number") {
await this.refreshMelt(refreshSession);
- const r = await this.q().get<RefreshSessionRecord>(
- Stores.refresh,
- refreshSession.id,
- );
+ const r = await this.q().get<RefreshSessionRecord>(Stores.refresh,
refreshSession.id);
if (!r) {
throw Error("refresh session does not exist anymore");
}
@@ -2262,24 +2017,21 @@ export class Wallet {
await this.refreshReveal(refreshSession);
}
+
async refreshMelt(refreshSession: RefreshSessionRecord): Promise<void> {
if (refreshSession.norevealIndex !== undefined) {
console.error("won't melt again");
return;
}
- const coin = await this.q().get<CoinRecord>(
- Stores.coins,
- refreshSession.meltCoinPub,
- );
+ const coin = await this.q().get<CoinRecord>(Stores.coins,
+ refreshSession.meltCoinPub);
if (!coin) {
console.error("can't melt coin, it does not exist");
return;
}
- const reqUrl = new URI("refresh/melt").absoluteTo(
- refreshSession.exchangeBaseUrl,
- );
+ const reqUrl = new
URI("refresh/melt").absoluteTo(refreshSession.exchangeBaseUrl);
const meltReq = {
coin_pub: coin.coinPub,
confirm_sig: refreshSession.confirmSig,
@@ -2312,12 +2064,11 @@ export class Wallet {
refreshSession.norevealIndex = norevealIndex;
- await this.q()
- .put(Stores.refresh, refreshSession)
- .finish();
+ await this.q().put(Stores.refresh, refreshSession).finish();
this.notifier.notify();
}
+
async refreshReveal(refreshSession: RefreshSessionRecord): Promise<void> {
const norevealIndex = refreshSession.norevealIndex;
if (norevealIndex === undefined) {
@@ -2331,40 +2082,17 @@ export class Wallet {
throw Error("refresh index error");
}
- const meltCoinRecord = await this.q().get(
- Stores.coins,
- refreshSession.meltCoinPub,
- );
- if (!meltCoinRecord) {
- throw Error("inconsistent database");
- }
-
const evs = preCoins.map((x: RefreshPreCoinRecord) => x.coinEv);
- const linkSigs: string[] = [];
- for (let i = 0; i < refreshSession.newDenoms.length; i++) {
- const linkSig = await this.cryptoApi.signCoinLink(
- meltCoinRecord.coinPriv,
- refreshSession.newDenomHashes[i],
- refreshSession.meltCoinPub,
- refreshSession.transferPubs[norevealIndex],
- preCoins[i].coinEv,
- );
- linkSigs.push(linkSig);
- }
-
const req = {
coin_evs: evs,
new_denoms_h: refreshSession.newDenomHashes,
rc: refreshSession.hash,
transfer_privs: privs,
transfer_pub: refreshSession.transferPubs[norevealIndex],
- link_sigs: linkSigs,
};
- const reqUrl = new URI("refresh/reveal").absoluteTo(
- refreshSession.exchangeBaseUrl,
- );
+ const reqUrl = new URI("refresh/reveal")
.absoluteTo(refreshSession.exchangeBaseUrl);
console.log("reveal request:", req);
const resp = await this.http.postJson(reqUrl.href(), req);
@@ -2382,10 +2110,8 @@ export class Wallet {
console.log("/refresh/reveal did not contain ev_sigs");
}
- const exchange = await this.q().get<ExchangeRecord>(
- Stores.exchanges,
- refreshSession.exchangeBaseUrl,
- );
+ const exchange = await this.q().get<ExchangeRecord>(Stores.exchanges,
+
refreshSession.exchangeBaseUrl);
if (!exchange) {
console.error(`exchange ${refreshSession.exchangeBaseUrl} not found`);
return;
@@ -2394,21 +2120,21 @@ export class Wallet {
const coins: CoinRecord[] = [];
for (let i = 0; i < respJson.ev_sigs.length; i++) {
- const denom = await this.q().get(Stores.denominations, [
- refreshSession.exchangeBaseUrl,
- refreshSession.newDenoms[i],
- ]);
+ const denom = await (
+ this.q()
+ .get(Stores.denominations,
+ [
+ refreshSession.exchangeBaseUrl,
+ refreshSession.newDenoms[i],
+ ]));
if (!denom) {
console.error("denom not found");
continue;
}
- const pc =
- refreshSession.preCoinsForGammas[refreshSession.norevealIndex!][i];
- const denomSig = await this.cryptoApi.rsaUnblind(
- respJson.ev_sigs[i].ev_sig,
- pc.blindingKey,
- denom.denomPub,
- );
+ const pc =
refreshSession.preCoinsForGammas[refreshSession.norevealIndex!][i];
+ const denomSig = await
this.cryptoApi.rsaUnblind(respJson.ev_sigs[i].ev_sig,
+ pc.blindingKey,
+ denom.denomPub);
const coin: CoinRecord = {
blindingKey: pc.blindingKey,
coinPriv: pc.privateKey,
@@ -2428,23 +2154,22 @@ export class Wallet {
refreshSession.finished = true;
await this.q()
- .putAll(Stores.coins, coins)
- .put(Stores.refresh, refreshSession)
- .finish();
+ .putAll(Stores.coins, coins)
+ .put(Stores.refresh, refreshSession)
+ .finish();
this.notifier.notify();
}
+
/**
* Retrive the full event history for this wallet.
*/
- async getHistory(): Promise<{ history: HistoryRecord[] }> {
+ async getHistory(): Promise<{history: HistoryRecord[]}> {
const history: HistoryRecord[] = [];
// FIXME: do pagination instead of generating the full history
- const proposals = await this.q()
- .iter<ProposalDownloadRecord>(Stores.proposals)
- .toArray();
+ const proposals = await
this.q().iter<ProposalDownloadRecord>(Stores.proposals).toArray();
for (const p of proposals) {
history.push({
detail: {
@@ -2456,9 +2181,7 @@ export class Wallet {
});
}
- const purchases = await this.q()
- .iter<PurchaseRecord>(Stores.purchases)
- .toArray();
+ const purchases = await
this.q().iter<PurchaseRecord>(Stores.purchases).toArray();
for (const p of purchases) {
history.push({
detail: {
@@ -2472,17 +2195,16 @@ export class Wallet {
});
if (p.timestamp_refund) {
const contractAmount = Amounts.parseOrThrow(p.contractTerms.amount);
- const amountsPending = Object.keys(p.refundsPending).map(x =>
- Amounts.parseOrThrow(p.refundsPending[x].refund_amount),
+ const amountsPending = (
+ Object.keys(p.refundsPending)
+ .map((x) =>
Amounts.parseOrThrow(p.refundsPending[x].refund_amount))
);
- const amountsDone = Object.keys(p.refundsDone).map(x =>
- Amounts.parseOrThrow(p.refundsDone[x].refund_amount),
+ const amountsDone = (
+ Object.keys(p.refundsDone)
+ .map((x) =>
Amounts.parseOrThrow(p.refundsDone[x].refund_amount))
);
const amounts: AmountJson[] = amountsPending.concat(amountsDone);
- const amount = Amounts.add(
- Amounts.getZero(contractAmount.currency),
- ...amounts,
- ).amount;
+ const amount = Amounts.add(Amounts.getZero(contractAmount.currency),
...amounts).amount;
history.push({
detail: {
@@ -2497,9 +2219,7 @@ export class Wallet {
}
}
- const reserves: ReserveRecord[] = await this.q()
- .iter<ReserveRecord>(Stores.reserves)
- .toArray();
+ const reserves: ReserveRecord[] = await
this.q().iter<ReserveRecord>(Stores.reserves).toArray();
for (const r of reserves) {
history.push({
detail: {
@@ -2523,9 +2243,7 @@ export class Wallet {
}
}
- const tips: TipRecord[] = await this.q()
- .iter<TipRecord>(Stores.tips)
- .toArray();
+ const tips: TipRecord[] = await
this.q().iter<TipRecord>(Stores.tips).toArray();
for (const tip of tips) {
history.push({
detail: {
@@ -2541,74 +2259,70 @@ export class Wallet {
history.sort((h1, h2) => Math.sign(h1.timestamp - h2.timestamp));
- return { history };
+ return {history};
}
async getDenoms(exchangeUrl: string): Promise<DenominationRecord[]> {
- const denoms = await this.q()
- .iterIndex(Stores.denominations.exchangeBaseUrlIndex, exchangeUrl)
- .toArray();
+ const denoms = await
this.q().iterIndex(Stores.denominations.exchangeBaseUrlIndex,
exchangeUrl).toArray();
return denoms;
}
- async getProposal(
- proposalId: number,
- ): Promise<ProposalDownloadRecord | undefined> {
+ async getProposal(proposalId: number):
Promise<ProposalDownloadRecord|undefined> {
const proposal = await this.q().get(Stores.proposals, proposalId);
return proposal;
}
async getExchanges(): Promise<ExchangeRecord[]> {
return this.q()
- .iter<ExchangeRecord>(Stores.exchanges)
- .toArray();
+ .iter<ExchangeRecord>(Stores.exchanges)
+ .toArray();
}
async getCurrencies(): Promise<CurrencyRecord[]> {
return this.q()
- .iter<CurrencyRecord>(Stores.currencies)
- .toArray();
+ .iter<CurrencyRecord>(Stores.currencies)
+ .toArray();
}
async updateCurrency(currencyRecord: CurrencyRecord): Promise<void> {
console.log("updating currency to", currencyRecord);
await this.q()
- .put(Stores.currencies, currencyRecord)
- .finish();
+ .put(Stores.currencies, currencyRecord)
+ .finish();
this.notifier.notify();
}
async getReserves(exchangeBaseUrl: string): Promise<ReserveRecord[]> {
return this.q()
- .iter<ReserveRecord>(Stores.reserves)
- .filter((r: ReserveRecord) => r.exchange_base_url === exchangeBaseUrl)
- .toArray();
+ .iter<ReserveRecord>(Stores.reserves)
+ .filter((r: ReserveRecord) => r.exchange_base_url ===
exchangeBaseUrl)
+ .toArray();
}
async getCoins(exchangeBaseUrl: string): Promise<CoinRecord[]> {
return this.q()
- .iter<CoinRecord>(Stores.coins)
- .filter((c: CoinRecord) => c.exchangeBaseUrl === exchangeBaseUrl)
- .toArray();
+ .iter<CoinRecord>(Stores.coins)
+ .filter((c: CoinRecord) => c.exchangeBaseUrl ===
exchangeBaseUrl)
+ .toArray();
}
async getPreCoins(exchangeBaseUrl: string): Promise<PreCoinRecord[]> {
return this.q()
- .iter<PreCoinRecord>(Stores.precoins)
- .filter((c: PreCoinRecord) => c.exchangeBaseUrl === exchangeBaseUrl)
- .toArray();
+ .iter<PreCoinRecord>(Stores.precoins)
+ .filter((c: PreCoinRecord) => c.exchangeBaseUrl ===
exchangeBaseUrl)
+ .toArray();
}
async hashContract(contract: ContractTerms): Promise<string> {
return this.cryptoApi.hashString(canonicalJson(contract));
}
- async getCurrencyRecord(
- currency: string,
- ): Promise<CurrencyRecord | undefined> {
+
+ async getCurrencyRecord(currency: string): Promise<CurrencyRecord|undefined>
{
return this.q().get(Stores.currencies, currency);
}
+
async payback(coinPub: string): Promise<void> {
let coin = await this.q().get(Stores.coins, coinPub);
if (!coin) {
@@ -2624,9 +2338,7 @@ export class Wallet {
}
switch (coin.status) {
case CoinStatus.Refreshed:
- throw Error(
- `Can't do payback for coin ${coinPub} since it's refreshed`,
- );
+ throw Error(`Can't do payback for coin ${coinPub} since it's
refreshed`);
case CoinStatus.PaybackDone:
console.log(`Coin ${coinPub} already payed back`);
return;
@@ -2636,9 +2348,7 @@ export class Wallet {
// technically we might update reserve status before we get the response
// from the reserve for the payback request.
reserve.hasPayback = true;
- await this.q()
- .put(Stores.coins, coin)
- .put(Stores.reserves, reserve);
+ await this.q().put(Stores.coins, coin).put(Stores.reserves, reserve);
this.notifier.notify();
const paybackRequest = await this.cryptoApi.createPaybackRequest(coin);
@@ -2647,9 +2357,7 @@ export class Wallet {
if (resp.status !== 200) {
throw Error();
}
- const paybackConfirmation = PaybackConfirmation.checked(
- JSON.parse(resp.responseText),
- );
+ const paybackConfirmation =
PaybackConfirmation.checked(JSON.parse(resp.responseText));
if (paybackConfirmation.reserve_pub !== coin.reservePub) {
throw Error(`Coin's reserve doesn't match reserve on payback`);
}
@@ -2663,10 +2371,8 @@ export class Wallet {
await this.updateReserve(reservePub!);
}
- async denominationRecordFromKeys(
- exchangeBaseUrl: string,
- denomIn: Denomination,
- ): Promise<DenominationRecord> {
+
+ async denominationRecordFromKeys(exchangeBaseUrl: string, denomIn:
Denomination): Promise<DenominationRecord> {
const denomPubHash = await this.cryptoApi.hashDenomPub(denomIn.denom_pub);
const d: DenominationRecord = {
denomPub: denomIn.denom_pub,
@@ -2699,10 +2405,7 @@ export class Wallet {
}
async getPaybackReserves(): Promise<ReserveRecord[]> {
- return await this.q()
- .iter(Stores.reserves)
- .filter(r => r.hasPayback)
- .toArray();
+ return await this.q().iter(Stores.reserves).filter((r) =>
r.hasPayback).toArray();
}
/**
@@ -2714,26 +2417,18 @@ export class Wallet {
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();
+ 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]);
- });
+ Object.keys(m).map((e) => { exchangeWireTypes[e] = Array.from(m[e]); });
const senderWiresSet = new Set();
- await this.q()
- .iter(Stores.senderWires)
- .map(x => {
+ await this.q().iter(Stores.senderWires).map((x) => {
senderWiresSet.add(x.paytoUri);
- })
- .run();
+ }).run();
const senderWires = Array.from(senderWiresSet);
return {
@@ -2753,7 +2448,7 @@ export class Wallet {
console.error(`wire type must be a non-empty string, not ${wireType}`);
return;
}
- const stampSecNow = Math.floor(new Date().getTime() / 1000);
+ 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`);
@@ -2769,17 +2464,13 @@ export class Wallet {
const { priv, pub } = await this.cryptoApi.createEddsaKeypair();
- const wireHash = await this.cryptoApi.hashString(
- canonicalJson(req.senderWire),
- );
+ const wireHash = await
this.cryptoApi.hashString(canonicalJson(req.senderWire));
const contractTerms: ContractTerms = {
H_wire: wireHash,
amount: Amounts.toString(req.amount),
auditors: [],
- exchanges: [
- { master_pub: exchange.masterPublicKey, url: exchange.baseUrl },
- ],
+ exchanges: [ { master_pub: exchange.masterPublicKey, url:
exchange.baseUrl } ],
extra: {},
fulfillment_url: "",
locations: [],
@@ -2795,19 +2486,15 @@ export class Wallet {
wire_method: wireType,
};
- const contractTermsHash = await this.cryptoApi.hashString(
- canonicalJson(contractTerms),
- );
+ const contractTermsHash = await
this.cryptoApi.hashString(canonicalJson(contractTerms));
- const payCoinInfo = await this.cryptoApi.signDeposit(
- contractTerms,
- cds,
- Amounts.parseOrThrow(contractTerms.amount),
+ const payCoinInfo = await (
+ this.cryptoApi.signDeposit(contractTerms, cds,
Amounts.parseOrThrow(contractTerms.amount))
);
console.log("pci", payCoinInfo);
- const coins = payCoinInfo.sigs.map(s => ({ coinPaySig: s }));
+ const coins = payCoinInfo.sigs.map((s) => ({ coinPaySig: s }));
const coinsReturnRecord: CoinsReturnRecord = {
coins,
@@ -2819,18 +2506,16 @@ export class Wallet {
};
await this.q()
- .put(Stores.coinsReturns, coinsReturnRecord)
- .putAll(Stores.coins, payCoinInfo.updatedCoins)
- .finish();
+ .put(Stores.coinsReturns, coinsReturnRecord)
+ .putAll(Stores.coins, payCoinInfo.updatedCoins)
+ .finish();
this.badge.showNotification();
this.notifier.notify();
this.depositReturnedCoins(coinsReturnRecord);
}
- async depositReturnedCoins(
- coinsReturnRecord: CoinsReturnRecord,
- ): Promise<void> {
+ async depositReturnedCoins(coinsReturnRecord: CoinsReturnRecord):
Promise<void> {
for (const c of coinsReturnRecord.coins) {
if (c.depositedSig) {
continue;
@@ -2851,7 +2536,7 @@ export class Wallet {
wire_transfer_deadline: coinsReturnRecord.contractTerms.pay_deadline,
};
console.log("req", req);
- const reqUrl = new URI("deposit").absoluteTo(coinsReturnRecord.exchange);
+ 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);
@@ -2871,10 +2556,7 @@ export class Wallet {
// 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,
- );
+ const currentCrr = await this.q().get(Stores.coinsReturns,
coinsReturnRecord.contractTermsHash);
if (!currentCrr) {
console.error("database inconsistent");
continue;
@@ -2889,9 +2571,7 @@ export class Wallet {
}
}
- async acceptRefundResponse(
- refundResponse: MerchantRefundResponse,
- ): Promise<string> {
+ async acceptRefundResponse(refundResponse: MerchantRefundResponse):
Promise<string> {
const refundPermissions = refundResponse.refund_permissions;
if (!refundPermissions.length) {
@@ -2902,19 +2582,16 @@ export class Wallet {
/**
* Add refund to purchase if not already added.
*/
- function f(t: PurchaseRecord | undefined): PurchaseRecord | undefined {
+ function f(t: PurchaseRecord|undefined): PurchaseRecord|undefined {
if (!t) {
console.error("purchase not found, not adding refunds");
return;
}
- t.timestamp_refund = new Date().getTime();
+ t.timestamp_refund = (new Date()).getTime();
for (const perm of refundPermissions) {
- if (
- !t.refundsPending[perm.merchant_sig] &&
- !t.refundsDone[perm.merchant_sig]
- ) {
+ if (!t.refundsPending[perm.merchant_sig] &&
!t.refundsDone[perm.merchant_sig]) {
t.refundsPending[perm.merchant_sig] = perm;
}
}
@@ -2924,9 +2601,7 @@ export class Wallet {
const hc = refundResponse.h_contract_terms;
// Add the refund permissions to the purchase within a DB transaction
- await this.q()
- .mutate(Stores.purchases, hc, f)
- .finish();
+ await this.q().mutate(Stores.purchases, hc, f).finish();
this.notifier.notify();
// Start submitting it but don't wait for it here.
@@ -2935,6 +2610,7 @@ export class Wallet {
return hc;
}
+
/**
* Accept a refund, return the contract hash for the contract
* that was involved in the refund.
@@ -2956,13 +2632,11 @@ export class Wallet {
return this.acceptRefundResponse(refundResponse);
}
+
private async submitRefunds(contractTermsHash: string): Promise<void> {
const purchase = await this.q().get(Stores.purchases, contractTermsHash);
if (!purchase) {
- console.error(
- "not submitting refunds, contract terms not found:",
- contractTermsHash,
- );
+ console.error("not submitting refunds, contract terms not found:",
contractTermsHash);
return;
}
const pendingKeys = Object.keys(purchase.refundsPending);
@@ -2983,7 +2657,7 @@ export class Wallet {
console.log("sending refund permission", perm);
// FIXME: not correct once we support multiple exchanges per payment
const exchangeUrl = purchase.payReq.coins[0].exchange_url;
- const reqUrl = new URI("refund").absoluteTo(exchangeUrl);
+ const reqUrl = (new URI("refund")).absoluteTo(exchangeUrl);
const resp = await this.http.postJson(reqUrl.href(), req);
if (resp.status !== 200) {
console.error("refund failed", resp);
@@ -2991,9 +2665,7 @@ export class Wallet {
}
// Transactionally mark successful refunds as done
- const transformPurchase = (
- t: PurchaseRecord | undefined,
- ): PurchaseRecord | undefined => {
+ const transformPurchase = (t: PurchaseRecord|undefined):
PurchaseRecord|undefined => {
if (!t) {
console.warn("purchase not found, not updating refund");
return;
@@ -3004,9 +2676,7 @@ export class Wallet {
}
return t;
};
- const transformCoin = (
- c: CoinRecord | undefined,
- ): CoinRecord | undefined => {
+ const transformCoin = (c: CoinRecord|undefined): CoinRecord|undefined =>
{
if (!c) {
console.warn("coin not found, can't apply refund");
return;
@@ -3021,9 +2691,9 @@ export class Wallet {
};
await this.q()
- .mutate(Stores.purchases, contractTermsHash, transformPurchase)
- .mutate(Stores.coins, perm.coin_pub, transformCoin)
- .finish();
+ .mutate(Stores.purchases, contractTermsHash, transformPurchase)
+ .mutate(Stores.coins, perm.coin_pub, transformCoin)
+ .finish();
this.refresh(perm.coin_pub);
}
@@ -3031,44 +2701,27 @@ export class Wallet {
this.notifier.notify();
}
- async getPurchase(
- contractTermsHash: string,
- ): Promise<PurchaseRecord | undefined> {
+ async getPurchase(contractTermsHash: string):
Promise<PurchaseRecord|undefined> {
return this.q().get(Stores.purchases, contractTermsHash);
}
- async getFullRefundFees(
- refundPermissions: MerchantRefundPermission[],
- ): Promise<AmountJson> {
+ async getFullRefundFees(refundPermissions: MerchantRefundPermission[]):
Promise<AmountJson> {
if (refundPermissions.length === 0) {
throw Error("no refunds given");
}
- const coin0 = await this.q().get(
- Stores.coins,
- refundPermissions[0].coin_pub,
- );
+ const coin0 = await this.q().get(Stores.coins,
refundPermissions[0].coin_pub);
if (!coin0) {
throw Error("coin not found");
}
- let feeAcc = Amounts.getZero(
- Amounts.parseOrThrow(refundPermissions[0].refund_amount).currency,
- );
+ let feeAcc =
Amounts.getZero(Amounts.parseOrThrow(refundPermissions[0].refund_amount).currency);
- const denoms = await this.q()
- .iterIndex(
- Stores.denominations.exchangeBaseUrlIndex,
- coin0.exchangeBaseUrl,
- )
- .toArray();
+ const denoms = await
this.q().iterIndex(Stores.denominations.exchangeBaseUrlIndex,
coin0.exchangeBaseUrl).toArray();
for (const rp of refundPermissions) {
const coin = await this.q().get(Stores.coins, rp.coin_pub);
if (!coin) {
throw Error("coin not found");
}
- const denom = await this.q().get(Stores.denominations, [
- coin0.exchangeBaseUrl,
- coin.denomPub,
- ]);
+ const denom = await this.q().get(Stores.denominations,
[coin0.exchangeBaseUrl, coin.denomPub]);
if (!denom) {
throw Error(`denom not found (${coin.denomPub})`);
}
@@ -3078,16 +2731,13 @@ export class Wallet {
// refreshed normally (and what about incremental refunds?)
const refundAmount = Amounts.parseOrThrow(rp.refund_amount);
const refundFee = Amounts.parseOrThrow(rp.refund_fee);
- const refreshCost = getTotalRefreshCost(
- denoms,
- denom,
- Amounts.sub(refundAmount, refundFee).amount,
- );
+ const refreshCost = getTotalRefreshCost(denoms, denom,
Amounts.sub(refundAmount, refundFee).amount);
feeAcc = Amounts.add(feeAcc, refreshCost, refundFee).amount;
}
return feeAcc;
}
+
async processTip(tipToken: TipToken): Promise<TipRecord> {
const merchantDomain = new URI(tipToken.pickup_url).origin();
const key = tipToken.tip_id + merchantDomain;
@@ -3104,6 +2754,7 @@ export class Wallet {
}
}
+
private async processTipImpl(tipToken: TipToken): Promise<TipRecord> {
console.log("got tip token", tipToken);
@@ -3114,25 +2765,17 @@ export class Wallet {
throw Error("tipping failed (invalid expiration)");
}
- let tipRecord = await this.q().get(Stores.tips, [
- tipToken.tip_id,
- merchantDomain,
- ]);
+ let tipRecord = await this.q().get(Stores.tips, [tipToken.tip_id,
merchantDomain]);
if (tipRecord && tipRecord.pickedUp) {
return tipRecord;
}
const tipAmount = Amounts.parseOrThrow(tipToken.amount);
await this.updateExchangeFromUrl(tipToken.exchange_url);
- const denomsForWithdraw = await this.getVerifiedWithdrawDenomList(
- tipToken.exchange_url,
- tipAmount,
- );
- const planchets = await Promise.all(
- denomsForWithdraw.map(d => this.cryptoApi.createTipPlanchet(d)),
- );
+ const denomsForWithdraw = await
this.getVerifiedWithdrawDenomList(tipToken.exchange_url, tipAmount);
+ const planchets = await Promise.all(denomsForWithdraw.map(d =>
this.cryptoApi.createTipPlanchet(d)));
const coinPubs: string[] = planchets.map(x => x.coinPub);
- const now = new Date().getTime();
+ const now = (new Date()).getTime();
tipRecord = {
accepted: false,
amount: Amounts.parseOrThrow(tipToken.amount),
@@ -3149,14 +2792,11 @@ export class Wallet {
let merchantResp;
- tipRecord = await this.q().putOrGetExisting(Stores.tips, tipRecord, [
- tipRecord.tipId,
- merchantDomain,
- ]);
+ tipRecord = await this.q().putOrGetExisting(Stores.tips, tipRecord,
[tipRecord.tipId, merchantDomain]);
this.notifier.notify();
// Planchets in the form that the merchant expects
- const planchetsDetail: TipPlanchetDetail[] = tipRecord.planchets.map(p =>
({
+ const planchetsDetail: TipPlanchetDetail[] = tipRecord.planchets.map((p)
=> ({
coin_ev: p.coinEv,
denom_pub_hash: p.denomPubHash,
}));
@@ -3199,14 +2839,13 @@ export class Wallet {
tipRecord.pickedUp = true;
- await this.q()
- .put(Stores.tips, tipRecord)
- .finish();
+ await this.q().put(Stores.tips, tipRecord).finish();
this.notifier.notify();
return tipRecord;
}
+
/**
* Start using the coins from a tip.
*/
@@ -3242,6 +2881,7 @@ export class Wallet {
this.notifier.notify();
}
+
async getTipStatus(tipToken: TipToken): Promise<TipStatus> {
const tipId = tipToken.tip_id;
const merchantDomain = new URI(tipToken.pickup_url).origin();
@@ -3261,6 +2901,7 @@ export class Wallet {
return tipStatus;
}
+
async abortFailedPayment(contractTermsHash: string): Promise<void> {
const purchase = await this.q().get(Stores.purchases, contractTermsHash);
if (!purchase) {
@@ -3288,7 +2929,7 @@ export class Wallet {
try {
const config = {
headers: { "Content-Type": "application/json;charset=UTF-8" },
- timeout: 5000 /* 5 seconds */,
+ timeout: 5000, /* 5 seconds */
validateStatus: (s: number) => s === 200,
};
resp = await axios.post(purchase.contractTerms.pay_url, abortReq,
config);
@@ -3305,13 +2946,10 @@ export class Wallet {
p.abortDone = true;
return p;
};
- await this.q().mutate(
- Stores.purchases,
- purchase.contractTermsHash,
- markAbortDone,
- );
+ await this.q().mutate(Stores.purchases, purchase.contractTermsHash,
markAbortDone);
}
+
/**
* Synchronously get the paid URL for a resource from the plain fulfillment
* URL. Returns undefined if the fulfillment URL is not a resource that was
@@ -3327,7 +2965,7 @@ export class Wallet {
* based on the current system time.
*/
async collectGarbage() {
- const nowMilli = new Date().getTime();
+ const nowMilli = (new Date()).getTime();
const nowSec = Math.floor(nowMilli / 1000);
const gcReserve = (r: ReserveRecord, n: number) => {
@@ -3340,35 +2978,28 @@ export class Wallet {
}
return false;
};
- await this.q()
- .deleteIf(Stores.reserves, gcReserve)
- .finish();
+ await this.q().deleteIf(Stores.reserves, gcReserve).finish();
const gcProposal = (d: ProposalDownloadRecord, n: number) => {
// Delete proposal after 60 minutes or 5 minutes before pay deadline,
// whatever comes first.
- const deadlinePayMilli =
- getTalerStampSec(d.contractTerms.pay_deadline)! * 1000;
- const deadlineExpireMilli = nowMilli + 1000 * 60 * 60;
+ const deadlinePayMilli = getTalerStampSec(d.contractTerms.pay_deadline)!
* 1000;
+ const deadlineExpireMilli = nowMilli + (1000 * 60 * 60);
return d.timestamp < Math.min(deadlinePayMilli, deadlineExpireMilli);
};
- await this.q()
- .deleteIf(Stores.proposals, gcProposal)
- .finish();
+ await this.q().deleteIf(Stores.proposals, gcProposal).finish();
const activeExchanges: string[] = [];
const gcExchange = (d: ExchangeRecord, n: number) => {
// Delete if if unused and last update more than 20 minutes ago
- if (!d.lastUsedTime && nowMilli > d.lastUpdateTime + 1000 * 60 * 20) {
+ if (!d.lastUsedTime && nowMilli > d.lastUpdateTime + (1000 * 60 * 20)) {
return true;
}
activeExchanges.push(d.baseUrl);
return false;
};
- await this.q()
- .deleteIf(Stores.exchanges, gcExchange)
- .finish();
+ await this.q().deleteIf(Stores.exchanges, gcExchange).finish();
const gcDenominations = (d: DenominationRecord, n: number) => {
if (nowSec > getTalerStampSec(d.stampExpireDeposit)!) {
@@ -3379,9 +3010,7 @@ export class Wallet {
}
return false;
};
- await this.q()
- .deleteIf(Stores.denominations, gcDenominations)
- .finish();
+ await this.q().deleteIf(Stores.denominations, gcDenominations).finish();
const gcWireFees = (r: ExchangeWireFeesRecord, n: number) => {
if (activeExchanges.indexOf(r.exchangeBaseUrl) < 0) {
@@ -3389,9 +3018,8 @@ export class Wallet {
}
return false;
};
- await this.q()
- .deleteIf(Stores.exchangeWireFees, gcWireFees)
- .finish();
+ await this.q().deleteIf(Stores.exchangeWireFees, gcWireFees).finish();
+
// FIXME(#5210) also GC coins
}
--
To stop receiving notification emails like this one, please contact
address@hidden.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] [taler-wallet-webex] branch master updated: Revert "add config for code formatter (prettier)",
gnunet <=