aboutsummaryrefslogtreecommitdiff
path: root/src/wallet.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet.ts')
-rw-r--r--src/wallet.ts842
1 files changed, 428 insertions, 414 deletions
diff --git a/src/wallet.ts b/src/wallet.ts
index a2a9e83f5..b21cdbd96 100644
--- a/src/wallet.ts
+++ b/src/wallet.ts
@@ -22,57 +22,58 @@
/**
* Imports.
*/
+import {Checkable} from "./checkable";
+import {CryptoApi} from "./crypto/cryptoApi";
+import {
+ amountToPretty,
+ canonicalJson,
+ canonicalizeBaseUrl,
+ deepEquals,
+ flatMap,
+ getTalerStampSec,
+} from "./helpers";
+import {
+ HttpRequestLibrary,
+ HttpResponse,
+ RequestException,
+} from "./http";
+import {
+ AbortTransaction,
+ Index,
+ JoinLeftResult,
+ JoinResult,
+ QueryRoot,
+ Store,
+} from "./query";
import {
AmountJson,
Amounts,
- CoinRecord,
+ Auditor,
+ AuditorRecord,
CoinPaySig,
+ CoinRecord,
+ CoinStatus,
Contract,
CreateReserveResponse,
+ CurrencyRecord,
Denomination,
+ DenominationRecord,
+ DenominationStatus,
ExchangeHandle,
ExchangeRecord,
+ ExchangeWireFeesRecord,
Notifier,
PayCoinInfo,
+ PaybackConfirmation,
PreCoinRecord,
RefreshSessionRecord,
ReserveCreationInfo,
ReserveRecord,
- CurrencyRecord,
- Auditor,
- AuditorRecord,
WalletBalance,
WalletBalanceEntry,
WireFee,
- ExchangeWireFeesRecord,
WireInfo,
- DenominationRecord,
- DenominationStatus,
- CoinStatus,
- PaybackConfirmation,
} from "./types";
-import {
- HttpRequestLibrary,
- HttpResponse,
- RequestException,
-} from "./http";
-import {
- AbortTransaction,
- Index,
- JoinResult,
- QueryRoot,
- Store, JoinLeftResult,
-} from "./query";
-import {Checkable} from "./checkable";
-import {
- amountToPretty,
- canonicalizeBaseUrl,
- canonicalJson,
- deepEquals,
- flatMap,
- getTalerStampSec,
-} from "./helpers";
-import {CryptoApi} from "./crypto/cryptoApi";
import URI = require("urijs");
@@ -272,33 +273,31 @@ export interface ConfigRecord {
}
-
const builtinCurrencies: CurrencyRecord[] = [
{
- name: "KUDOS",
- fractionalDigits: 2,
auditors: [
{
+ auditorPub: "XN9KMN5G2KGPCAN0E89MM5HE8FV4WBWA9KDTMTDR817MWBCYA7H0",
baseUrl: "https://auditor.demo.taler.net/",
expirationStamp: (new Date(2027, 1)).getTime(),
- auditorPub: "XN9KMN5G2KGPCAN0E89MM5HE8FV4WBWA9KDTMTDR817MWBCYA7H0",
},
],
exchanges: [],
+ fractionalDigits: 2,
+ name: "KUDOS",
},
{
- name: "PUDOS",
- fractionalDigits: 2,
auditors: [
],
exchanges: [
{ baseUrl: "https://exchange.test.taler.net/", priority: 0 },
],
+ fractionalDigits: 2,
+ name: "PUDOS",
},
];
-
// FIXME: these functions should be dependency-injected
// into the wallet, as this is chrome specific => bad
@@ -312,17 +311,17 @@ function setInterval(f: any, t: number) {
function isWithdrawableDenom(d: DenominationRecord) {
- const now_sec = (new Date).getTime() / 1000;
- const stamp_withdraw_sec = getTalerStampSec(d.stampExpireWithdraw);
- if (stamp_withdraw_sec == null) {
+ const nowSec = (new Date()).getTime() / 1000;
+ const stampWithdrawSec = getTalerStampSec(d.stampExpireWithdraw);
+ if (stampWithdrawSec === null) {
return false;
}
- const stamp_start_sec = getTalerStampSec(d.stampStart);
- if (stamp_start_sec == null) {
+ const stampStartSec = getTalerStampSec(d.stampStart);
+ if (stampStartSec === null) {
return false;
}
// Withdraw if still possible to withdraw within a minute
- if ((stamp_withdraw_sec + 60 > now_sec) && (now_sec >= stamp_start_sec)) {
+ if ((stampWithdrawSec + 60 > nowSec) && (nowSec >= stampStartSec)) {
return true;
}
return false;
@@ -333,31 +332,30 @@ export type CoinSelectionResult = {exchangeUrl: string, cds: CoinWithDenom[]}|un
export function selectCoins(cds: CoinWithDenom[], paymentAmount: AmountJson,
depositFeeLimit: AmountJson): CoinWithDenom[]|undefined {
- if (cds.length == 0) {
+ if (cds.length === 0) {
return undefined;
}
// Sort by ascending deposit fee
cds.sort((o1, o2) => Amounts.cmp(o1.denom.feeDeposit,
o2.denom.feeDeposit));
- let currency = cds[0].denom.value.currency;
- let cdsResult: CoinWithDenom[] = [];
+ const currency = cds[0].denom.value.currency;
+ const cdsResult: CoinWithDenom[] = [];
let accFee: AmountJson = Amounts.getZero(currency);
let accAmount: AmountJson = Amounts.getZero(currency);
let isBelowFee = false;
let coversAmount = false;
let coversAmountWithFee = false;
- for (let i = 0; i < cds.length; i++) {
- let {coin, denom} = cds[i];
+ for (const {coin, denom} of cds) {
if (coin.suspended) {
continue;
}
- if (coin.status != CoinStatus.Fresh) {
+ if (coin.status !== CoinStatus.Fresh) {
continue;
}
if (Amounts.cmp(denom.feeDeposit, coin.currentAmount) >= 0) {
continue;
}
- cdsResult.push(cds[i]);
+ cdsResult.push({coin, denom});
accFee = Amounts.add(denom.feeDeposit, accFee).amount;
accAmount = Amounts.add(coin.currentAmount, accAmount).amount;
coversAmount = Amounts.cmp(accAmount, paymentAmount) >= 0;
@@ -391,8 +389,8 @@ function getWithdrawDenomList(amountAvailable: AmountJson,
// is useful ...
for (let i = 0; i < 1000; i++) {
let found = false;
- for (let d of denoms) {
- let cost = Amounts.add(d.value, d.feeWithdraw).amount;
+ for (const d of denoms) {
+ const cost = Amounts.add(d.value, d.feeWithdraw).amount;
if (Amounts.cmp(remaining, cost) < 0) {
continue;
}
@@ -415,7 +413,7 @@ export namespace Stores {
super("exchanges", {keyPath: "baseUrl"});
}
- pubKeyIndex = new Index<string,ExchangeRecord>(this, "pubKey", "masterPublicKey");
+ pubKeyIndex = new Index<string, ExchangeRecord>(this, "pubKey", "masterPublicKey");
}
class NonceStore extends Store<NonceRecord> {
@@ -429,26 +427,26 @@ export namespace Stores {
super("coins", {keyPath: "coinPub"});
}
- exchangeBaseUrlIndex = new Index<string,CoinRecord>(this, "exchangeBaseUrl", "exchangeBaseUrl");
- denomPubIndex = new Index<string,CoinRecord>(this, "denomPub", "denomPub");
+ exchangeBaseUrlIndex = new Index<string, CoinRecord>(this, "exchangeBaseUrl", "exchangeBaseUrl");
+ denomPubIndex = new Index<string, CoinRecord>(this, "denomPub", "denomPub");
}
class HistoryStore extends Store<HistoryRecord> {
constructor() {
super("history", {
+ autoIncrement: true,
keyPath: "id",
- autoIncrement: true
});
}
- timestampIndex = new Index<number,HistoryRecord>(this, "timestamp", "timestamp");
+ timestampIndex = new Index<number, HistoryRecord>(this, "timestamp", "timestamp");
}
class OffersStore extends Store<OfferRecord> {
constructor() {
super("offers", {
+ autoIncrement: true,
keyPath: "id",
- autoIncrement: true
});
}
}
@@ -458,8 +456,8 @@ export namespace Stores {
super("transactions", {keyPath: "contractHash"});
}
- fulfillmentUrlIndex = new Index<string,TransactionRecord>(this, "fulfillment_url", "contract.fulfillment_url");
- orderIdIndex = new Index<string,TransactionRecord>(this, "order_id", "contract.order_id");
+ fulfillmentUrlIndex = new Index<string, TransactionRecord>(this, "fulfillment_url", "contract.fulfillment_url");
+ orderIdIndex = new Index<string, TransactionRecord>(this, "order_id", "contract.order_id");
}
class DenominationsStore extends Store<DenominationRecord> {
@@ -469,7 +467,7 @@ export namespace Stores {
{keyPath: ["exchangeBaseUrl", "denomPub"] as any as IDBKeyPath});
}
- denomPubHashIndex = new Index<string,DenominationRecord>(this, "denomPubHash", "denomPubHash");
+ denomPubHashIndex = new Index<string, DenominationRecord>(this, "denomPubHash", "denomPubHash");
exchangeBaseUrlIndex = new Index<string, DenominationRecord>(this, "exchangeBaseUrl", "exchangeBaseUrl");
denomPubIndex = new Index<string, DenominationRecord>(this, "denomPub", "denomPub");
}
@@ -491,19 +489,31 @@ export namespace Stores {
super("exchangeWireFees", {keyPath: "exchangeBaseUrl"});
}
}
- export const exchanges: ExchangeStore = new ExchangeStore();
- export const exchangeWireFees: ExchangeWireFeesStore = new ExchangeWireFeesStore();
- export const nonces: NonceStore = new NonceStore();
- export const transactions: TransactionsStore = new TransactionsStore();
- export const reserves: Store<ReserveRecord> = new Store<ReserveRecord>("reserves", {keyPath: "reserve_pub"});
- export const coins: CoinsStore = new CoinsStore();
- export const refresh: Store<RefreshSessionRecord> = new Store<RefreshSessionRecord>("refresh", {keyPath: "meltCoinPub"});
- export const history: HistoryStore = new HistoryStore();
- export const offers: OffersStore = new OffersStore();
- export const precoins: Store<PreCoinRecord> = new Store<PreCoinRecord>("precoins", {keyPath: "coinPub"});
- export const denominations: DenominationsStore = new DenominationsStore();
- export const currencies: CurrenciesStore = new CurrenciesStore();
- export const config: ConfigStore = new ConfigStore();
+ export const exchanges = new ExchangeStore();
+ export const exchangeWireFees = new ExchangeWireFeesStore();
+ export const nonces = new NonceStore();
+ export const transactions = new TransactionsStore();
+ export const reserves = new Store<ReserveRecord>("reserves", {keyPath: "reserve_pub"});
+ export const coins = new CoinsStore();
+ export const refresh = new Store<RefreshSessionRecord>("refresh", {keyPath: "meltCoinPub"});
+ export const history = new HistoryStore();
+ export const offers = new OffersStore();
+ export const precoins = new Store<PreCoinRecord>("precoins", {keyPath: "coinPub"});
+ export const denominations = new DenominationsStore();
+ export const currencies = new CurrenciesStore();
+ export const config = new ConfigStore();
+}
+
+
+interface CoinsForPaymentArgs {
+ allowedAuditors: Auditor[];
+ allowedExchanges: ExchangeHandle[];
+ depositFeeLimit: AmountJson;
+ paymentAmount: AmountJson;
+ wireFeeAmortization: number;
+ wireFeeLimit: AmountJson;
+ wireFeeTime: number;
+ wireMethod: string;
}
@@ -543,10 +553,10 @@ export class Wallet {
}
private async fillDefaults() {
- let onTrue = (r: QueryRoot) => {
+ const onTrue = (r: QueryRoot) => {
console.log("defaults already applied");
};
- let onFalse = (r: QueryRoot) => {
+ const onFalse = (r: QueryRoot) => {
console.log("applying defaults");
r.put(Stores.config, {key: "currencyDefaultsApplied", value: true})
.putAll(Stores.currencies, builtinCurrencies)
@@ -555,7 +565,7 @@ export class Wallet {
await (
this.q()
.iter(Stores.config)
- .filter(x => x.key == "currencyDefaultsApplied")
+ .filter((x) => x.key === "currencyDefaultsApplied")
.first()
.cond((x) => x && x.value, onTrue, onFalse)
);
@@ -569,7 +579,7 @@ export class Wallet {
private stopOperation(operationId: string) {
this.runningOperations.delete(operationId);
- if (this.runningOperations.size == 0) {
+ if (this.runningOperations.size === 0) {
this.badge.stopBusy();
}
}
@@ -577,12 +587,12 @@ export class Wallet {
async updateExchanges(): Promise<void> {
console.log("updating exchanges");
- let exchangesUrls = await this.q()
- .iter(Stores.exchanges)
- .map((e) => e.baseUrl)
- .toArray();
+ const exchangesUrls = await this.q()
+ .iter(Stores.exchanges)
+ .map((e) => e.baseUrl)
+ .toArray();
- for (let url of exchangesUrls) {
+ for (const url of exchangesUrls) {
this.updateExchangeFromUrl(url)
.catch((e) => {
console.error("updating exchange failed", e);
@@ -621,7 +631,7 @@ export class Wallet {
this.q()
.iter(Stores.coins)
.reduce((c: CoinRecord) => {
- if (c.status == CoinStatus.Dirty) {
+ if (c.status === CoinStatus.Dirty) {
console.log("resuming pending refresh for coin", c);
this.refresh(c.coinPub);
}
@@ -633,23 +643,28 @@ export class Wallet {
* 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(paymentAmount: AmountJson,
- wireMethod: string,
- wireFeeTime: number,
- depositFeeLimit: AmountJson,
- wireFeeLimit: AmountJson,
- wireFeeAmortization: number,
- allowedExchanges: ExchangeHandle[],
- allowedAuditors: Auditor[]): Promise<CoinSelectionResult> {
-
- let exchanges = await this.q().iter(Stores.exchanges).toArray();
-
- for (let exchange of exchanges) {
+ private async getCoinsForPayment(args: CoinsForPaymentArgs): Promise<CoinSelectionResult> {
+ const {
+ allowedAuditors,
+ allowedExchanges,
+ depositFeeLimit,
+ paymentAmount,
+ wireFeeAmortization,
+ wireFeeLimit,
+ wireFeeTime,
+ wireMethod,
+ } = args;
+
+ let remainingAmount = paymentAmount;
+
+ const exchanges = await this.q().iter(Stores.exchanges).toArray();
+
+ for (const exchange of exchanges) {
let isOkay: boolean = false;
// is the exchange explicitly allowed?
- for (let allowedExchange of allowedExchanges) {
- if (allowedExchange.master_pub == exchange.masterPublicKey) {
+ for (const allowedExchange of allowedExchanges) {
+ if (allowedExchange.master_pub === exchange.masterPublicKey) {
isOkay = true;
break;
}
@@ -657,9 +672,9 @@ export class Wallet {
// is the exchange allowed because of one of its auditors?
if (!isOkay) {
- for (let allowedAuditor of allowedAuditors) {
- for (let auditor of exchange.auditors) {
- if (auditor.auditor_pub == allowedAuditor.auditor_pub) {
+ for (const allowedAuditor of allowedAuditors) {
+ for (const auditor of exchange.auditors) {
+ if (auditor.auditor_pub === allowedAuditor.auditor_pub) {
isOkay = true;
break;
}
@@ -674,53 +689,52 @@ export class Wallet {
continue;
}
- let coins: CoinRecord[] = await this.q()
+ const coins: CoinRecord[] = await this.q()
.iterIndex(Stores.coins.exchangeBaseUrlIndex,
exchange.baseUrl)
.toArray();
- if (!coins || coins.length == 0) {
+ if (!coins || coins.length === 0) {
continue;
}
// Denomination of the first coin, we assume that all other
// coins have the same currency
- let 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");
}
- let currency = firstDenom.value.currency;
- let cds: CoinWithDenom[] = [];
- for (let i = 0; i < coins.length; i++) {
- let coin = coins[i];
- let denom = await this.q().get(Stores.denominations,
+ const currency = firstDenom.value.currency;
+ const cds: CoinWithDenom[] = [];
+ for (const coin of coins) {
+ const denom = await this.q().get(Stores.denominations,
[exchange.baseUrl, coin.denomPub]);
if (!denom) {
throw Error("db inconsistent");
}
- if (denom.value.currency != currency) {
+ if (denom.value.currency !== currency) {
console.warn(`same pubkey for different currencies at exchange ${exchange.baseUrl}`);
continue;
}
if (coin.suspended) {
continue;
}
- if (coin.status != CoinStatus.Fresh) {
+ if (coin.status !== CoinStatus.Fresh) {
continue;
}
cds.push({coin, denom});
}
- let 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;
}
- let wireFee: AmountJson|undefined = undefined;
- for (let 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;
@@ -728,18 +742,18 @@ export class Wallet {
}
if (wireFee) {
- let amortizedWireFee = Amounts.divide(wireFee, wireFeeAmortization);
+ const amortizedWireFee = Amounts.divide(wireFee, wireFeeAmortization);
if (Amounts.cmp(wireFeeLimit, amortizedWireFee) < 0) {
- paymentAmount = Amounts.add(amortizedWireFee, paymentAmount).amount;
+ remainingAmount = Amounts.add(amortizedWireFee, remainingAmount).amount;
}
}
- let res = selectCoins(cds, paymentAmount, depositFeeLimit);
+ const res = selectCoins(cds, remainingAmount, depositFeeLimit);
if (res) {
return {
- exchangeUrl: exchange.baseUrl,
cds: res,
- }
+ exchangeUrl: exchange.baseUrl,
+ };
}
}
return undefined;
@@ -753,31 +767,31 @@ export class Wallet {
private async recordConfirmPay(offer: OfferRecord,
payCoinInfo: PayCoinInfo,
chosenExchange: string): Promise<void> {
- let payReq: PayReq = {
+ const payReq: PayReq = {
coins: payCoinInfo.map((x) => x.sig),
+ exchange: chosenExchange,
merchant_pub: offer.contract.merchant_pub,
order_id: offer.contract.order_id,
- exchange: chosenExchange,
};
- let t: TransactionRecord = {
- contractHash: offer.H_contract,
+ const t: TransactionRecord = {
contract: offer.contract,
- payReq: payReq,
- merchantSig: offer.merchant_sig,
+ contractHash: offer.H_contract,
finished: false,
+ merchantSig: offer.merchant_sig,
+ payReq,
};
- let historyEntry: HistoryRecord = {
- type: "pay",
- timestamp: (new Date).getTime(),
- subjectId: `contract-${offer.H_contract}`,
+ const historyEntry: HistoryRecord = {
detail: {
- merchantName: offer.contract.merchant.name,
amount: offer.contract.amount,
contractHash: offer.H_contract,
fulfillmentUrl: offer.contract.fulfillment_url,
+ merchantName: offer.contract.merchant.name,
},
- level: HistoryLevel.User
+ level: HistoryLevel.User,
+ subjectId: `contract-${offer.H_contract}`,
+ timestamp: (new Date()).getTime(),
+ type: "pay",
};
await this.q()
@@ -798,7 +812,7 @@ export class Wallet {
async saveOffer(offer: OfferRecord): Promise<number> {
console.log(`saving offer in wallet.ts`);
- let id = await this.q().putWithResult(Stores.offers, offer);
+ const id = await this.q().putWithResult(Stores.offers, offer);
this.notifier.notify();
console.log(`saved offer with id ${id}`);
if (typeof id !== "number") {
@@ -815,21 +829,23 @@ export class Wallet {
async confirmPay(offer: OfferRecord): Promise<any> {
console.log("executing confirmPay");
- let transaction = await this.q().get(Stores.transactions, offer.H_contract);
+ const transaction = await this.q().get(Stores.transactions, offer.H_contract);
if (transaction) {
// Already payed ...
return {};
}
- let res = await this.getCoinsForPayment(offer.contract.amount,
- offer.contract.wire_method,
- getTalerStampSec(offer.contract.timestamp) || 0,
- offer.contract.max_fee,
- offer.contract.max_wire_fee || Amounts.getZero(offer.contract.amount.currency),
- offer.contract.wire_fee_amortization || 1,
- offer.contract.exchanges,
- offer.contract.auditors);
+ const res = await this.getCoinsForPayment({
+ allowedAuditors: offer.contract.auditors,
+ allowedExchanges: offer.contract.exchanges,
+ depositFeeLimit: offer.contract.max_fee,
+ paymentAmount: offer.contract.amount,
+ wireFeeAmortization: offer.contract.wire_fee_amortization || 1,
+ wireFeeLimit: offer.contract.max_wire_fee || Amounts.getZero(offer.contract.amount.currency),
+ wireFeeTime: getTalerStampSec(offer.contract.timestamp) || 0,
+ wireMethod: offer.contract.wire_method,
+ });
console.log("max_fee", offer.contract.max_fee);
console.log("coin selection result", res);
@@ -840,9 +856,9 @@ export class Wallet {
error: "coins-insufficient",
};
}
- let {exchangeUrl, cds} = res;
+ const {exchangeUrl, cds} = res;
- let ds = await this.cryptoApi.signDeposit(offer, cds);
+ const ds = await this.cryptoApi.signDeposit(offer, cds);
await this.recordConfirmPay(offer,
ds,
exchangeUrl);
@@ -856,20 +872,22 @@ export class Wallet {
*/
async checkPay(offer: OfferRecord): Promise<any> {
// First check if we already payed for it.
- let transaction = await this.q().get(Stores.transactions, offer.H_contract);
+ const transaction = await this.q().get(Stores.transactions, offer.H_contract);
if (transaction) {
return {isPayed: true};
}
// If not already payed, check if we could pay for it.
- let res = await this.getCoinsForPayment(offer.contract.amount,
- offer.contract.wire_method,
- getTalerStampSec(offer.contract.timestamp) || 0,
- offer.contract.max_fee,
- offer.contract.max_wire_fee || Amounts.getZero(offer.contract.amount.currency),
- offer.contract.wire_fee_amortization || 1,
- offer.contract.exchanges,
- offer.contract.auditors);
+ const res = await this.getCoinsForPayment({
+ allowedAuditors: offer.contract.auditors,
+ allowedExchanges: offer.contract.exchanges,
+ depositFeeLimit: offer.contract.max_fee,
+ paymentAmount: offer.contract.amount,
+ wireFeeAmortization: offer.contract.wire_fee_amortization || 1,
+ wireFeeLimit: offer.contract.max_wire_fee || Amounts.getZero(offer.contract.amount.currency),
+ wireFeeTime: getTalerStampSec(offer.contract.timestamp) || 0,
+ wireMethod: offer.contract.wire_method,
+ });
if (!res) {
console.log("not confirming payment, insufficient coins");
@@ -894,14 +912,14 @@ export class Wallet {
console.log("query for payment failed");
return {
success: false,
- }
+ };
}
console.log("query for payment succeeded:", t);
- let resp = {
- success: true,
- payReq: t.payReq,
+ const resp = {
H_contract: t.contractHash,
contract: t.contract,
+ payReq: t.payReq,
+ success: true,
};
return resp;
}
@@ -917,29 +935,28 @@ export class Wallet {
this.startOperation(opId);
try {
- let exchange = await this.updateExchangeFromUrl(reserveRecord.exchange_base_url);
- let reserve = await this.updateReserve(reserveRecord.reserve_pub);
- let n = await this.depleteReserve(reserve);
+ const exchange = await this.updateExchangeFromUrl(reserveRecord.exchange_base_url);
+ const reserve = await this.updateReserve(reserveRecord.reserve_pub);
+ const n = await this.depleteReserve(reserve);
- if (n != 0) {
- let depleted: HistoryRecord = {
- type: "depleted-reserve",
- subjectId: `reserve-progress-${reserveRecord.reserve_pub}`,
- timestamp: (new Date).getTime(),
+ if (n !== 0) {
+ const depleted: HistoryRecord = {
detail: {
+ currentAmount: reserveRecord.current_amount,
exchangeBaseUrl: reserveRecord.exchange_base_url,
- reservePub: reserveRecord.reserve_pub,
requestedAmount: reserveRecord.requested_amount,
- currentAmount: reserveRecord.current_amount,
+ reservePub: reserveRecord.reserve_pub,
},
- level: HistoryLevel.User
+ level: HistoryLevel.User,
+ subjectId: `reserve-progress-${reserveRecord.reserve_pub}`,
+ timestamp: (new Date()).getTime(),
+ type: "depleted-reserve",
};
await this.q().put(Stores.history, depleted).finish();
}
} catch (e) {
// random, exponential backoff truncated at 3 minutes
- let nextDelay = Math.min(2 * retryDelayMs + retryDelayMs * Math.random(),
- 3000 * 60);
+ const nextDelay = Math.min(2 * retryDelayMs + retryDelayMs * Math.random(), 3000 * 60);
console.warn(`Failed to deplete reserve, trying again in ${retryDelayMs} ms`);
setTimeout(() => this.processReserve(reserveRecord, nextDelay),
retryDelayMs);
@@ -980,9 +997,7 @@ export class Wallet {
console.log(`before committing coin: current ${amountToPretty(r.current_amount!)}, precoin: ${amountToPretty(
r.precoin_amount)})}`);
- let x = Amounts.sub(r.precoin_amount,
- preCoin.coinValue,
- denom.feeWithdraw);
+ const x = Amounts.sub(r.precoin_amount, preCoin.coinValue, denom.feeWithdraw);
if (x.saturated) {
console.error("database inconsistent");
throw AbortTransaction;
@@ -992,12 +1007,12 @@ export class Wallet {
};
const historyEntry: HistoryRecord = {
- type: "withdraw",
- timestamp: (new Date).getTime(),
- level: HistoryLevel.Expert,
detail: {
coinPub: coin.coinPub,
- }
+ },
+ level: HistoryLevel.Expert,
+ timestamp: (new Date()).getTime(),
+ type: "withdraw",
};
await this.q()
@@ -1013,10 +1028,12 @@ export class Wallet {
retryDelayMs,
"ms", e);
// exponential backoff truncated at one minute
- let nextRetryDelayMs = Math.min(retryDelayMs * 2, 5 * 60 * 1000);
+ const nextRetryDelayMs = Math.min(retryDelayMs * 2, 5 * 60 * 1000);
setTimeout(() => this.processPreCoin(preCoin, nextRetryDelayMs),
retryDelayMs);
- this.processPreCoinThrottle[preCoin.exchangeBaseUrl] = (this.processPreCoinThrottle[preCoin.exchangeBaseUrl] || 0) + 1;
+
+ const currentThrottle = this.processPreCoinThrottle[preCoin.exchangeBaseUrl] || 0;
+ this.processPreCoinThrottle[preCoin.exchangeBaseUrl] = currentThrottle + 1;
setTimeout(() => {this.processPreCoinThrottle[preCoin.exchangeBaseUrl]--; }, retryDelayMs);
} finally {
this.processPreCoinConcurrent--;
@@ -1031,44 +1048,44 @@ export class Wallet {
* audited nor trusted already.
*/
async createReserve(req: CreateReserveRequest): Promise<CreateReserveResponse> {
- let keypair = await this.cryptoApi.createEddsaKeypair();
- const now = (new Date).getTime();
+ const keypair = await this.cryptoApi.createEddsaKeypair();
+ const now = (new Date()).getTime();
const canonExchange = canonicalizeBaseUrl(req.exchange);
const reserveRecord: ReserveRecord = {
- hasPayback: false,
- reserve_pub: keypair.pub,
- reserve_priv: keypair.priv,
- exchange_base_url: canonExchange,
+ confirmed: false,
created: now,
- last_query: null,
current_amount: null,
- requested_amount: req.amount,
- confirmed: false,
+ exchange_base_url: canonExchange,
+ hasPayback: false,
+ last_query: null,
precoin_amount: Amounts.getZero(req.amount.currency),
+ requested_amount: req.amount,
+ reserve_priv: keypair.priv,
+ reserve_pub: keypair.pub,
};
const historyEntry = {
- type: "create-reserve",
- level: HistoryLevel.Expert,
- timestamp: now,
- subjectId: `reserve-progress-${reserveRecord.reserve_pub}`,
detail: {
requestedAmount: req.amount,
reservePub: reserveRecord.reserve_pub,
- }
+ },
+ level: HistoryLevel.Expert,
+ subjectId: `reserve-progress-${reserveRecord.reserve_pub}`,
+ timestamp: now,
+ type: "create-reserve",
};
- let exchangeInfo = await this.updateExchangeFromUrl(req.exchange);
- let {isAudited, isTrusted} = await this.getExchangeTrust(exchangeInfo);
+ const exchangeInfo = await this.updateExchangeFromUrl(req.exchange);
+ const {isAudited, isTrusted} = await this.getExchangeTrust(exchangeInfo);
let currencyRecord = await this.q().get(Stores.currencies, exchangeInfo.currency);
if (!currencyRecord) {
currencyRecord = {
- name: exchangeInfo.currency,
- fractionalDigits: 2,
- exchanges: [],
auditors: [],
- }
+ exchanges: [],
+ fractionalDigits: 2,
+ name: exchangeInfo.currency,
+ };
}
if (!isAudited && !isTrusted) {
@@ -1081,7 +1098,7 @@ export class Wallet {
.put(Stores.history, historyEntry)
.finish();
- let r: CreateReserveResponse = {
+ const r: CreateReserveResponse = {
exchange: canonExchange,
reservePub: keypair.pub,
};
@@ -1099,8 +1116,8 @@ export class Wallet {
* an unconfirmed reserve should be hidden.
*/
async confirmReserve(req: ConfirmReserveRequest): Promise<void> {
- const now = (new Date).getTime();
- let reserve: ReserveRecord|undefined = await (
+ const now = (new Date()).getTime();
+ const reserve: ReserveRecord|undefined = await (
this.q().get<ReserveRecord>(Stores.reserves,
req.reservePub));
if (!reserve) {
@@ -1109,15 +1126,15 @@ export class Wallet {
}
console.log("reserve confirmed");
const historyEntry: HistoryRecord = {
- type: "confirm-reserve",
- timestamp: now,
- subjectId: `reserve-progress-${reserve.reserve_pub}`,
detail: {
exchangeBaseUrl: reserve.exchange_base_url,
- reservePub: req.reservePub,
requestedAmount: reserve.requested_amount,
+ reservePub: req.reservePub,
},
level: HistoryLevel.User,
+ subjectId: `reserve-progress-${reserve.reserve_pub}`,
+ timestamp: now,
+ type: "confirm-reserve",
};
reserve.confirmed = true;
await this.q()
@@ -1131,40 +1148,40 @@ export class Wallet {
private async withdrawExecute(pc: PreCoinRecord): Promise<CoinRecord> {
- let reserve = await this.q().get<ReserveRecord>(Stores.reserves,
+ const reserve = await this.q().get<ReserveRecord>(Stores.reserves,
pc.reservePub);
if (!reserve) {
throw Error("db inconsistent");
}
- let wd: any = {};
+ const wd: any = {};
wd.denom_pub = pc.denomPub;
wd.reserve_pub = pc.reservePub;
wd.reserve_sig = pc.withdrawSig;
wd.coin_ev = pc.coinEv;
- let reqUrl = (new URI("reserve/withdraw")).absoluteTo(reserve.exchange_base_url);
- let resp = await this.http.postJson(reqUrl.href(), wd);
+ const reqUrl = (new URI("reserve/withdraw")).absoluteTo(reserve.exchange_base_url);
+ const resp = await this.http.postJson(reqUrl.href(), wd);
- if (resp.status != 200) {
+ if (resp.status !== 200) {
throw new RequestException({
hint: "Withdrawal failed",
- status: resp.status
+ status: resp.status,
});
}
- let r = JSON.parse(resp.responseText);
- let denomSig = await this.cryptoApi.rsaUnblind(r.ev_sig,
+ const r = JSON.parse(resp.responseText);
+ const denomSig = await this.cryptoApi.rsaUnblind(r.ev_sig,
pc.blindingKey,
pc.denomPub);
- let coin: CoinRecord = {
- reservePub: pc.reservePub,
- coinPub: pc.coinPub,
- coinPriv: pc.coinPriv,
- denomPub: pc.denomPub,
- denomSig: denomSig,
+ const coin: CoinRecord = {
blindingKey: pc.blindingKey,
+ coinPriv: pc.coinPriv,
+ coinPub: pc.coinPub,
currentAmount: pc.coinValue,
+ denomPub: pc.denomPub,
+ denomSig,
exchangeBaseUrl: pc.exchangeBaseUrl,
+ reservePub: pc.reservePub,
status: CoinStatus.Fresh,
};
return coin;
@@ -1179,25 +1196,24 @@ export class Wallet {
if (!reserve.current_amount) {
throw Error("can't withdraw when amount is unknown");
}
- let currentAmount = reserve.current_amount;
- if (!currentAmount) {
+ const withdrawAmount = reserve.current_amount;
+ if (!withdrawAmount) {
throw Error("can't withdraw when amount is unknown");
}
- let denomsForWithdraw = await this.getVerifiedWithdrawDenomList(reserve.exchange_base_url,
- currentAmount);
+ const denomsForWithdraw = await this.getVerifiedWithdrawDenomList(reserve.exchange_base_url, withdrawAmount);
console.log(`withdrawing ${denomsForWithdraw.length} coins`);
- let ps = denomsForWithdraw.map(async(denom) => {
+ const ps = denomsForWithdraw.map(async(denom) => {
function mutateReserve(r: ReserveRecord): ReserveRecord {
- let currentAmount = r.current_amount;
+ 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;
- let result = Amounts.sub(currentAmount,
+ const result = Amounts.sub(currentAmount,
denom.value,
denom.feeWithdraw);
if (result.saturated) {
@@ -1212,7 +1228,7 @@ export class Wallet {
return r;
}
- let preCoin = await this.cryptoApi
+ const preCoin = await this.cryptoApi
.createPreCoin(denom, reserve);
await this.q()
.put(Stores.precoins, preCoin)
@@ -1230,34 +1246,34 @@ export class Wallet {
* by quering the reserve's exchange.
*/
private async updateReserve(reservePub: string): Promise<ReserveRecord> {
- let reserve = await this.q()
+ const reserve = await this.q()
.get<ReserveRecord>(Stores.reserves, reservePub);
if (!reserve) {
throw Error("reserve not in db");
}
- let reqUrl = new URI("reserve/status").absoluteTo(reserve.exchange_base_url);
- reqUrl.query({'reserve_pub': reservePub});
- let resp = await this.http.get(reqUrl.href());
- if (resp.status != 200) {
+ 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();
}
- let reserveInfo = JSON.parse(resp.responseText);
+ const reserveInfo = JSON.parse(resp.responseText);
if (!reserveInfo) {
throw Error();
}
- let oldAmount = reserve.current_amount;
- let newAmount = reserveInfo.balance;
+ const oldAmount = reserve.current_amount;
+ const newAmount = reserveInfo.balance;
reserve.current_amount = reserveInfo.balance;
- let historyEntry = {
- type: "reserve-update",
- timestamp: (new Date).getTime(),
- subjectId: `reserve-progress-${reserve.reserve_pub}`,
+ const historyEntry = {
detail: {
- reservePub,
- requestedAmount: reserve.requested_amount,
+ newAmount,
oldAmount,
- newAmount
- }
+ requestedAmount: reserve.requested_amount,
+ reservePub,
+ },
+ subjectId: `reserve-progress-${reserve.reserve_pub}`,
+ timestamp: (new Date()).getTime(),
+ type: "reserve-update",
};
await this.q()
.put(Stores.reserves, reserve)
@@ -1272,16 +1288,16 @@ export class Wallet {
*/
async getWireInfo(exchangeBaseUrl: string): Promise<WireInfo> {
exchangeBaseUrl = canonicalizeBaseUrl(exchangeBaseUrl);
- let reqUrl = new URI("wire").absoluteTo(exchangeBaseUrl);
- let resp = await this.http.get(reqUrl.href());
+ const reqUrl = new URI("wire").absoluteTo(exchangeBaseUrl);
+ const resp = await this.http.get(reqUrl.href());
- if (resp.status != 200) {
+ if (resp.status !== 200) {
throw Error("/wire request failed");
}
- let wiJson = JSON.parse(resp.responseText);
+ const wiJson = JSON.parse(resp.responseText);
if (!wiJson) {
- throw Error("/wire response malformed")
+ throw Error("/wire response malformed");
}
return wiJson;
}
@@ -1290,7 +1306,7 @@ export class Wallet {
return (
this.q().iterIndex(Stores.denominations.exchangeBaseUrlIndex,
exchangeBaseUrl)
- .filter((d) => d.status == DenominationStatus.Unverified || d.status == DenominationStatus.VerifiedGood)
+ .filter((d) => d.status === DenominationStatus.Unverified || d.status === DenominationStatus.VerifiedGood)
.toArray()
);
}
@@ -1312,7 +1328,7 @@ export class Wallet {
const possibleDenoms = await (
this.q().iterIndex(Stores.denominations.exchangeBaseUrlIndex,
exchange.baseUrl)
- .filter((d) => d.status == DenominationStatus.Unverified || d.status == DenominationStatus.VerifiedGood)
+ .filter((d) => d.status === DenominationStatus.Unverified || d.status === DenominationStatus.VerifiedGood)
.toArray()
);
@@ -1323,12 +1339,12 @@ export class Wallet {
do {
allValid = true;
- let nextPossibleDenoms = [];
+ const nextPossibleDenoms = [];
selectedDenoms = getWithdrawDenomList(amount, possibleDenoms);
- for (let denom of selectedDenoms || []) {
- if (denom.status == DenominationStatus.Unverified) {
+ for (const denom of selectedDenoms || []) {
+ if (denom.status === DenominationStatus.Unverified) {
console.log(`verifying denom ${denom.denomPub.substr(0, 15)}`);
- let valid = await this.cryptoApi.isValidDenom(denom,
+ const valid = await this.cryptoApi.isValidDenom(denom,
exchange.masterPublicKey);
if (!valid) {
denom.status = DenominationStatus.VerifiedBad;
@@ -1349,24 +1365,23 @@ export class Wallet {
}
-
/**
* Check if and how an exchange is trusted and/or audited.
*/
async getExchangeTrust(exchangeInfo: ExchangeRecord): Promise<{isTrusted: boolean, isAudited: boolean}> {
let isTrusted = false;
let isAudited = false;
- let currencyRecord = await this.q().get(Stores.currencies, exchangeInfo.currency);
+ const currencyRecord = await this.q().get(Stores.currencies, exchangeInfo.currency);
if (currencyRecord) {
- for (let trustedExchange of currencyRecord.exchanges) {
- if (trustedExchange.baseUrl == exchangeInfo.baseUrl) {
+ for (const trustedExchange of currencyRecord.exchanges) {
+ if (trustedExchange.baseUrl === exchangeInfo.baseUrl) {
isTrusted = true;
break;
}
}
- for (let trustedAuditor of currencyRecord.auditors) {
- for (let exchangeAuditor of exchangeInfo.auditors) {
- if (trustedAuditor.baseUrl == exchangeAuditor.url) {
+ for (const trustedAuditor of currencyRecord.auditors) {
+ for (const exchangeAuditor of exchangeInfo.auditors) {
+ if (trustedAuditor.baseUrl === exchangeAuditor.url) {
isAudited = true;
break;
}
@@ -1378,47 +1393,47 @@ export class Wallet {
async getReserveCreationInfo(baseUrl: string,
amount: AmountJson): Promise<ReserveCreationInfo> {
- let exchangeInfo = await this.updateExchangeFromUrl(baseUrl);
+ const exchangeInfo = await this.updateExchangeFromUrl(baseUrl);
- let selectedDenoms = await this.getVerifiedWithdrawDenomList(baseUrl,
+ const selectedDenoms = await this.getVerifiedWithdrawDenomList(baseUrl,
amount);
let acc = Amounts.getZero(amount.currency);
- for (let d of selectedDenoms) {
+ for (const d of selectedDenoms) {
acc = Amounts.add(acc, d.feeWithdraw).amount;
}
- let actualCoinCost = selectedDenoms
+ const actualCoinCost = selectedDenoms
.map((d: DenominationRecord) => Amounts.add(d.value,
d.feeWithdraw).amount)
.reduce((a, b) => Amounts.add(a, b).amount);
- let wireInfo = await this.getWireInfo(baseUrl);
+ const wireInfo = await this.getWireInfo(baseUrl);
- let wireFees = await this.q().get(Stores.exchangeWireFees, baseUrl);
+ const wireFees = await this.q().get(Stores.exchangeWireFees, baseUrl);
if (!wireFees) {
// should never happen unless DB is inconsistent
throw Error(`no wire fees found for exchange ${baseUrl}`);
}
- let {isTrusted, isAudited} = await this.getExchangeTrust(exchangeInfo);
+ const {isTrusted, isAudited} = await this.getExchangeTrust(exchangeInfo);
- let earliestDepositExpiration = Infinity;;
- for (let denom of selectedDenoms) {
- let expireDeposit = getTalerStampSec(denom.stampExpireDeposit)!;
+ let earliestDepositExpiration = Infinity;
+ for (const denom of selectedDenoms) {
+ const expireDeposit = getTalerStampSec(denom.stampExpireDeposit)!;
if (expireDeposit < earliestDepositExpiration) {
earliestDepositExpiration = expireDeposit;
}
}
- let ret: ReserveCreationInfo = {
+ const ret: ReserveCreationInfo = {
+ earliestDepositExpiration,
exchangeInfo,
- selectedDenoms,
- wireInfo,
- wireFees,
isAudited,
isTrusted,
- withdrawFee: acc,
- earliestDepositExpiration,
overhead: Amounts.sub(amount, actualCoinCost).amount,
+ selectedDenoms,
+ wireFees,
+ wireInfo,
+ withdrawFee: acc,
};
return ret;
}
@@ -1431,24 +1446,24 @@ export class Wallet {
*/
async updateExchangeFromUrl(baseUrl: string): Promise<ExchangeRecord> {
baseUrl = canonicalizeBaseUrl(baseUrl);
- let keysUrl = new URI("keys").absoluteTo(baseUrl);
- let wireUrl = new URI("wire").absoluteTo(baseUrl);
- let keysResp = await this.http.get(keysUrl.href());
- if (keysResp.status != 200) {
+ const keysUrl = new URI("keys").absoluteTo(baseUrl);
+ const wireUrl = new URI("wire").absoluteTo(baseUrl);
+ const keysResp = await this.http.get(keysUrl.href());
+ if (keysResp.status !== 200) {
throw Error("/keys request failed");
}
- let wireResp = await this.http.get(wireUrl.href());
- if (wireResp.status != 200) {
+ const wireResp = await this.http.get(wireUrl.href());
+ if (wireResp.status !== 200) {
throw Error("/wire request failed");
}
- let exchangeKeysJson = KeysJson.checked(JSON.parse(keysResp.responseText));
- let wireRespJson = JSON.parse(wireResp.responseText);
+ const exchangeKeysJson = KeysJson.checked(JSON.parse(keysResp.responseText));
+ const wireRespJson = JSON.parse(wireResp.responseText);
if (typeof wireRespJson !== "object") {
throw Error("/wire response is not an object");
}
console.log("exchange wire", wireRespJson);
- let wireMethodDetails: WireDetailJson[] = [];
- for (let methodName in wireRespJson) {
+ const wireMethodDetails: WireDetailJson[] = [];
+ for (const methodName in wireRespJson) {
wireMethodDetails.push(WireDetailJson.checked(wireRespJson[methodName]));
}
return this.updateExchangeFromJson(baseUrl, exchangeKeysJson, wireMethodDetails);
@@ -1456,12 +1471,12 @@ export class Wallet {
private async suspendCoins(exchangeInfo: ExchangeRecord): Promise<void> {
- let suspendedCoins = await (
+ const resultSuspendedCoins = await (
this.q()
.iterIndex(Stores.coins.exchangeBaseUrlIndex, exchangeInfo.baseUrl)
.indexJoinLeft(Stores.denominations.exchangeBaseUrlIndex,
(e) => e.exchangeBaseUrl)
- .reduce((cd: JoinLeftResult<CoinRecord,DenominationRecord>,
+ .reduce((cd: JoinLeftResult<CoinRecord, DenominationRecord>,
suspendedCoins: CoinRecord[]) => {
if ((!cd.right) || (!cd.right.isOffered)) {
return Array.prototype.concat(suspendedCoins, [cd.left]);
@@ -1469,8 +1484,8 @@ export class Wallet {
return Array.prototype.concat(suspendedCoins);
}, []));
- let q = this.q();
- suspendedCoins.map((c) => {
+ const q = this.q();
+ resultSuspendedCoins.map((c) => {
console.log("suspending coin", c);
c.suspended = true;
q.put(Stores.coins, c);
@@ -1489,7 +1504,7 @@ export class Wallet {
throw Error("invalid update time");
}
- if (exchangeKeysJson.denoms.length == 0) {
+ if (exchangeKeysJson.denoms.length === 0) {
throw Error("exchange doesn't offer any denominations");
}
@@ -1499,24 +1514,24 @@ export class Wallet {
if (!r) {
exchangeInfo = {
+ auditors: exchangeKeysJson.auditors,
baseUrl,
+ currency: exchangeKeysJson.denoms[0].value.currency,
lastUpdateTime: updateTimeSec,
masterPublicKey: exchangeKeysJson.master_public_key,
- auditors: exchangeKeysJson.auditors,
- currency: exchangeKeysJson.denoms[0].value.currency,
};
console.log("making fresh exchange");
} else {
if (updateTimeSec < r.lastUpdateTime) {
console.log("outdated /keys, not updating");
- return r
+ return r;
}
exchangeInfo = r;
exchangeInfo.lastUpdateTime = updateTimeSec;
console.log("updating old exchange");
}
- let updatedExchangeInfo = await this.updateExchangeInfo(exchangeInfo,
+ const updatedExchangeInfo = await this.updateExchangeInfo(exchangeInfo,
exchangeKeysJson);
await this.suspendCoins(updatedExchangeInfo);
@@ -1532,37 +1547,37 @@ export class Wallet {
};
}
- for (let detail of wireMethodDetails) {
+ for (const detail of wireMethodDetails) {
let latestFeeStamp = 0;
- let fees = oldWireFees.feesForType[detail.type] || [];
+ const fees = oldWireFees.feesForType[detail.type] || [];
oldWireFees.feesForType[detail.type] = fees;
- for (let oldFee of fees) {
+ for (const oldFee of fees) {
if (oldFee.endStamp > latestFeeStamp) {
latestFeeStamp = oldFee.endStamp;
}
}
- for (let fee of detail.fees) {
- let start = getTalerStampSec(fee.start_date);
- if (start == null) {
+ for (const fee of detail.fees) {
+ const start = getTalerStampSec(fee.start_date);
+ if (start === null) {
console.error("invalid start stamp in fee", fee);
continue;
}
if (start < latestFeeStamp) {
continue;
}
- let end = getTalerStampSec(fee.end_date);
- if (end == null) {
+ const end = getTalerStampSec(fee.end_date);
+ if (end === null) {
console.error("invalid end stamp in fee", fee);
continue;
}
- let wf: WireFee = {
- wireFee: fee.wire_fee,
+ const wf: WireFee = {
closingFee: fee.closing_fee,
+ endStamp: end,
sig: fee.sig,
startStamp: start,
- endStamp: end,
- }
- let valid: boolean = await this.cryptoApi.isValidWireFee(detail.type, wf, exchangeInfo.masterPublicKey);
+ wireFee: fee.wire_fee,
+ };
+ const valid: boolean = await this.cryptoApi.isValidWireFee(detail.type, wf, exchangeInfo.masterPublicKey);
if (!valid) {
console.error("fee signature invalid", fee);
throw Error("fee signature invalid");
@@ -1574,14 +1589,14 @@ export class Wallet {
await this.q().put(Stores.exchangeWireFees, oldWireFees);
if (exchangeKeysJson.payback) {
- for (let payback of exchangeKeysJson.payback) {
- let denom = await this.q().getIndexed(Stores.denominations.denomPubHashIndex, payback.h_denom_pub);
+ for (const payback of exchangeKeysJson.payback) {
+ const denom = await this.q().getIndexed(Stores.denominations.denomPubHashIndex, payback.h_denom_pub);
if (!denom) {
continue;
}
console.log(`cashing back denom`, denom);
- let coins = await this.q().iterIndex(Stores.coins.denomPubIndex, denom.denomPub).toArray();
- for (let coin of coins) {
+ const coins = await this.q().iterIndex(Stores.coins.denomPubIndex, denom.denomPub).toArray();
+ for (const coin of coins) {
this.payback(coin.coinPub);
}
}
@@ -1593,7 +1608,7 @@ export class Wallet {
private async updateExchangeInfo(exchangeInfo: ExchangeRecord,
newKeys: KeysJson): Promise<ExchangeRecord> {
- if (exchangeInfo.masterPublicKey != newKeys.master_public_key) {
+ if (exchangeInfo.masterPublicKey !== newKeys.master_public_key) {
throw Error("public keys do not match");
}
@@ -1608,17 +1623,17 @@ export class Wallet {
const newDenoms: typeof existingDenoms = {};
const newAndUnseenDenoms: typeof existingDenoms = {};
- for (let d of newKeys.denoms) {
- let dr = await this.denominationRecordFromKeys(exchangeInfo.baseUrl, d);
+ for (const d of newKeys.denoms) {
+ const dr = await this.denominationRecordFromKeys(exchangeInfo.baseUrl, d);
if (!(d.denom_pub in existingDenoms)) {
newAndUnseenDenoms[dr.denomPub] = dr;
}
newDenoms[dr.denomPub] = dr;
}
- for (let oldDenomPub in existingDenoms) {
+ for (const oldDenomPub in existingDenoms) {
if (!(oldDenomPub in newDenoms)) {
- let d = existingDenoms[oldDenomPub];
+ const d = existingDenoms[oldDenomPub];
d.isOffered = false;
}
}
@@ -1640,13 +1655,13 @@ export class Wallet {
async getBalances(): Promise<WalletBalance> {
function ensureEntry(balance: WalletBalance, currency: string) {
let entry: WalletBalanceEntry|undefined = balance[currency];
- let z = Amounts.getZero(currency);
+ const z = Amounts.getZero(currency);
if (!entry) {
balance[currency] = entry = {
available: z,
+ paybackAmount: z,
pendingIncoming: z,
pendingPayment: z,
- paybackAmount: z,
};
}
return entry;
@@ -1656,11 +1671,11 @@ export class Wallet {
if (c.suspended) {
return balance;
}
- if (!(c.status == CoinStatus.Dirty || c.status == CoinStatus.Fresh)) {
+ if (!(c.status === CoinStatus.Dirty || c.status === CoinStatus.Fresh)) {
return balance;
}
- let currency = c.currentAmount.currency;
- let entry = ensureEntry(balance, currency);
+ const currency = c.currentAmount.currency;
+ const entry = ensureEntry(balance, currency);
entry.available = Amounts.add(entry.available, c.currentAmount).amount;
return balance;
}
@@ -1669,7 +1684,7 @@ export class Wallet {
if (!r.confirmed) {
return balance;
}
- let entry = ensureEntry(balance, r.requested_amount.currency);
+ const entry = ensureEntry(balance, r.requested_amount.currency);
let amount = r.current_amount;
if (!amount) {
amount = r.requested_amount;
@@ -1686,7 +1701,7 @@ export class Wallet {
if (!r.hasPayback) {
return balance;
}
- let entry = ensureEntry(balance, r.requested_amount.currency);
+ const entry = ensureEntry(balance, r.requested_amount.currency);
if (Amounts.cmp(smallestWithdraw[r.exchange_base_url], r.current_amount!) < 0) {
entry.paybackAmount = Amounts.add(entry.paybackAmount, r.current_amount!).amount;
}
@@ -1700,7 +1715,7 @@ export class Wallet {
if (r.finished) {
return balance;
}
- let entry = ensureEntry(balance, r.valueWithFee.currency);
+ const entry = ensureEntry(balance, r.valueWithFee.currency);
entry.pendingIncoming = Amounts.add(entry.pendingIncoming,
r.valueOutput).amount;
@@ -1711,7 +1726,7 @@ export class Wallet {
if (t.finished) {
return balance;
}
- let entry = ensureEntry(balance, t.contract.amount.currency);
+ const entry = ensureEntry(balance, t.contract.amount.currency);
entry.pendingPayment = Amounts.add(entry.pendingPayment,
t.contract.amount).amount;
@@ -1721,7 +1736,7 @@ export class Wallet {
function collectSmallestWithdraw(e: JoinResult<ExchangeRecord, DenominationRecord>,
sw: any) {
let min = sw[e.left.baseUrl];
- let v = Amounts.add(e.right.value, e.right.feeWithdraw).amount;
+ const v = Amounts.add(e.right.value, e.right.feeWithdraw).amount;
if (!min) {
min = v;
} else if (Amounts.cmp(v, min) < 0) {
@@ -1731,7 +1746,7 @@ export class Wallet {
return sw;
}
- let balance = {};
+ const balance = {};
// Mapping from exchange pub to smallest
// possible amount we can withdraw
let smallestWithdraw: {[baseUrl: string]: AmountJson} = {};
@@ -1742,7 +1757,7 @@ export class Wallet {
(x) => x.baseUrl)
.reduce(collectSmallestWithdraw, {}));
- let tx = this.q();
+ const tx = this.q();
tx.iter(Stores.coins)
.reduce(collectBalances, balance);
tx.iter(Stores.refresh)
@@ -1760,52 +1775,52 @@ export class Wallet {
async createRefreshSession(oldCoinPub: string): Promise<RefreshSessionRecord|undefined> {
- let coin = await this.q().get<CoinRecord>(Stores.coins, oldCoinPub);
+ const coin = await this.q().get<CoinRecord>(Stores.coins, oldCoinPub);
if (!coin) {
throw Error("coin not found");
}
- if (coin.currentAmount.value == 0 && coin.currentAmount.fraction == 0) {
+ if (coin.currentAmount.value === 0 && coin.currentAmount.fraction === 0) {
return undefined;
}
- let exchange = await this.updateExchangeFromUrl(coin.exchangeBaseUrl);
+ const exchange = await this.updateExchangeFromUrl(coin.exchangeBaseUrl);
if (!exchange) {
throw Error("db inconsistent");
}
- let oldDenom = await this.q().get(Stores.denominations,
+ const oldDenom = await this.q().get(Stores.denominations,
[exchange.baseUrl, coin.denomPub]);
if (!oldDenom) {
throw Error("db inconsistent");
}
- let availableDenoms: DenominationRecord[] = await (
+ const availableDenoms: DenominationRecord[] = await (
this.q()
.iterIndex(Stores.denominations.exchangeBaseUrlIndex,
exchange.baseUrl)
.toArray()
);
- let availableAmount = Amounts.sub(coin.currentAmount,
+ const availableAmount = Amounts.sub(coin.currentAmount,
oldDenom.feeRefresh).amount;
- let newCoinDenoms = getWithdrawDenomList(availableAmount,
+ const newCoinDenoms = getWithdrawDenomList(availableAmount,
availableDenoms);
console.log("refreshing coin", coin);
console.log("refreshing into", newCoinDenoms);
- if (newCoinDenoms.length == 0) {
+ if (newCoinDenoms.length === 0) {
console.log(`not refreshing, available amount ${amountToPretty(availableAmount)} too small`);
return undefined;
}
- let refreshSession: RefreshSessionRecord = await (
+ const refreshSession: RefreshSessionRecord = await (
this.cryptoApi.createRefreshSession(exchange.baseUrl,
3,
coin,
@@ -1813,7 +1828,7 @@ export class Wallet {
oldDenom.feeRefresh));
function mutateCoin(c: CoinRecord): CoinRecord {
- let r = Amounts.sub(c.currentAmount,
+ const r = Amounts.sub(c.currentAmount,
refreshSession.valueWithFee);
if (r.saturated) {
// Something else must have written the coin value
@@ -1837,7 +1852,7 @@ export class Wallet {
async refresh(oldCoinPub: string): Promise<void> {
let refreshSession: RefreshSessionRecord|undefined;
- let oldSession = await this.q().get(Stores.refresh, oldCoinPub);
+ const oldSession = await this.q().get(Stores.refresh, oldCoinPub);
if (oldSession) {
console.log("got old session for", oldCoinPub);
console.log(oldSession);
@@ -1858,9 +1873,9 @@ export class Wallet {
return;
}
if (typeof refreshSession.norevealIndex !== "number") {
- let coinPub = refreshSession.meltCoinPub;
+ const coinPub = refreshSession.meltCoinPub;
await this.refreshMelt(refreshSession);
- let r = await this.q().get<RefreshSessionRecord>(Stores.refresh, coinPub);
+ const r = await this.q().get<RefreshSessionRecord>(Stores.refresh, coinPub);
if (!r) {
throw Error("refresh session does not exist anymore");
}
@@ -1872,53 +1887,53 @@ export class Wallet {
async refreshMelt(refreshSession: RefreshSessionRecord): Promise<void> {
- if (refreshSession.norevealIndex != undefined) {
+ if (refreshSession.norevealIndex !== undefined) {
console.error("won't melt again");
return;
}
- let coin = await this.q().get<CoinRecord>(Stores.coins,
+ const coin = await this.q().get<CoinRecord>(Stores.coins,
refreshSession.meltCoinPub);
if (!coin) {
console.error("can't melt coin, it does not exist");
return;
}
- let reqUrl = new URI("refresh/melt").absoluteTo(refreshSession.exchangeBaseUrl);
- let meltCoin = {
+ const reqUrl = new URI("refresh/melt").absoluteTo(refreshSession.exchangeBaseUrl);
+ const meltCoin = {
coin_pub: coin.coinPub,
+ confirm_sig: refreshSession.confirmSig,
denom_pub: coin.denomPub,
denom_sig: coin.denomSig,
- confirm_sig: refreshSession.confirmSig,
value_with_fee: refreshSession.valueWithFee,
};
- let coinEvs = refreshSession.preCoinsForGammas.map((x) => x.map((y) => y.coinEv));
- let req = {
- "new_denoms": refreshSession.newDenoms,
- "melt_coin": meltCoin,
- "transfer_pubs": refreshSession.transferPubs,
- "coin_evs": coinEvs,
+ const coinEvs = refreshSession.preCoinsForGammas.map((x) => x.map((y) => y.coinEv));
+ const req = {
+ coin_evs: coinEvs,
+ melt_coin: meltCoin,
+ new_denoms: refreshSession.newDenoms,
+ transfer_pubs: refreshSession.transferPubs,
};
console.log("melt request:", req);
- let resp = await this.http.postJson(reqUrl.href(), req);
+ const resp = await this.http.postJson(reqUrl.href(), req);
console.log("melt request:", req);
console.log("melt response:", resp.responseText);
- if (resp.status != 200) {
+ if (resp.status !== 200) {
console.error(resp.responseText);
throw Error("refresh failed");
}
- let respJson = JSON.parse(resp.responseText);
+ const respJson = JSON.parse(resp.responseText);
if (!respJson) {
throw Error("exchange responded with garbage");
}
- let norevealIndex = respJson.noreveal_index;
+ const norevealIndex = respJson.noreveal_index;
- if (typeof norevealIndex != "number") {
+ if (typeof norevealIndex !== "number") {
throw Error("invalid response");
}
@@ -1929,71 +1944,70 @@ export class Wallet {
async refreshReveal(refreshSession: RefreshSessionRecord): Promise<void> {
- let norevealIndex = refreshSession.norevealIndex;
- if (norevealIndex == undefined) {
+ const norevealIndex = refreshSession.norevealIndex;
+ if (norevealIndex === undefined) {
throw Error("can't reveal without melting first");
}
- let privs = Array.from(refreshSession.transferPrivs);
+ const privs = Array.from(refreshSession.transferPrivs);
privs.splice(norevealIndex, 1);
- let req = {
- "session_hash": refreshSession.hash,
- "transfer_privs": privs,
+ const req = {
+ session_hash: refreshSession.hash,
+ transfer_privs: privs,
};
- let reqUrl = new URI("refresh/reveal")
- .absoluteTo(refreshSession.exchangeBaseUrl);
+ const reqUrl = new URI("refresh/reveal") .absoluteTo(refreshSession.exchangeBaseUrl);
console.log("reveal request:", req);
- let resp = await this.http.postJson(reqUrl.href(), req);
+ const resp = await this.http.postJson(reqUrl.href(), req);
console.log("session:", refreshSession);
console.log("reveal response:", resp);
- if (resp.status != 200) {
+ if (resp.status !== 200) {
console.log("error: /refresh/reveal returned status " + resp.status);
return;
}
- let respJson = JSON.parse(resp.responseText);
+ const respJson = JSON.parse(resp.responseText);
if (!respJson.ev_sigs || !Array.isArray(respJson.ev_sigs)) {
console.log("/refresh/reveal did not contain ev_sigs");
}
- let exchange = await this.q().get<ExchangeRecord>(Stores.exchanges,
+ const exchange = await this.q().get<ExchangeRecord>(Stores.exchanges,
refreshSession.exchangeBaseUrl);
if (!exchange) {
console.error(`exchange ${refreshSession.exchangeBaseUrl} not found`);
return;
}
- let coins: CoinRecord[] = [];
+ const coins: CoinRecord[] = [];
for (let i = 0; i < respJson.ev_sigs.length; i++) {
- let denom = await (
+ const denom = await (
this.q()
.get(Stores.denominations,
[
refreshSession.exchangeBaseUrl,
- refreshSession.newDenoms[i]
+ refreshSession.newDenoms[i],
]));
if (!denom) {
console.error("denom not found");
continue;
}
- let pc = refreshSession.preCoinsForGammas[refreshSession.norevealIndex!][i];
- let denomSig = await this.cryptoApi.rsaUnblind(respJson.ev_sigs[i].ev_sig,
+ const pc = refreshSession.preCoinsForGammas[refreshSession.norevealIndex!][i];
+ const denomSig = await this.cryptoApi.rsaUnblind(respJson.ev_sigs[i].ev_sig,
pc.blindingKey,
denom.denomPub);
- let coin: CoinRecord = {
- reservePub: undefined,
+ const coin: CoinRecord = {
blindingKey: pc.blindingKey,
- coinPub: pc.publicKey,
coinPriv: pc.privateKey,
- denomPub: denom.denomPub,
- denomSig: denomSig,
+ coinPub: pc.publicKey,
currentAmount: denom.value,
+ denomPub: denom.denomPub,
+ denomSig,
exchangeBaseUrl: refreshSession.exchangeBaseUrl,
+ reservePub: undefined,
status: CoinStatus.Fresh,
};
@@ -2018,7 +2032,7 @@ export class Wallet {
return acc;
}
- let history = await (
+ const history = await (
this.q()
.iterIndex(Stores.history.timestampIndex)
.reduce(collect, []));
@@ -2027,12 +2041,12 @@ export class Wallet {
}
async getDenoms(exchangeUrl: string): Promise<DenominationRecord[]> {
- let denoms = await this.q().iterIndex(Stores.denominations.exchangeBaseUrlIndex, exchangeUrl).toArray();
+ const denoms = await this.q().iterIndex(Stores.denominations.exchangeBaseUrlIndex, exchangeUrl).toArray();
return denoms;
}
async getOffer(offerId: number): Promise<any> {
- let offer = await this.q() .get(Stores.offers, offerId);
+ const offer = await this.q() .get(Stores.offers, offerId);
return offer;
}
@@ -2089,7 +2103,7 @@ export class Wallet {
* Store the private key in our DB, so we can prove ownership.
*/
async generateNonce(): Promise<string> {
- let {priv, pub} = await this.cryptoApi.createEddsaKeypair();
+ const {priv, pub} = await this.cryptoApi.createEddsaKeypair();
await this.q()
.put(Stores.nonces, {priv, pub})
.finish();
@@ -2103,23 +2117,23 @@ export class Wallet {
async paymentSucceeded(contractHash: string, merchantSig: string): Promise<any> {
const doPaymentSucceeded = async() => {
- let t = await this.q().get<TransactionRecord>(Stores.transactions,
+ const t = await this.q().get<TransactionRecord>(Stores.transactions,
contractHash);
if (!t) {
console.error("contract not found");
return;
}
- let merchantPub = t.contract.merchant_pub;
- let valid = this.cryptoApi.isValidPaymentSignature(merchantSig, contractHash, merchantPub);
+ const merchantPub = t.contract.merchant_pub;
+ const valid = this.cryptoApi.isValidPaymentSignature(merchantSig, contractHash, merchantPub);
if (!valid) {
console.error("merchant payment signature invalid");
// FIXME: properly display error
return;
}
t.finished = true;
- let modifiedCoins: CoinRecord[] = [];
- for (let pc of t.payReq.coins) {
- let c = await this.q().get<CoinRecord>(Stores.coins, pc.coin_pub);
+ const modifiedCoins: CoinRecord[] = [];
+ for (const pc of t.payReq.coins) {
+ const c = await this.q().get<CoinRecord>(Stores.coins, pc.coin_pub);
if (!c) {
console.error("coin not found");
return;
@@ -2132,7 +2146,7 @@ export class Wallet {
.putAll(Stores.coins, modifiedCoins)
.put(Stores.transactions, t)
.finish();
- for (let c of t.payReq.coins) {
+ for (const c of t.payReq.coins) {
this.refresh(c.coin_pub);
}
};
@@ -2145,11 +2159,11 @@ export class Wallet {
if (!coin) {
throw Error(`Coin ${coinPub} not found, can't request payback`);
}
- let reservePub = coin.reservePub;
+ const reservePub = coin.reservePub;
if (!reservePub) {
throw Error(`Can't request payback for a refreshed coin`);
}
- let reserve = await this.q().get(Stores.reserves, reservePub);
+ const reserve = await this.q().get(Stores.reserves, reservePub);
if (!reserve) {
throw Error(`Reserve of coin ${coinPub} not found`);
}
@@ -2167,14 +2181,14 @@ export class Wallet {
reserve.hasPayback = true;
await this.q().put(Stores.coins, coin).put(Stores.reserves, reserve);
- let paybackRequest = await this.cryptoApi.createPaybackRequest(coin);
- let reqUrl = new URI("payback").absoluteTo(coin.exchangeBaseUrl);
- let resp = await this.http.postJson(reqUrl.href(), paybackRequest);
- if (resp.status != 200) {
+ const paybackRequest = await this.cryptoApi.createPaybackRequest(coin);
+ const reqUrl = new URI("payback").absoluteTo(coin.exchangeBaseUrl);
+ const resp = await this.http.postJson(reqUrl.href(), paybackRequest);
+ if (resp.status !== 200) {
throw Error();
}
- let paybackConfirmation = PaybackConfirmation.checked(JSON.parse(resp.responseText));
- if (paybackConfirmation.reserve_pub != coin.reservePub) {
+ 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`);
}
coin = await this.q().get(Stores.coins, coinPub);
@@ -2188,29 +2202,29 @@ export class Wallet {
async denominationRecordFromKeys(exchangeBaseUrl: string, denomIn: Denomination): Promise<DenominationRecord> {
- let denomPubHash = await this.cryptoApi.hashDenomPub(denomIn.denom_pub);
- let d: DenominationRecord = {
- denomPubHash,
+ const denomPubHash = await this.cryptoApi.hashDenomPub(denomIn.denom_pub);
+ const d: DenominationRecord = {
denomPub: denomIn.denom_pub,
- exchangeBaseUrl: exchangeBaseUrl,
+ denomPubHash,
+ exchangeBaseUrl,
feeDeposit: denomIn.fee_deposit,
- masterSig: denomIn.master_sig,
- feeRefund: denomIn.fee_refund,
feeRefresh: denomIn.fee_refresh,
+ feeRefund: denomIn.fee_refund,
feeWithdraw: denomIn.fee_withdraw,
+ isOffered: true,
+ masterSig: denomIn.master_sig,
stampExpireDeposit: denomIn.stamp_expire_deposit,
stampExpireLegal: denomIn.stamp_expire_legal,
stampExpireWithdraw: denomIn.stamp_expire_withdraw,
stampStart: denomIn.stamp_start,
status: DenominationStatus.Unverified,
- isOffered: true,
value: denomIn.value,
};
return d;
}
async withdrawPaybackReserve(reservePub: string): Promise<void> {
- let reserve = await this.q().get(Stores.reserves, reservePub);
+ const reserve = await this.q().get(Stores.reserves, reservePub);
if (!reserve) {
throw Error(`Reserve ${reservePub} does not exist`);
}
@@ -2220,7 +2234,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();
}
}