From e6763f3fac0d2c9e6f7459499b960b4d5c54fc66 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Wed, 19 Oct 2016 22:49:03 +0200 Subject: [PATCH] show pending outgoing balance in overview --- lib/wallet/types.ts | 33 +++++++++++++++------------ lib/wallet/wallet.ts | 46 +++++++++++++++++++++++++++++-------- pages/tree.tsx | 3 +++ popup/popup.tsx | 54 ++++++++++++++++++++++++++++++++++---------- 4 files changed, 101 insertions(+), 35 deletions(-) diff --git a/lib/wallet/types.ts b/lib/wallet/types.ts index 1edfa3601..2df8094a7 100644 --- a/lib/wallet/types.ts +++ b/lib/wallet/types.ts @@ -327,6 +327,7 @@ export interface WalletBalance { export interface WalletBalanceEntry { available: AmountJson; pendingIncoming: AmountJson; + pendingPayment: AmountJson; } @@ -432,26 +433,30 @@ export namespace Amounts { } - export function sub(a: AmountJson, b: AmountJson): Result { - if (a.currency !== b.currency) { - throw Error(`Mismatched currency: ${a.currency} and ${b.currency}`); - } + export function sub(a: AmountJson, ...rest: AmountJson[]): Result { let currency = a.currency; let value = a.value; let fraction = a.fraction; - if (fraction < b.fraction) { - if (value < 1) { + + for (let b of rest) { + if (b.currency !== currency) { + throw Error(`Mismatched currency: ${b.currency} and ${currency}`); + } + if (fraction < b.fraction) { + if (value < 1) { + return { amount: { currency, value: 0, fraction: 0 }, saturated: true }; + } + value--; + fraction += 1e6; + } + console.assert(fraction >= b.fraction); + fraction -= b.fraction; + if (value < b.value) { return { amount: { currency, value: 0, fraction: 0 }, saturated: true }; } - value--; - fraction += 1e6; + value -= b.value; } - console.assert(fraction >= b.fraction); - fraction -= b.fraction; - if (value < b.value) { - return { amount: { currency, value: 0, fraction: 0 }, saturated: true }; - } - value -= b.value; + return { amount: { currency, value, fraction }, saturated: false }; } diff --git a/lib/wallet/wallet.ts b/lib/wallet/wallet.ts index 851b7b048..f66e42e29 100644 --- a/lib/wallet/wallet.ts +++ b/lib/wallet/wallet.ts @@ -153,6 +153,12 @@ interface Transaction { contract: Contract; payReq: PayReq; merchantSig: string; + + /** + * The transaction isn't active anymore, it's either successfully paid + * or refunded/aborted. + */ + finished: boolean; } export enum HistoryLevel { @@ -461,7 +467,8 @@ export class Wallet { let x: number; - function storeExchangeCoin(mc: JoinResult, url: string) { + function storeExchangeCoin(mc: JoinResult, + url: string) { let exchange: IExchangeInfo = mc.left; console.log("got coin for exchange", url); let coin: Coin = mc.right; @@ -584,6 +591,7 @@ export class Wallet { contract: offer.contract, payReq: payReq, merchantSig: offer.merchant_sig, + finished: false, }; let historyEntry: HistoryRecord = { @@ -835,6 +843,7 @@ export class Wallet { .put(Stores.reserves, reserve) .put(Stores.history, historyEntry) .finish(); + this.notifier.notify(); this.processReserve(reserve); } @@ -915,7 +924,7 @@ export class Wallet { throw Error("can't withdraw from reserve when current amount is" + " unknown"); } - let x = Amounts.sub(currentAmount, preCoin.coinValue); + let x = Amounts.sub(currentAmount, preCoin.coinValue, denom.fee_withdraw); if (x.saturated) { aborted = true; throw AbortTransaction; @@ -928,6 +937,7 @@ export class Wallet { .put(Stores.precoins, preCoin) .mutate(Stores.reserves, reserve.reserve_pub, mutateReserve) .finish(); + this.notifier.notify(); if (!aborted) { await this.processPreCoin(preCoin); } @@ -987,6 +997,7 @@ export class Wallet { await this.q() .put(Stores.reserves, reserve) .finish(); + this.notifier.notify(); return reserve; } @@ -1186,6 +1197,7 @@ export class Wallet { balance[currency] = entry = { available: z, pendingIncoming: z, + pendingPayment: z, }; } return entry; @@ -1228,6 +1240,17 @@ export class Wallet { return balance; } + function collectPayments(t: Transaction, balance: WalletBalance) { + if (t.finished) { + return balance; + } + let entry = ensureEntry(balance, t.contract.amount.currency); + entry.pendingPayment = Amounts.add(entry.pendingPayment, + t.contract.amount).amount; + + return balance; + } + function collectSmallestWithdraw(e: IExchangeInfo, sw: any) { let min: AmountJson|undefined; for (let d of e.active_denoms) { @@ -1253,8 +1276,7 @@ export class Wallet { .iter(Stores.exchanges) .reduce(collectSmallestWithdraw, {})); - console.log("smallest withdraw", smallestWithdraw); - + console.log("smallest withdraws", smallestWithdraw) await (this.q() .iter(Stores.coins) .reduce(collectBalances, balance)); @@ -1262,13 +1284,12 @@ export class Wallet { await (this.q() .iter(Stores.refresh) .reduce(collectPendingRefresh, balance)); - - console.log("balances collected"); - await (this.q() .iter(Stores.reserves) .reduce(collectPendingWithdraw, balance)); - console.log("balance", balance); + await (this.q() + .iter(Stores.transactions) + .reduce(collectPayments, balance)); return balance; } @@ -1583,6 +1604,8 @@ export class Wallet { console.error("contract not found"); return; } + t.finished = true; + let modifiedCoins: Coin[] = []; for (let pc of t.payReq.coins) { let c = await this.q().get(Stores.coins, pc.coin_pub); if (!c) { @@ -1590,8 +1613,13 @@ export class Wallet { return; } c.transactionPending = false; - await this.q().put(Stores.coins, c).finish(); + modifiedCoins.push(c); } + + await this.q() + .putAll(Stores.coins, modifiedCoins) + .put(Stores.transactions, t) + .finish(); for (let c of t.payReq.coins) { this.refresh(c.coin_pub); } diff --git a/pages/tree.tsx b/pages/tree.tsx index 0d1046b34..e782877a5 100644 --- a/pages/tree.tsx +++ b/pages/tree.tsx @@ -43,6 +43,9 @@ class ReserveView extends preact.Component {
  • Key: {r.reserve_pub}
  • Created: {(new Date(r.created * 1000).toString())}
  • +
  • Current: {r.current_amount ? prettyAmount(r.current_amount!) : "null"}
  • +
  • Requested: {prettyAmount(r.requested_amount)}
  • +
  • Confirmed: {r.confirmed}
); diff --git a/popup/popup.tsx b/popup/popup.tsx index 31f950c21..121562e31 100644 --- a/popup/popup.tsx +++ b/popup/popup.tsx @@ -221,12 +221,46 @@ class WalletBalanceView extends preact.Component { getting started?; } - formatPending(amount: AmountJson) { - return ( - - ({prettyAmount(amount)} pending) - - ); + formatPending(entry: WalletBalanceEntry): JSX.Element { + let incoming: JSX.Element | undefined; + let payment: JSX.Element | undefined; + + console.log("available: ", entry.pendingIncoming ? prettyAmount(entry.available) : null); + console.log("incoming: ", entry.pendingIncoming ? prettyAmount(entry.pendingIncoming) : null); + + if (Amounts.isNonZero(entry.pendingIncoming)) { + incoming = ( + + + {"+"} + {prettyAmount(entry.pendingIncoming)} + + {" "} + incoming + ); + } + + if (Amounts.isNonZero(entry.pendingPayment)) { + payment = ( + + + {prettyAmount(entry.pendingPayment)} + + {" "} + being spent + ); + } + + let l = [incoming, payment].filter((x) => x !== undefined); + if (l.length == 0) { + return ; + } + + if (l.length == 1) { + return ({l}) + } + return ({l[0]}, {l[1]}); + } render(): JSX.Element { @@ -243,12 +277,8 @@ class WalletBalanceView extends preact.Component { return (

{prettyAmount(entry.available)} - { " "} - {Amounts.isNonZero(entry.pendingIncoming) - ? this.formatPending(entry.pendingIncoming) - : [] - } - + {" "} + {this.formatPending(entry)}

); });