version upgrade and formatting
This commit is contained in:
parent
7974a76228
commit
035b3fdae2
@ -46,7 +46,7 @@
|
|||||||
"react": "^16.8.5",
|
"react": "^16.8.5",
|
||||||
"react-dom": "^16.8.5",
|
"react-dom": "^16.8.5",
|
||||||
"structured-clone": "^0.2.2",
|
"structured-clone": "^0.2.2",
|
||||||
"terser-webpack-plugin": "^1.2.3",
|
"terser-webpack-plugin": "^2.2.1",
|
||||||
"through2": "3.0.1",
|
"through2": "3.0.1",
|
||||||
"tslint": "^5.19.0",
|
"tslint": "^5.19.0",
|
||||||
"typedoc": "^0.15.0",
|
"typedoc": "^0.15.0",
|
||||||
@ -60,7 +60,7 @@
|
|||||||
"webpack-merge": "^4.2.2"
|
"webpack-merge": "^4.2.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/chrome": "^0.0.88",
|
"@types/chrome": "^0.0.91",
|
||||||
"@types/urijs": "^1.19.3",
|
"@types/urijs": "^1.19.3",
|
||||||
"axios": "^0.19.0",
|
"axios": "^0.19.0",
|
||||||
"idb-bridge": "^0.0.11",
|
"idb-bridge": "^0.0.11",
|
||||||
|
20
src/query.ts
20
src/query.ts
@ -89,7 +89,10 @@ export function oneShotGetIndexed<S extends IDBValidKey, T>(
|
|||||||
key: any,
|
key: any,
|
||||||
): Promise<T | undefined> {
|
): Promise<T | undefined> {
|
||||||
const tx = db.transaction([index.storeName], "readonly");
|
const tx = db.transaction([index.storeName], "readonly");
|
||||||
const req = tx.objectStore(index.storeName).index(index.indexName).get(key);
|
const req = tx
|
||||||
|
.objectStore(index.storeName)
|
||||||
|
.index(index.indexName)
|
||||||
|
.get(key);
|
||||||
return requestToPromise(req);
|
return requestToPromise(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +107,10 @@ export function oneShotPut<T>(
|
|||||||
return requestToPromise(req);
|
return requestToPromise(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyMutation<T>(req: IDBRequest, f: (x: T) => T | undefined): Promise<void> {
|
function applyMutation<T>(
|
||||||
|
req: IDBRequest,
|
||||||
|
f: (x: T) => T | undefined,
|
||||||
|
): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
req.onsuccess = () => {
|
req.onsuccess = () => {
|
||||||
const cursor = req.result;
|
const cursor = req.result;
|
||||||
@ -226,7 +232,7 @@ class ResultStream<T> {
|
|||||||
const x = await this.next();
|
const x = await this.next();
|
||||||
if (x.hasValue) {
|
if (x.hasValue) {
|
||||||
if (f(x.value)) {
|
if (f(x.value)) {
|
||||||
arr.push(x.value)
|
arr.push(x.value);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
@ -261,7 +267,7 @@ class ResultStream<T> {
|
|||||||
|
|
||||||
export function oneShotIter<T>(
|
export function oneShotIter<T>(
|
||||||
db: IDBDatabase,
|
db: IDBDatabase,
|
||||||
store: Store<T>
|
store: Store<T>,
|
||||||
): ResultStream<T> {
|
): ResultStream<T> {
|
||||||
const tx = db.transaction([store.name], "readonly");
|
const tx = db.transaction([store.name], "readonly");
|
||||||
const req = tx.objectStore(store.name).openCursor();
|
const req = tx.objectStore(store.name).openCursor();
|
||||||
@ -274,7 +280,10 @@ export function oneShotIterIndex<S extends IDBValidKey, T>(
|
|||||||
query?: any,
|
query?: any,
|
||||||
): ResultStream<T> {
|
): ResultStream<T> {
|
||||||
const tx = db.transaction([index.storeName], "readonly");
|
const tx = db.transaction([index.storeName], "readonly");
|
||||||
const req = tx.objectStore(index.storeName).index(index.indexName).openCursor(query);
|
const req = tx
|
||||||
|
.objectStore(index.storeName)
|
||||||
|
.index(index.indexName)
|
||||||
|
.openCursor(query);
|
||||||
return new ResultStream<T>(req);
|
return new ResultStream<T>(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,7 +398,6 @@ export class Index<S extends IDBValidKey, T> {
|
|||||||
protected _dummyKey: S | undefined;
|
protected _dummyKey: S | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exception that should be thrown by client code to abort a transaction.
|
* Exception that should be thrown by client code to abort a transaction.
|
||||||
*/
|
*/
|
||||||
|
584
src/wallet.ts
584
src/wallet.ts
@ -409,8 +409,10 @@ export class Wallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async processPending(): Promise<void> {
|
public async processPending(): Promise<void> {
|
||||||
|
const exchangeBaseUrlList = await oneShotIter(
|
||||||
const exchangeBaseUrlList = await oneShotIter(this.db, Stores.exchanges).map((x) => x.baseUrl);
|
this.db,
|
||||||
|
Stores.exchanges,
|
||||||
|
).map(x => x.baseUrl);
|
||||||
|
|
||||||
for (let exchangeBaseUrl of exchangeBaseUrlList) {
|
for (let exchangeBaseUrl of exchangeBaseUrlList) {
|
||||||
await this.updateExchangeFromUrl(exchangeBaseUrl);
|
await this.updateExchangeFromUrl(exchangeBaseUrl);
|
||||||
@ -436,9 +438,12 @@ export class Wallet {
|
|||||||
* already been applied.
|
* already been applied.
|
||||||
*/
|
*/
|
||||||
async fillDefaults() {
|
async fillDefaults() {
|
||||||
await runWithWriteTransaction(this.db, [Stores.config, Stores.currencies], async (tx) => {
|
await runWithWriteTransaction(
|
||||||
|
this.db,
|
||||||
|
[Stores.config, Stores.currencies],
|
||||||
|
async tx => {
|
||||||
let applied = false;
|
let applied = false;
|
||||||
await tx.iter(Stores.config).forEach((x) => {
|
await tx.iter(Stores.config).forEach(x => {
|
||||||
if (x.key == "currencyDefaultsApplied" && x.value == true) {
|
if (x.key == "currencyDefaultsApplied" && x.value == true) {
|
||||||
applied = true;
|
applied = true;
|
||||||
}
|
}
|
||||||
@ -448,7 +453,8 @@ export class Wallet {
|
|||||||
await tx.put(Stores.currencies, c);
|
await tx.put(Stores.currencies, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private startOperation(operationId: string) {
|
private startOperation(operationId: string) {
|
||||||
@ -464,7 +470,9 @@ export class Wallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async updateExchanges(): Promise<void> {
|
async updateExchanges(): Promise<void> {
|
||||||
const exchangeUrls = await oneShotIter(this.db, Stores.exchanges).map((e) => e.baseUrl);
|
const exchangeUrls = await oneShotIter(this.db, Stores.exchanges).map(
|
||||||
|
e => e.baseUrl,
|
||||||
|
);
|
||||||
|
|
||||||
for (const url of exchangeUrls) {
|
for (const url of exchangeUrls) {
|
||||||
this.updateExchangeFromUrl(url).catch(e => {
|
this.updateExchangeFromUrl(url).catch(e => {
|
||||||
@ -481,9 +489,9 @@ export class Wallet {
|
|||||||
Wallet.enableTracing && console.log("resuming pending operations from db");
|
Wallet.enableTracing && console.log("resuming pending operations from db");
|
||||||
|
|
||||||
oneShotIter(this.db, Stores.reserves).forEach(reserve => {
|
oneShotIter(this.db, Stores.reserves).forEach(reserve => {
|
||||||
Wallet.enableTracing &&
|
Wallet.enableTracing &&
|
||||||
console.log("resuming reserve", reserve.reserve_pub);
|
console.log("resuming reserve", reserve.reserve_pub);
|
||||||
this.processReserve(reserve.reserve_pub);
|
this.processReserve(reserve.reserve_pub);
|
||||||
});
|
});
|
||||||
|
|
||||||
oneShotIter(this.db, Stores.precoins).forEach(preCoin => {
|
oneShotIter(this.db, Stores.precoins).forEach(preCoin => {
|
||||||
@ -495,27 +503,41 @@ export class Wallet {
|
|||||||
this.continueRefreshSession(r);
|
this.continueRefreshSession(r);
|
||||||
});
|
});
|
||||||
|
|
||||||
oneShotIter(this.db, Stores.coinsReturns).forEach((r: CoinsReturnRecord) => {
|
oneShotIter(this.db, Stores.coinsReturns).forEach(
|
||||||
this.depositReturnedCoins(r);
|
(r: CoinsReturnRecord) => {
|
||||||
});
|
this.depositReturnedCoins(r);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getCoinsForReturn(
|
private async getCoinsForReturn(
|
||||||
exchangeBaseUrl: string,
|
exchangeBaseUrl: string,
|
||||||
amount: AmountJson,
|
amount: AmountJson,
|
||||||
): Promise<CoinWithDenom[] | undefined> {
|
): Promise<CoinWithDenom[] | undefined> {
|
||||||
const exchange = await oneShotGet(this.db, Stores.exchanges, exchangeBaseUrl);
|
const exchange = await oneShotGet(
|
||||||
|
this.db,
|
||||||
|
Stores.exchanges,
|
||||||
|
exchangeBaseUrl,
|
||||||
|
);
|
||||||
if (!exchange) {
|
if (!exchange) {
|
||||||
throw Error(`Exchange ${exchangeBaseUrl} not known to the wallet`);
|
throw Error(`Exchange ${exchangeBaseUrl} not known to the wallet`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const coins: CoinRecord[] = await oneShotIterIndex(this.db, Stores.coins.exchangeBaseUrlIndex, exchange.baseUrl).toArray();
|
const coins: CoinRecord[] = await oneShotIterIndex(
|
||||||
|
this.db,
|
||||||
|
Stores.coins.exchangeBaseUrlIndex,
|
||||||
|
exchange.baseUrl,
|
||||||
|
).toArray();
|
||||||
|
|
||||||
if (!coins || !coins.length) {
|
if (!coins || !coins.length) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const denoms = await oneShotIterIndex(this.db, Stores.denominations.exchangeBaseUrlIndex, exchange.baseUrl).toArray();
|
const denoms = await oneShotIterIndex(
|
||||||
|
this.db,
|
||||||
|
Stores.denominations.exchangeBaseUrlIndex,
|
||||||
|
exchange.baseUrl,
|
||||||
|
).toArray();
|
||||||
|
|
||||||
// Denomination of the first coin, we assume that all other
|
// Denomination of the first coin, we assume that all other
|
||||||
// coins have the same currency
|
// coins have the same currency
|
||||||
@ -621,9 +643,17 @@ export class Wallet {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const coins = await oneShotIterIndex(this.db, Stores.coins.exchangeBaseUrlIndex, exchange.baseUrl).toArray();
|
const coins = await oneShotIterIndex(
|
||||||
|
this.db,
|
||||||
|
Stores.coins.exchangeBaseUrlIndex,
|
||||||
|
exchange.baseUrl,
|
||||||
|
).toArray();
|
||||||
|
|
||||||
const denoms = await oneShotIterIndex(this.db, Stores.denominations.exchangeBaseUrlIndex, exchange.baseUrl).toArray();
|
const denoms = await oneShotIterIndex(
|
||||||
|
this.db,
|
||||||
|
Stores.denominations.exchangeBaseUrlIndex,
|
||||||
|
exchange.baseUrl,
|
||||||
|
).toArray();
|
||||||
|
|
||||||
if (!coins || coins.length === 0) {
|
if (!coins || coins.length === 0) {
|
||||||
continue;
|
continue;
|
||||||
@ -726,12 +756,16 @@ export class Wallet {
|
|||||||
timestamp_refund: 0,
|
timestamp_refund: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
await runWithWriteTransaction(this.db, [Stores.coins, Stores.purchases], async (tx) => {
|
await runWithWriteTransaction(
|
||||||
await tx.put(Stores.purchases, t);
|
this.db,
|
||||||
for (let c of payCoinInfo.updatedCoins) {
|
[Stores.coins, Stores.purchases],
|
||||||
await tx.put(Stores.coins, c);
|
async tx => {
|
||||||
}
|
await tx.put(Stores.purchases, t);
|
||||||
});
|
for (let c of payCoinInfo.updatedCoins) {
|
||||||
|
await tx.put(Stores.coins, c);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
this.badge.showNotification();
|
this.badge.showNotification();
|
||||||
this.notifier.notify();
|
this.notifier.notify();
|
||||||
@ -812,7 +846,11 @@ export class Wallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// First check if we already payed for it.
|
// First check if we already payed for it.
|
||||||
const purchase = await oneShotGet(this.db, Stores.purchases, proposal.contractTermsHash);
|
const purchase = await oneShotGet(
|
||||||
|
this.db,
|
||||||
|
Stores.purchases,
|
||||||
|
proposal.contractTermsHash,
|
||||||
|
);
|
||||||
|
|
||||||
if (!purchase) {
|
if (!purchase) {
|
||||||
const paymentAmount = Amounts.parseOrThrow(proposal.contractTerms.amount);
|
const paymentAmount = Amounts.parseOrThrow(proposal.contractTerms.amount);
|
||||||
@ -894,7 +932,11 @@ export class Wallet {
|
|||||||
* downloaded in the context of a session ID.
|
* downloaded in the context of a session ID.
|
||||||
*/
|
*/
|
||||||
async downloadProposal(url: string, sessionId?: string): Promise<number> {
|
async downloadProposal(url: string, sessionId?: string): Promise<number> {
|
||||||
const oldProposal = await oneShotGetIndexed(this.db, Stores.proposals.urlIndex, url);
|
const oldProposal = await oneShotGetIndexed(
|
||||||
|
this.db,
|
||||||
|
Stores.proposals.urlIndex,
|
||||||
|
url,
|
||||||
|
);
|
||||||
if (oldProposal) {
|
if (oldProposal) {
|
||||||
return oldProposal.id!;
|
return oldProposal.id!;
|
||||||
}
|
}
|
||||||
@ -940,9 +982,11 @@ export class Wallet {
|
|||||||
throw Error(`proposal with id ${proposalId} not found`);
|
throw Error(`proposal with id ${proposalId} not found`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const purchase = await oneShotGet(this.db,
|
const purchase = await oneShotGet(
|
||||||
|
this.db,
|
||||||
Stores.purchases,
|
Stores.purchases,
|
||||||
proposal.contractTermsHash);
|
proposal.contractTermsHash,
|
||||||
|
);
|
||||||
|
|
||||||
if (!purchase) {
|
if (!purchase) {
|
||||||
throw Error("purchase not found for proposal");
|
throw Error("purchase not found for proposal");
|
||||||
@ -957,7 +1001,11 @@ export class Wallet {
|
|||||||
contractTermsHash: string,
|
contractTermsHash: string,
|
||||||
sessionId: string | undefined,
|
sessionId: string | undefined,
|
||||||
): Promise<ConfirmPayResult> {
|
): Promise<ConfirmPayResult> {
|
||||||
const purchase = await oneShotGet(this.db, Stores.purchases, contractTermsHash);
|
const purchase = await oneShotGet(
|
||||||
|
this.db,
|
||||||
|
Stores.purchases,
|
||||||
|
contractTermsHash,
|
||||||
|
);
|
||||||
if (!purchase) {
|
if (!purchase) {
|
||||||
throw Error("Purchase not found: " + contractTermsHash);
|
throw Error("Purchase not found: " + contractTermsHash);
|
||||||
}
|
}
|
||||||
@ -1004,12 +1052,16 @@ export class Wallet {
|
|||||||
modifiedCoins.push(c);
|
modifiedCoins.push(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
await runWithWriteTransaction(this.db, [Stores.coins, Stores.purchases], async (tx) => {
|
await runWithWriteTransaction(
|
||||||
for (let c of modifiedCoins) {
|
this.db,
|
||||||
tx.put(Stores.coins, c);
|
[Stores.coins, Stores.purchases],
|
||||||
}
|
async tx => {
|
||||||
tx.put(Stores.purchases, purchase);
|
for (let c of modifiedCoins) {
|
||||||
});
|
tx.put(Stores.coins, c);
|
||||||
|
}
|
||||||
|
tx.put(Stores.purchases, purchase);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
for (const c of purchase.payReq.coins) {
|
for (const c of purchase.payReq.coins) {
|
||||||
this.refresh(c.coin_pub);
|
this.refresh(c.coin_pub);
|
||||||
@ -1065,9 +1117,11 @@ export class Wallet {
|
|||||||
|
|
||||||
const sessionId = sessionIdOverride || proposal.downloadSessionId;
|
const sessionId = sessionIdOverride || proposal.downloadSessionId;
|
||||||
|
|
||||||
let purchase = await oneShotGet(this.db,
|
let purchase = await oneShotGet(
|
||||||
|
this.db,
|
||||||
Stores.purchases,
|
Stores.purchases,
|
||||||
proposal.contractTermsHash,);
|
proposal.contractTermsHash,
|
||||||
|
);
|
||||||
|
|
||||||
if (purchase) {
|
if (purchase) {
|
||||||
return this.submitPay(purchase.contractTermsHash, sessionId);
|
return this.submitPay(purchase.contractTermsHash, sessionId);
|
||||||
@ -1167,9 +1221,7 @@ export class Wallet {
|
|||||||
* Send reserve details
|
* Send reserve details
|
||||||
*/
|
*/
|
||||||
private async sendReserveInfoToBank(reservePub: string) {
|
private async sendReserveInfoToBank(reservePub: string) {
|
||||||
const reserve = await oneShotGet(this.db,
|
const reserve = await oneShotGet(this.db, Stores.reserves, reservePub);
|
||||||
Stores.reserves,
|
|
||||||
reservePub);
|
|
||||||
if (!reserve) {
|
if (!reserve) {
|
||||||
throw Error("reserve not in db");
|
throw Error("reserve not in db");
|
||||||
}
|
}
|
||||||
@ -1190,7 +1242,7 @@ export class Wallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (status.transfer_done) {
|
if (status.transfer_done) {
|
||||||
await oneShotMutate(this.db, Stores.reserves, reservePub, (r) => {
|
await oneShotMutate(this.db, Stores.reserves, reservePub, r => {
|
||||||
r.timestamp_confirmed = now;
|
r.timestamp_confirmed = now;
|
||||||
return r;
|
return r;
|
||||||
});
|
});
|
||||||
@ -1206,7 +1258,7 @@ export class Wallet {
|
|||||||
console.log("bank error response", e);
|
console.log("bank error response", e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
await oneShotMutate(this.db, Stores.reserves, reservePub, (r) => {
|
await oneShotMutate(this.db, Stores.reserves, reservePub, r => {
|
||||||
r.timestamp_reserve_info_posted = now;
|
r.timestamp_reserve_info_posted = now;
|
||||||
return r;
|
return r;
|
||||||
});
|
});
|
||||||
@ -1321,9 +1373,11 @@ export class Wallet {
|
|||||||
this.processPreCoinConcurrent++;
|
this.processPreCoinConcurrent++;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const exchange = await oneShotGet(this.db,
|
const exchange = await oneShotGet(
|
||||||
|
this.db,
|
||||||
Stores.exchanges,
|
Stores.exchanges,
|
||||||
preCoin.exchangeBaseUrl,);
|
preCoin.exchangeBaseUrl,
|
||||||
|
);
|
||||||
if (!exchange) {
|
if (!exchange) {
|
||||||
console.error("db inconsistent: exchange for precoin not found");
|
console.error("db inconsistent: exchange for precoin not found");
|
||||||
return;
|
return;
|
||||||
@ -1353,11 +1407,15 @@ export class Wallet {
|
|||||||
return r;
|
return r;
|
||||||
};
|
};
|
||||||
|
|
||||||
await runWithWriteTransaction(this.db, [Stores.reserves, Stores.precoins, Stores.coins], async (tx) => {
|
await runWithWriteTransaction(
|
||||||
await tx.mutate(Stores.reserves, preCoin.reservePub, mutateReserve);
|
this.db,
|
||||||
await tx.delete(Stores.precoins, coin.coinPub);
|
[Stores.reserves, Stores.precoins, Stores.coins],
|
||||||
await tx.add(Stores.coins, coin);
|
async tx => {
|
||||||
});
|
await tx.mutate(Stores.reserves, preCoin.reservePub, mutateReserve);
|
||||||
|
await tx.delete(Stores.precoins, coin.coinPub);
|
||||||
|
await tx.add(Stores.coins, coin);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
this.badge.showNotification();
|
this.badge.showNotification();
|
||||||
|
|
||||||
@ -1441,7 +1499,11 @@ export class Wallet {
|
|||||||
throw Error("exchange not updated");
|
throw Error("exchange not updated");
|
||||||
}
|
}
|
||||||
const { isAudited, isTrusted } = await this.getExchangeTrust(exchangeInfo);
|
const { isAudited, isTrusted } = await this.getExchangeTrust(exchangeInfo);
|
||||||
let currencyRecord = await oneShotGet(this.db, Stores.currencies, exchangeDetails.currency);
|
let currencyRecord = await oneShotGet(
|
||||||
|
this.db,
|
||||||
|
Stores.currencies,
|
||||||
|
exchangeDetails.currency,
|
||||||
|
);
|
||||||
if (!currencyRecord) {
|
if (!currencyRecord) {
|
||||||
currencyRecord = {
|
currencyRecord = {
|
||||||
auditors: [],
|
auditors: [],
|
||||||
@ -1460,10 +1522,14 @@ export class Wallet {
|
|||||||
|
|
||||||
const cr: CurrencyRecord = currencyRecord;
|
const cr: CurrencyRecord = currencyRecord;
|
||||||
|
|
||||||
runWithWriteTransaction(this.db, [Stores.currencies, Stores.reserves], async (tx) => {
|
runWithWriteTransaction(
|
||||||
await tx.put(Stores.currencies, cr);
|
this.db,
|
||||||
await tx.put(Stores.reserves, reserveRecord);
|
[Stores.currencies, Stores.reserves],
|
||||||
});
|
async tx => {
|
||||||
|
await tx.put(Stores.currencies, cr);
|
||||||
|
await tx.put(Stores.reserves, reserveRecord);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
if (req.bankWithdrawStatusUrl) {
|
if (req.bankWithdrawStatusUrl) {
|
||||||
this.processReserve(keypair.pub);
|
this.processReserve(keypair.pub);
|
||||||
@ -1611,13 +1677,17 @@ export class Wallet {
|
|||||||
// This will fail and throw an exception if the remaining amount in the
|
// This will fail and throw an exception if the remaining amount in the
|
||||||
// reserve is too low to create a pre-coin.
|
// reserve is too low to create a pre-coin.
|
||||||
try {
|
try {
|
||||||
await runWithWriteTransaction(this.db, [Stores.precoins, Stores.withdrawals, Stores.reserves], async (tx) => {
|
await runWithWriteTransaction(
|
||||||
for (let pcr of preCoinRecords) {
|
this.db,
|
||||||
await tx.put(Stores.precoins, pcr);
|
[Stores.precoins, Stores.withdrawals, Stores.reserves],
|
||||||
}
|
async tx => {
|
||||||
await tx.mutate(Stores.reserves, reserve.reserve_pub, mutateReserve);
|
for (let pcr of preCoinRecords) {
|
||||||
await tx.put(Stores.withdrawals, withdrawalRecord);
|
await tx.put(Stores.precoins, pcr);
|
||||||
});
|
}
|
||||||
|
await tx.mutate(Stores.reserves, reserve.reserve_pub, mutateReserve);
|
||||||
|
await tx.put(Stores.withdrawals, withdrawalRecord);
|
||||||
|
},
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1661,10 +1731,18 @@ export class Wallet {
|
|||||||
return reserve;
|
return reserve;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPossibleDenoms(exchangeBaseUrl: string): Promise<DenominationRecord[]> {
|
async getPossibleDenoms(
|
||||||
return await oneShotIterIndex(this.db, Stores.denominations.exchangeBaseUrlIndex, exchangeBaseUrl).filter((d) => {
|
exchangeBaseUrl: string,
|
||||||
return d.status === DenominationStatus.Unverified ||
|
): Promise<DenominationRecord[]> {
|
||||||
d.status === DenominationStatus.VerifiedGood;
|
return await oneShotIterIndex(
|
||||||
|
this.db,
|
||||||
|
Stores.denominations.exchangeBaseUrlIndex,
|
||||||
|
exchangeBaseUrl,
|
||||||
|
).filter(d => {
|
||||||
|
return (
|
||||||
|
d.status === DenominationStatus.Unverified ||
|
||||||
|
d.status === DenominationStatus.VerifiedGood
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1677,7 +1755,11 @@ export class Wallet {
|
|||||||
async getVerifiedSmallestWithdrawAmount(
|
async getVerifiedSmallestWithdrawAmount(
|
||||||
exchangeBaseUrl: string,
|
exchangeBaseUrl: string,
|
||||||
): Promise<AmountJson> {
|
): Promise<AmountJson> {
|
||||||
const exchange = await oneShotGet(this.db, Stores.exchanges, exchangeBaseUrl);
|
const exchange = await oneShotGet(
|
||||||
|
this.db,
|
||||||
|
Stores.exchanges,
|
||||||
|
exchangeBaseUrl,
|
||||||
|
);
|
||||||
if (!exchange) {
|
if (!exchange) {
|
||||||
throw Error(`exchange ${exchangeBaseUrl} not found`);
|
throw Error(`exchange ${exchangeBaseUrl} not found`);
|
||||||
}
|
}
|
||||||
@ -1726,7 +1808,11 @@ export class Wallet {
|
|||||||
exchangeBaseUrl: string,
|
exchangeBaseUrl: string,
|
||||||
amount: AmountJson,
|
amount: AmountJson,
|
||||||
): Promise<DenominationRecord[]> {
|
): Promise<DenominationRecord[]> {
|
||||||
const exchange = await oneShotGet(this.db, Stores.exchanges, exchangeBaseUrl);
|
const exchange = await oneShotGet(
|
||||||
|
this.db,
|
||||||
|
Stores.exchanges,
|
||||||
|
exchangeBaseUrl,
|
||||||
|
);
|
||||||
if (!exchange) {
|
if (!exchange) {
|
||||||
throw Error(`exchange ${exchangeBaseUrl} not found`);
|
throw Error(`exchange ${exchangeBaseUrl} not found`);
|
||||||
}
|
}
|
||||||
@ -1780,9 +1866,11 @@ export class Wallet {
|
|||||||
if (!exchangeDetails) {
|
if (!exchangeDetails) {
|
||||||
throw Error(`exchange ${exchangeInfo.baseUrl} details not available`);
|
throw Error(`exchange ${exchangeInfo.baseUrl} details not available`);
|
||||||
}
|
}
|
||||||
const currencyRecord = await oneShotGet(this.db,
|
const currencyRecord = await oneShotGet(
|
||||||
|
this.db,
|
||||||
Stores.currencies,
|
Stores.currencies,
|
||||||
exchangeDetails.currency);
|
exchangeDetails.currency,
|
||||||
|
);
|
||||||
if (currencyRecord) {
|
if (currencyRecord) {
|
||||||
for (const trustedExchange of currencyRecord.exchanges) {
|
for (const trustedExchange of currencyRecord.exchanges) {
|
||||||
if (trustedExchange.exchangePub === exchangeDetails.masterPublicKey) {
|
if (trustedExchange.exchangePub === exchangeDetails.masterPublicKey) {
|
||||||
@ -1868,11 +1956,15 @@ export class Wallet {
|
|||||||
const possibleDenoms = await oneShotIterIndex(
|
const possibleDenoms = await oneShotIterIndex(
|
||||||
this.db,
|
this.db,
|
||||||
Stores.denominations.exchangeBaseUrlIndex,
|
Stores.denominations.exchangeBaseUrlIndex,
|
||||||
baseUrl)
|
baseUrl,
|
||||||
.filter((d) => d.isOffered);
|
).filter(d => d.isOffered);
|
||||||
|
|
||||||
const trustedAuditorPubs = [];
|
const trustedAuditorPubs = [];
|
||||||
const currencyRecord = await oneShotGet(this.db, Stores.currencies, amount.currency);
|
const currencyRecord = await oneShotGet(
|
||||||
|
this.db,
|
||||||
|
Stores.currencies,
|
||||||
|
amount.currency,
|
||||||
|
);
|
||||||
if (currencyRecord) {
|
if (currencyRecord) {
|
||||||
trustedAuditorPubs.push(
|
trustedAuditorPubs.push(
|
||||||
...currencyRecord.auditors.map(a => a.auditorPub),
|
...currencyRecord.auditors.map(a => a.auditorPub),
|
||||||
@ -1927,7 +2019,11 @@ export class Wallet {
|
|||||||
exchangeBaseUrl: string,
|
exchangeBaseUrl: string,
|
||||||
supportedTargetTypes: string[],
|
supportedTargetTypes: string[],
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const exchangeRecord = await oneShotGet(this.db, Stores.exchanges, exchangeBaseUrl);
|
const exchangeRecord = await oneShotGet(
|
||||||
|
this.db,
|
||||||
|
Stores.exchanges,
|
||||||
|
exchangeBaseUrl,
|
||||||
|
);
|
||||||
if (!exchangeRecord) {
|
if (!exchangeRecord) {
|
||||||
throw Error(`Exchange '${exchangeBaseUrl}' not found.`);
|
throw Error(`Exchange '${exchangeBaseUrl}' not found.`);
|
||||||
}
|
}
|
||||||
@ -1967,7 +2063,7 @@ export class Wallet {
|
|||||||
};
|
};
|
||||||
await oneShotPut(this.db, Stores.exchanges, newExchangeRecord);
|
await oneShotPut(this.db, Stores.exchanges, newExchangeRecord);
|
||||||
} else {
|
} else {
|
||||||
runWithWriteTransaction(this.db, [Stores.exchanges], async (t) => {
|
runWithWriteTransaction(this.db, [Stores.exchanges], async t => {
|
||||||
const rec = await t.get(Stores.exchanges, baseUrl);
|
const rec = await t.get(Stores.exchanges, baseUrl);
|
||||||
if (!rec) {
|
if (!rec) {
|
||||||
return;
|
return;
|
||||||
@ -1984,7 +2080,11 @@ export class Wallet {
|
|||||||
await this.updateExchangeWithKeys(baseUrl);
|
await this.updateExchangeWithKeys(baseUrl);
|
||||||
await this.updateExchangeWithWireInfo(baseUrl);
|
await this.updateExchangeWithWireInfo(baseUrl);
|
||||||
|
|
||||||
const updatedExchange = await oneShotGet(this.db, Stores.exchanges, baseUrl);
|
const updatedExchange = await oneShotGet(
|
||||||
|
this.db,
|
||||||
|
Stores.exchanges,
|
||||||
|
baseUrl,
|
||||||
|
);
|
||||||
|
|
||||||
if (!updatedExchange) {
|
if (!updatedExchange) {
|
||||||
// This should practically never happen
|
// This should practically never happen
|
||||||
@ -2011,9 +2111,15 @@ export class Wallet {
|
|||||||
* in the pending operations.
|
* in the pending operations.
|
||||||
*/
|
*/
|
||||||
private async updateExchangeWithKeys(baseUrl: string): Promise<void> {
|
private async updateExchangeWithKeys(baseUrl: string): Promise<void> {
|
||||||
const existingExchangeRecord = await oneShotGet(this.db, Stores.exchanges, baseUrl);
|
const existingExchangeRecord = await oneShotGet(
|
||||||
|
this.db,
|
||||||
|
Stores.exchanges,
|
||||||
|
baseUrl,
|
||||||
|
);
|
||||||
|
|
||||||
if (existingExchangeRecord?.updateStatus != ExchangeUpdateStatus.FETCH_KEYS) {
|
if (
|
||||||
|
existingExchangeRecord?.updateStatus != ExchangeUpdateStatus.FETCH_KEYS
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const keysUrl = new URI("keys")
|
const keysUrl = new URI("keys")
|
||||||
@ -2111,7 +2217,6 @@ export class Wallet {
|
|||||||
const wireInfo = ExchangeWireJson.checked(wiJson);
|
const wireInfo = ExchangeWireJson.checked(wiJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get detailed balance information, sliced by exchange and by currency.
|
* Get detailed balance information, sliced by exchange and by currency.
|
||||||
*/
|
*/
|
||||||
@ -2155,71 +2260,100 @@ export class Wallet {
|
|||||||
byExchange: {},
|
byExchange: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
await runWithWriteTransaction(this.db, [Stores.coins, Stores.refresh, Stores.reserves, Stores.purchases], async (tx) => {
|
await runWithWriteTransaction(
|
||||||
await tx.iter(Stores.coins).forEach((c) => {
|
this.db,
|
||||||
if (c.suspended) {
|
[Stores.coins, Stores.refresh, Stores.reserves, Stores.purchases],
|
||||||
return;
|
async tx => {
|
||||||
}
|
await tx.iter(Stores.coins).forEach(c => {
|
||||||
if (c.status === CoinStatus.Fresh) {
|
if (c.suspended) {
|
||||||
addTo(balanceStore, "available", c.currentAmount, c.exchangeBaseUrl);
|
return;
|
||||||
}
|
}
|
||||||
if (c.status === CoinStatus.Dirty) {
|
if (c.status === CoinStatus.Fresh) {
|
||||||
addTo(balanceStore, "pendingIncoming", c.currentAmount, c.exchangeBaseUrl);
|
addTo(
|
||||||
|
balanceStore,
|
||||||
|
"available",
|
||||||
|
c.currentAmount,
|
||||||
|
c.exchangeBaseUrl,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (c.status === CoinStatus.Dirty) {
|
||||||
|
addTo(
|
||||||
|
balanceStore,
|
||||||
|
"pendingIncoming",
|
||||||
|
c.currentAmount,
|
||||||
|
c.exchangeBaseUrl,
|
||||||
|
);
|
||||||
|
addTo(
|
||||||
|
balanceStore,
|
||||||
|
"pendingIncomingDirty",
|
||||||
|
c.currentAmount,
|
||||||
|
c.exchangeBaseUrl,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await tx.iter(Stores.refresh).forEach(r => {
|
||||||
|
// Don't count finished refreshes, since the refresh already resulted
|
||||||
|
// in coins being added to the wallet.
|
||||||
|
if (r.finished) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
addTo(
|
addTo(
|
||||||
balanceStore,
|
balanceStore,
|
||||||
"pendingIncomingDirty",
|
"pendingIncoming",
|
||||||
c.currentAmount,
|
r.valueOutput,
|
||||||
c.exchangeBaseUrl,
|
r.exchangeBaseUrl,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
});
|
|
||||||
await tx.iter(Stores.refresh).forEach((r) => {
|
|
||||||
// Don't count finished refreshes, since the refresh already resulted
|
|
||||||
// in coins being added to the wallet.
|
|
||||||
if (r.finished) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
addTo(balanceStore, "pendingIncoming", r.valueOutput, r.exchangeBaseUrl);
|
|
||||||
addTo(
|
|
||||||
balanceStore,
|
|
||||||
"pendingIncomingRefresh",
|
|
||||||
r.valueOutput,
|
|
||||||
r.exchangeBaseUrl,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
await tx.iter(Stores.reserves).forEach((r) => {
|
|
||||||
if (!r.timestamp_confirmed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let amount = Amounts.getZero(r.requested_amount.currency);
|
|
||||||
amount = Amounts.add(amount, r.precoin_amount).amount;
|
|
||||||
addTo(balanceStore, "pendingIncoming", amount, r.exchange_base_url);
|
|
||||||
addTo(balanceStore, "pendingIncomingWithdraw", amount, r.exchange_base_url);
|
|
||||||
});
|
|
||||||
|
|
||||||
await tx.iter(Stores.reserves).forEach((r) => {
|
|
||||||
if (!r.hasPayback) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
addTo(balanceStore, "paybackAmount", r.current_amount!, r.exchange_base_url);
|
|
||||||
return balanceStore;
|
|
||||||
});
|
|
||||||
|
|
||||||
await tx.iter(Stores.purchases).forEach((t) => {
|
|
||||||
if (t.finished) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (const c of t.payReq.coins) {
|
|
||||||
addTo(
|
addTo(
|
||||||
balanceStore,
|
balanceStore,
|
||||||
"pendingPayment",
|
"pendingIncomingRefresh",
|
||||||
Amounts.parseOrThrow(c.contribution),
|
r.valueOutput,
|
||||||
c.exchange_url,
|
r.exchangeBaseUrl,
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
});
|
|
||||||
});
|
await tx.iter(Stores.reserves).forEach(r => {
|
||||||
|
if (!r.timestamp_confirmed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let amount = Amounts.getZero(r.requested_amount.currency);
|
||||||
|
amount = Amounts.add(amount, r.precoin_amount).amount;
|
||||||
|
addTo(balanceStore, "pendingIncoming", amount, r.exchange_base_url);
|
||||||
|
addTo(
|
||||||
|
balanceStore,
|
||||||
|
"pendingIncomingWithdraw",
|
||||||
|
amount,
|
||||||
|
r.exchange_base_url,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
await tx.iter(Stores.reserves).forEach(r => {
|
||||||
|
if (!r.hasPayback) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
addTo(
|
||||||
|
balanceStore,
|
||||||
|
"paybackAmount",
|
||||||
|
r.current_amount!,
|
||||||
|
r.exchange_base_url,
|
||||||
|
);
|
||||||
|
return balanceStore;
|
||||||
|
});
|
||||||
|
|
||||||
|
await tx.iter(Stores.purchases).forEach(t => {
|
||||||
|
if (t.finished) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const c of t.payReq.coins) {
|
||||||
|
addTo(
|
||||||
|
balanceStore,
|
||||||
|
"pendingPayment",
|
||||||
|
Amounts.parseOrThrow(c.contribution),
|
||||||
|
c.exchange_url,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
Wallet.enableTracing && console.log("computed balances:", balanceStore);
|
Wallet.enableTracing && console.log("computed balances:", balanceStore);
|
||||||
return balanceStore;
|
return balanceStore;
|
||||||
@ -2253,7 +2387,11 @@ export class Wallet {
|
|||||||
throw Error("db inconsistent");
|
throw Error("db inconsistent");
|
||||||
}
|
}
|
||||||
|
|
||||||
const availableDenoms: DenominationRecord[] = await oneShotIterIndex(this.db, Stores.denominations.exchangeBaseUrlIndex, exchange.baseUrl).toArray();
|
const availableDenoms: DenominationRecord[] = await oneShotIterIndex(
|
||||||
|
this.db,
|
||||||
|
Stores.denominations.exchangeBaseUrlIndex,
|
||||||
|
exchange.baseUrl,
|
||||||
|
).toArray();
|
||||||
|
|
||||||
const availableAmount = Amounts.sub(coin.currentAmount, oldDenom.feeRefresh)
|
const availableAmount = Amounts.sub(coin.currentAmount, oldDenom.feeRefresh)
|
||||||
.amount;
|
.amount;
|
||||||
@ -2302,10 +2440,14 @@ export class Wallet {
|
|||||||
|
|
||||||
// Store refresh session and subtract refreshed amount from
|
// Store refresh session and subtract refreshed amount from
|
||||||
// coin in the same transaction.
|
// coin in the same transaction.
|
||||||
await runWithWriteTransaction(this.db, [Stores.refresh, Stores.coins], async (tx) => {
|
await runWithWriteTransaction(
|
||||||
key = await tx.put(Stores.refresh, refreshSession);
|
this.db,
|
||||||
await tx.mutate(Stores.coins, coin.coinPub, mutateCoin);
|
[Stores.refresh, Stores.coins],
|
||||||
});
|
async tx => {
|
||||||
|
key = await tx.put(Stores.refresh, refreshSession);
|
||||||
|
await tx.mutate(Stores.coins, coin.coinPub, mutateCoin);
|
||||||
|
},
|
||||||
|
);
|
||||||
this.notifier.notify();
|
this.notifier.notify();
|
||||||
|
|
||||||
if (!key || typeof key !== "number") {
|
if (!key || typeof key !== "number") {
|
||||||
@ -2319,7 +2461,10 @@ export class Wallet {
|
|||||||
|
|
||||||
async refresh(oldCoinPub: string): Promise<void> {
|
async refresh(oldCoinPub: string): Promise<void> {
|
||||||
const refreshImpl = async () => {
|
const refreshImpl = async () => {
|
||||||
const oldRefreshSessions = await oneShotIter(this.db, Stores.refresh).toArray();
|
const oldRefreshSessions = await oneShotIter(
|
||||||
|
this.db,
|
||||||
|
Stores.refresh,
|
||||||
|
).toArray();
|
||||||
for (const session of oldRefreshSessions) {
|
for (const session of oldRefreshSessions) {
|
||||||
if (session.finished) {
|
if (session.finished) {
|
||||||
continue;
|
continue;
|
||||||
@ -2395,7 +2540,11 @@ export class Wallet {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const coin = await oneShotGet(this.db, Stores.coins, refreshSession.meltCoinPub);
|
const coin = await oneShotGet(
|
||||||
|
this.db,
|
||||||
|
Stores.coins,
|
||||||
|
refreshSession.meltCoinPub,
|
||||||
|
);
|
||||||
|
|
||||||
if (!coin) {
|
if (!coin) {
|
||||||
console.error("can't melt coin, it does not exist");
|
console.error("can't melt coin, it does not exist");
|
||||||
@ -2451,7 +2600,11 @@ export class Wallet {
|
|||||||
throw Error("refresh index error");
|
throw Error("refresh index error");
|
||||||
}
|
}
|
||||||
|
|
||||||
const meltCoinRecord = await oneShotGet(this.db, Stores.coins, refreshSession.meltCoinPub);
|
const meltCoinRecord = await oneShotGet(
|
||||||
|
this.db,
|
||||||
|
Stores.coins,
|
||||||
|
refreshSession.meltCoinPub,
|
||||||
|
);
|
||||||
if (!meltCoinRecord) {
|
if (!meltCoinRecord) {
|
||||||
throw Error("inconsistent database");
|
throw Error("inconsistent database");
|
||||||
}
|
}
|
||||||
@ -2549,16 +2702,22 @@ export class Wallet {
|
|||||||
|
|
||||||
refreshSession.finished = true;
|
refreshSession.finished = true;
|
||||||
|
|
||||||
await runWithWriteTransaction(this.db, [Stores.coins, Stores.refresh], async (tx) => {
|
await runWithWriteTransaction(
|
||||||
for (let coin of coins) {
|
this.db,
|
||||||
await tx.put(Stores.coins, coin);
|
[Stores.coins, Stores.refresh],
|
||||||
}
|
async tx => {
|
||||||
await tx.put(Stores.refresh, refreshSession);
|
for (let coin of coins) {
|
||||||
});
|
await tx.put(Stores.coins, coin);
|
||||||
|
}
|
||||||
|
await tx.put(Stores.refresh, refreshSession);
|
||||||
|
},
|
||||||
|
);
|
||||||
this.notifier.notify();
|
this.notifier.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
async findExchange(exchangeBaseUrl: string): Promise<ExchangeRecord | undefined> {
|
async findExchange(
|
||||||
|
exchangeBaseUrl: string,
|
||||||
|
): Promise<ExchangeRecord | undefined> {
|
||||||
return await oneShotGet(this.db, Stores.exchanges, exchangeBaseUrl);
|
return await oneShotGet(this.db, Stores.exchanges, exchangeBaseUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2588,7 +2747,10 @@ export class Wallet {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const withdrawals = await oneShotIter(this.db, Stores.withdrawals).toArray();
|
const withdrawals = await oneShotIter(
|
||||||
|
this.db,
|
||||||
|
Stores.withdrawals,
|
||||||
|
).toArray();
|
||||||
for (const w of withdrawals) {
|
for (const w of withdrawals) {
|
||||||
history.push({
|
history.push({
|
||||||
detail: {
|
detail: {
|
||||||
@ -2721,7 +2883,11 @@ export class Wallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getDenoms(exchangeUrl: string): Promise<DenominationRecord[]> {
|
async getDenoms(exchangeUrl: string): Promise<DenominationRecord[]> {
|
||||||
const denoms = await oneShotIterIndex(this.db, Stores.denominations.exchangeBaseUrlIndex, exchangeUrl).toArray();
|
const denoms = await oneShotIterIndex(
|
||||||
|
this.db,
|
||||||
|
Stores.denominations.exchangeBaseUrlIndex,
|
||||||
|
exchangeUrl,
|
||||||
|
).toArray();
|
||||||
return denoms;
|
return denoms;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2747,15 +2913,21 @@ export class Wallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getReserves(exchangeBaseUrl: string): Promise<ReserveRecord[]> {
|
async getReserves(exchangeBaseUrl: string): Promise<ReserveRecord[]> {
|
||||||
return await oneShotIter(this.db, Stores.reserves).filter((r) => r.exchange_base_url === exchangeBaseUrl);
|
return await oneShotIter(this.db, Stores.reserves).filter(
|
||||||
|
r => r.exchange_base_url === exchangeBaseUrl,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCoins(exchangeBaseUrl: string): Promise<CoinRecord[]> {
|
async getCoins(exchangeBaseUrl: string): Promise<CoinRecord[]> {
|
||||||
return await oneShotIter(this.db, Stores.coins).filter((c) => c.exchangeBaseUrl === exchangeBaseUrl);
|
return await oneShotIter(this.db, Stores.coins).filter(
|
||||||
|
c => c.exchangeBaseUrl === exchangeBaseUrl,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPreCoins(exchangeBaseUrl: string): Promise<PreCoinRecord[]> {
|
async getPreCoins(exchangeBaseUrl: string): Promise<PreCoinRecord[]> {
|
||||||
return await oneShotIter(this.db, Stores.precoins).filter((c) => c.exchangeBaseUrl === exchangeBaseUrl);
|
return await oneShotIter(this.db, Stores.precoins).filter(
|
||||||
|
c => c.exchangeBaseUrl === exchangeBaseUrl,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async hashContract(contract: ContractTerms): Promise<string> {
|
private async hashContract(contract: ContractTerms): Promise<string> {
|
||||||
@ -2789,10 +2961,14 @@ export class Wallet {
|
|||||||
// technically we might update reserve status before we get the response
|
// technically we might update reserve status before we get the response
|
||||||
// from the reserve for the payback request.
|
// from the reserve for the payback request.
|
||||||
reserve.hasPayback = true;
|
reserve.hasPayback = true;
|
||||||
await runWithWriteTransaction(this.db, [Stores.coins, Stores.reserves], async (tx) => {
|
await runWithWriteTransaction(
|
||||||
await tx.put(Stores.coins, coin!!);
|
this.db,
|
||||||
await tx.put(Stores.reserves, reserve);
|
[Stores.coins, Stores.reserves],
|
||||||
});
|
async tx => {
|
||||||
|
await tx.put(Stores.coins, coin!!);
|
||||||
|
await tx.put(Stores.reserves, reserve);
|
||||||
|
},
|
||||||
|
);
|
||||||
this.notifier.notify();
|
this.notifier.notify();
|
||||||
|
|
||||||
const paybackRequest = await this.cryptoApi.createPaybackRequest(coin);
|
const paybackRequest = await this.cryptoApi.createPaybackRequest(coin);
|
||||||
@ -2851,7 +3027,9 @@ export class Wallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getPaybackReserves(): Promise<ReserveRecord[]> {
|
async getPaybackReserves(): Promise<ReserveRecord[]> {
|
||||||
return await oneShotIter(this.db, Stores.reserves).filter(r => r.hasPayback);
|
return await oneShotIter(this.db, Stores.reserves).filter(
|
||||||
|
r => r.hasPayback,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2865,7 +3043,7 @@ export class Wallet {
|
|||||||
async getSenderWireInfos(): Promise<SenderWireInfos> {
|
async getSenderWireInfos(): Promise<SenderWireInfos> {
|
||||||
const m: { [url: string]: Set<string> } = {};
|
const m: { [url: string]: Set<string> } = {};
|
||||||
|
|
||||||
await oneShotIter(this.db, Stores.exchanges).forEach((x) => {
|
await oneShotIter(this.db, Stores.exchanges).forEach(x => {
|
||||||
const wi = x.wireInfo;
|
const wi = x.wireInfo;
|
||||||
if (!wi) {
|
if (!wi) {
|
||||||
return;
|
return;
|
||||||
@ -2881,7 +3059,7 @@ export class Wallet {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const senderWiresSet: Set<string> = new Set();
|
const senderWiresSet: Set<string> = new Set();
|
||||||
await oneShotIter(this.db, Stores.senderWires).forEach((x) => {
|
await oneShotIter(this.db, Stores.senderWires).forEach(x => {
|
||||||
senderWiresSet.add(x.paytoUri);
|
senderWiresSet.add(x.paytoUri);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -2974,12 +3152,16 @@ export class Wallet {
|
|||||||
wire: req.senderWire,
|
wire: req.senderWire,
|
||||||
};
|
};
|
||||||
|
|
||||||
await runWithWriteTransaction(this.db, [Stores.coinsReturns, Stores.coins], async (tx) => {
|
await runWithWriteTransaction(
|
||||||
await tx.put(Stores.coinsReturns, coinsReturnRecord);
|
this.db,
|
||||||
for (let c of payCoinInfo.updatedCoins) {
|
[Stores.coinsReturns, Stores.coins],
|
||||||
await tx.put(Stores.coins, c);
|
async tx => {
|
||||||
}
|
await tx.put(Stores.coinsReturns, coinsReturnRecord);
|
||||||
});
|
for (let c of payCoinInfo.updatedCoins) {
|
||||||
|
await tx.put(Stores.coins, c);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
this.badge.showNotification();
|
this.badge.showNotification();
|
||||||
this.notifier.notify();
|
this.notifier.notify();
|
||||||
|
|
||||||
@ -3029,7 +3211,11 @@ export class Wallet {
|
|||||||
// FIXME: verify signature
|
// FIXME: verify signature
|
||||||
|
|
||||||
// For every successful deposit, we replace the old record with an updated one
|
// For every successful deposit, we replace the old record with an updated one
|
||||||
const currentCrr = await oneShotGet(this.db, Stores.coinsReturns, coinsReturnRecord.contractTermsHash);
|
const currentCrr = await oneShotGet(
|
||||||
|
this.db,
|
||||||
|
Stores.coinsReturns,
|
||||||
|
coinsReturnRecord.contractTermsHash,
|
||||||
|
);
|
||||||
if (!currentCrr) {
|
if (!currentCrr) {
|
||||||
console.error("database inconsistent");
|
console.error("database inconsistent");
|
||||||
continue;
|
continue;
|
||||||
@ -3114,7 +3300,11 @@ export class Wallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async submitRefunds(contractTermsHash: string): Promise<void> {
|
private async submitRefunds(contractTermsHash: string): Promise<void> {
|
||||||
const purchase = await oneShotGet(this.db, Stores.purchases, contractTermsHash);
|
const purchase = await oneShotGet(
|
||||||
|
this.db,
|
||||||
|
Stores.purchases,
|
||||||
|
contractTermsHash,
|
||||||
|
);
|
||||||
if (!purchase) {
|
if (!purchase) {
|
||||||
console.error(
|
console.error(
|
||||||
"not submitting refunds, contract terms not found:",
|
"not submitting refunds, contract terms not found:",
|
||||||
@ -3177,10 +3367,18 @@ export class Wallet {
|
|||||||
return c;
|
return c;
|
||||||
};
|
};
|
||||||
|
|
||||||
await runWithWriteTransaction(this.db, [Stores.purchases, Stores.coins], async (tx) => {
|
await runWithWriteTransaction(
|
||||||
await tx.mutate(Stores.purchases, contractTermsHash, transformPurchase);
|
this.db,
|
||||||
await tx.mutate(Stores.coins, perm.coin_pub, transformCoin);
|
[Stores.purchases, Stores.coins],
|
||||||
});
|
async tx => {
|
||||||
|
await tx.mutate(
|
||||||
|
Stores.purchases,
|
||||||
|
contractTermsHash,
|
||||||
|
transformPurchase,
|
||||||
|
);
|
||||||
|
await tx.mutate(Stores.coins, perm.coin_pub, transformCoin);
|
||||||
|
},
|
||||||
|
);
|
||||||
this.refresh(perm.coin_pub);
|
this.refresh(perm.coin_pub);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3200,7 +3398,11 @@ export class Wallet {
|
|||||||
if (refundPermissions.length === 0) {
|
if (refundPermissions.length === 0) {
|
||||||
throw Error("no refunds given");
|
throw Error("no refunds given");
|
||||||
}
|
}
|
||||||
const coin0 = await oneShotGet(this.db, Stores.coins, refundPermissions[0].coin_pub);
|
const coin0 = await oneShotGet(
|
||||||
|
this.db,
|
||||||
|
Stores.coins,
|
||||||
|
refundPermissions[0].coin_pub,
|
||||||
|
);
|
||||||
if (!coin0) {
|
if (!coin0) {
|
||||||
throw Error("coin not found");
|
throw Error("coin not found");
|
||||||
}
|
}
|
||||||
@ -3208,8 +3410,11 @@ export class Wallet {
|
|||||||
Amounts.parseOrThrow(refundPermissions[0].refund_amount).currency,
|
Amounts.parseOrThrow(refundPermissions[0].refund_amount).currency,
|
||||||
);
|
);
|
||||||
|
|
||||||
const denoms = await oneShotIterIndex(this.db, Stores.denominations.exchangeBaseUrlIndex,
|
const denoms = await oneShotIterIndex(
|
||||||
coin0.exchangeBaseUrl).toArray()
|
this.db,
|
||||||
|
Stores.denominations.exchangeBaseUrlIndex,
|
||||||
|
coin0.exchangeBaseUrl,
|
||||||
|
).toArray();
|
||||||
|
|
||||||
for (const rp of refundPermissions) {
|
for (const rp of refundPermissions) {
|
||||||
const coin = await oneShotGet(this.db, Stores.coins, rp.coin_pub);
|
const coin = await oneShotGet(this.db, Stores.coins, rp.coin_pub);
|
||||||
@ -3258,7 +3463,10 @@ export class Wallet {
|
|||||||
tipId: string,
|
tipId: string,
|
||||||
merchantOrigin: string,
|
merchantOrigin: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
let tipRecord = await oneShotGet(this.db, Stores.tips, [tipId, merchantOrigin]);
|
let tipRecord = await oneShotGet(this.db, Stores.tips, [
|
||||||
|
tipId,
|
||||||
|
merchantOrigin,
|
||||||
|
]);
|
||||||
if (!tipRecord) {
|
if (!tipRecord) {
|
||||||
throw Error("tip not in database");
|
throw Error("tip not in database");
|
||||||
}
|
}
|
||||||
@ -3282,7 +3490,7 @@ export class Wallet {
|
|||||||
);
|
);
|
||||||
const coinPubs: string[] = planchets.map(x => x.coinPub);
|
const coinPubs: string[] = planchets.map(x => x.coinPub);
|
||||||
|
|
||||||
await oneShotMutate(this.db, Stores.tips, [tipId, merchantOrigin], (r) => {
|
await oneShotMutate(this.db, Stores.tips, [tipId, merchantOrigin], r => {
|
||||||
if (!r.planchets) {
|
if (!r.planchets) {
|
||||||
r.planchets = planchets;
|
r.planchets = planchets;
|
||||||
r.coinPubs = coinPubs;
|
r.coinPubs = coinPubs;
|
||||||
@ -3376,7 +3584,7 @@ export class Wallet {
|
|||||||
let tipRecord = await oneShotGet(this.db, Stores.tips, [
|
let tipRecord = await oneShotGet(this.db, Stores.tips, [
|
||||||
res.tipId,
|
res.tipId,
|
||||||
res.merchantOrigin,
|
res.merchantOrigin,
|
||||||
])
|
]);
|
||||||
|
|
||||||
if (!tipRecord) {
|
if (!tipRecord) {
|
||||||
const withdrawDetails = await this.getWithdrawDetailsForAmount(
|
const withdrawDetails = await this.getWithdrawDetailsForAmount(
|
||||||
@ -3423,7 +3631,11 @@ export class Wallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async abortFailedPayment(contractTermsHash: string): Promise<void> {
|
async abortFailedPayment(contractTermsHash: string): Promise<void> {
|
||||||
const purchase = await oneShotGet(this.db, Stores.purchases, contractTermsHash);
|
const purchase = await oneShotGet(
|
||||||
|
this.db,
|
||||||
|
Stores.purchases,
|
||||||
|
contractTermsHash,
|
||||||
|
);
|
||||||
if (!purchase) {
|
if (!purchase) {
|
||||||
throw Error("Purchase not found, unable to abort with refund");
|
throw Error("Purchase not found, unable to abort with refund");
|
||||||
}
|
}
|
||||||
@ -3461,7 +3673,7 @@ export class Wallet {
|
|||||||
const refundResponse = MerchantRefundResponse.checked(resp.responseJson);
|
const refundResponse = MerchantRefundResponse.checked(resp.responseJson);
|
||||||
await this.acceptRefundResponse(refundResponse);
|
await this.acceptRefundResponse(refundResponse);
|
||||||
|
|
||||||
await runWithWriteTransaction(this.db, [Stores.purchases], async (tx) => {
|
await runWithWriteTransaction(this.db, [Stores.purchases], async tx => {
|
||||||
const p = await tx.get(Stores.purchases, purchase.contractTermsHash);
|
const p = await tx.get(Stores.purchases, purchase.contractTermsHash);
|
||||||
if (!p) {
|
if (!p) {
|
||||||
return;
|
return;
|
||||||
@ -3535,9 +3747,9 @@ export class Wallet {
|
|||||||
const refundsDoneAmounts = Object.values(purchase.refundsDone).map(x =>
|
const refundsDoneAmounts = Object.values(purchase.refundsDone).map(x =>
|
||||||
Amounts.parseOrThrow(x.refund_amount),
|
Amounts.parseOrThrow(x.refund_amount),
|
||||||
);
|
);
|
||||||
const refundsPendingAmounts = Object.values(purchase.refundsPending).map(
|
const refundsPendingAmounts = Object.values(
|
||||||
x => Amounts.parseOrThrow(x.refund_amount),
|
purchase.refundsPending,
|
||||||
);
|
).map(x => Amounts.parseOrThrow(x.refund_amount));
|
||||||
const totalRefundAmount = Amounts.sum([
|
const totalRefundAmount = Amounts.sum([
|
||||||
...refundsDoneAmounts,
|
...refundsDoneAmounts,
|
||||||
...refundsPendingAmounts,
|
...refundsPendingAmounts,
|
||||||
|
Loading…
Reference in New Issue
Block a user