diff options
Diffstat (limited to 'lib/wallet/wallet.ts')
-rw-r--r-- | lib/wallet/wallet.ts | 129 |
1 files changed, 112 insertions, 17 deletions
diff --git a/lib/wallet/wallet.ts b/lib/wallet/wallet.ts index ca8aa895e..380243b44 100644 --- a/lib/wallet/wallet.ts +++ b/lib/wallet/wallet.ts @@ -27,10 +27,11 @@ import { IExchangeInfo, Denomination, Notifier, - WireInfo, RefreshSession, ReserveRecord, CoinPaySig + WireInfo, RefreshSession, ReserveRecord, CoinPaySig, WalletBalance, + WalletBalanceEntry } from "./types"; import {HttpResponse, RequestException} from "./http"; -import {QueryRoot, Store, Index} from "./query"; +import {QueryRoot, Store, Index, JoinResult, AbortTransaction} from "./query"; import {Checkable} from "./checkable"; import {canonicalizeBaseUrl} from "./helpers"; import {ReserveCreationInfo, Amounts} from "./types"; @@ -904,10 +905,31 @@ export class Wallet { console.log("creating pre coin at", new Date()); let preCoin = await this.cryptoApi .createPreCoin(denom, reserve); + + let aborted = false; + + function mutateReserve(r: ReserveRecord) { + let currentAmount = r.current_amount; + if (!currentAmount) { + throw Error("can't withdraw from reserve when current amount is" + + " unknown"); + } + let x = Amounts.sub(currentAmount, preCoin.coinValue); + if (x.saturated) { + aborted = true; + throw AbortTransaction; + } + r.current_amount = x.amount; + return r; + } + await this.q() .put(Stores.precoins, preCoin) + .mutate(Stores.reserves, reserve.reserve_pub, mutateReserve) .finish(); - await this.processPreCoin(preCoin); + if (!aborted) { + await this.processPreCoin(preCoin); + } } @@ -1155,26 +1177,99 @@ export class Wallet { * Retrieve a mapping from currency name to the amount * that is currenctly available for spending in the wallet. */ - async getBalances(): Promise<any> { - function collectBalances(c: Coin, byCurrency: any) { + async getBalances(): Promise<WalletBalance> { + function ensureEntry(balance: WalletBalance, currency: string) { + let entry: WalletBalanceEntry|undefined = balance[currency]; + let z = Amounts.getZero(currency); + if (!entry) { + balance[currency] = entry = { + available: z, + pendingIncoming: z, + }; + } + return entry; + } + + function collectBalances(c: Coin, balance: WalletBalance) { if (c.suspended) { - return byCurrency; + return balance; + } + let currency = c.currentAmount.currency; + let entry = ensureEntry(balance, currency); + entry.available = Amounts.add(entry.available, c.currentAmount).amount; + return balance; + } + + function collectPendingWithdraw(r: ReserveRecord, balance: WalletBalance) { + if (!r.confirmed) { + return balance; } - let acc: AmountJson = byCurrency[c.currentAmount.currency]; - if (!acc) { - acc = Amounts.getZero(c.currentAmount.currency); + let entry = ensureEntry(balance, r.requested_amount.currency); + let amount = r.current_amount; + if (!amount) { + amount = r.requested_amount; } - byCurrency[c.currentAmount.currency] = Amounts.add(c.currentAmount, - acc).amount; - return byCurrency; + if (Amounts.cmp(smallestWithdraw[r.exchange_base_url], amount) < 0) { + entry.pendingIncoming = Amounts.add(entry.pendingIncoming, + amount).amount; + } + return balance; } - let byCurrency = await ( - this.q() - .iter(Stores.coins) - .reduce(collectBalances, {})); + function collectPendingRefresh(r: RefreshSession, balance: WalletBalance) { + if (!r.finished) { + return balance; + } + let entry = ensureEntry(balance, r.valueWithFee.currency); + entry.pendingIncoming = Amounts.add(entry.pendingIncoming, + r.valueOutput).amount; + + return balance; + } + + function collectSmallestWithdraw(e: IExchangeInfo, sw: any) { + let min: AmountJson|undefined; + for (let d of e.active_denoms) { + let v = Amounts.add(d.value, d.fee_withdraw).amount; + if (!min) { + min = v; + continue; + } + if (Amounts.cmp(v, min) < 0) { + min = v; + } + } + sw[e.baseUrl] = min; + return sw; + } + + let balance = {}; + // Mapping from exchange pub to smallest + // possible amount we can withdraw + let smallestWithdraw: {[baseUrl: string]: AmountJson} = {}; + + smallestWithdraw = await (this.q() + .iter(Stores.exchanges) + .reduce(collectSmallestWithdraw, {})); + + console.log("smallest withdraw", smallestWithdraw); + + await (this.q() + .iter(Stores.coins) + .reduce(collectBalances, balance)); + + 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); + return balance; - return {balances: byCurrency}; } |