show pending incoming amount
This commit is contained in:
parent
2780418c3e
commit
b0b737f72e
@ -324,6 +324,11 @@ namespace RpcFunctions {
|
|||||||
native.EddsaPrivateKey.fromCrock(
|
native.EddsaPrivateKey.fromCrock(
|
||||||
meltCoin.coinPriv)).toCrock();
|
meltCoin.coinPriv)).toCrock();
|
||||||
|
|
||||||
|
let valueOutput = Amounts.getZero(newCoinDenoms[0].value.currency);
|
||||||
|
for (let denom of newCoinDenoms) {
|
||||||
|
valueOutput = Amounts.add(valueOutput, denom.value).amount;
|
||||||
|
}
|
||||||
|
|
||||||
let refreshSession: RefreshSession = {
|
let refreshSession: RefreshSession = {
|
||||||
meltCoinPub: meltCoin.coinPub,
|
meltCoinPub: meltCoin.coinPub,
|
||||||
newDenoms: newCoinDenoms.map((d) => d.denom_pub),
|
newDenoms: newCoinDenoms.map((d) => d.denom_pub),
|
||||||
@ -336,6 +341,7 @@ namespace RpcFunctions {
|
|||||||
exchangeBaseUrl,
|
exchangeBaseUrl,
|
||||||
transferPrivs,
|
transferPrivs,
|
||||||
finished: false,
|
finished: false,
|
||||||
|
valueOutput,
|
||||||
};
|
};
|
||||||
|
|
||||||
return refreshSession;
|
return refreshSession;
|
||||||
|
@ -24,12 +24,19 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
|
||||||
|
export interface JoinResult<L,R> {
|
||||||
|
left: L;
|
||||||
|
right: R;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export class Store<T> {
|
export class Store<T> {
|
||||||
name: string;
|
name: string;
|
||||||
validator?: (v: T) => T;
|
validator?: (v: T) => T;
|
||||||
storeParams: IDBObjectStoreParameters;
|
storeParams: IDBObjectStoreParameters;
|
||||||
|
|
||||||
constructor(name: string, storeParams: IDBObjectStoreParameters, validator?: (v: T) => T) {
|
constructor(name: string, storeParams: IDBObjectStoreParameters,
|
||||||
|
validator?: (v: T) => T) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.validator = validator;
|
this.validator = validator;
|
||||||
this.storeParams = storeParams;
|
this.storeParams = storeParams;
|
||||||
@ -53,13 +60,16 @@ export class Index<S extends IDBValidKey,T> {
|
|||||||
*/
|
*/
|
||||||
export interface QueryStream<T> {
|
export interface QueryStream<T> {
|
||||||
indexJoin<S,I extends IDBValidKey>(index: Index<I,S>,
|
indexJoin<S,I extends IDBValidKey>(index: Index<I,S>,
|
||||||
keyFn: (obj: T) => I): QueryStream<[T, S]>;
|
keyFn: (obj: T) => I): QueryStream<[T, S]>;
|
||||||
filter(f: (x: any) => boolean): QueryStream<T>;
|
keyJoin<S,I extends IDBValidKey>(store: Store<S>,
|
||||||
|
keyFn: (obj: T) => I): QueryStream<JoinResult<T,S>>;
|
||||||
|
filter(f: (T: any) => boolean): QueryStream<T>;
|
||||||
reduce<S>(f: (v: T, acc: S) => S, start?: S): Promise<S>;
|
reduce<S>(f: (v: T, acc: S) => S, start?: S): Promise<S>;
|
||||||
flatMap(f: (x: T) => T[]): QueryStream<T>;
|
flatMap(f: (x: T) => T[]): QueryStream<T>;
|
||||||
toArray(): Promise<T[]>;
|
toArray(): Promise<T[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export let AbortTransaction = Symbol("abort_transaction");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an unresolved promise together with its extracted resolve / reject
|
* Get an unresolved promise together with its extracted resolve / reject
|
||||||
@ -96,11 +106,17 @@ abstract class QueryStreamBase<T> implements QueryStream<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
indexJoin<S,I extends IDBValidKey>(index: Index<I,S>,
|
indexJoin<S,I extends IDBValidKey>(index: Index<I,S>,
|
||||||
keyFn: (obj: T) => I): QueryStream<[T, S]> {
|
keyFn: (obj: T) => I): QueryStream<[T, S]> {
|
||||||
this.root.addStoreAccess(index.storeName, false);
|
this.root.addStoreAccess(index.storeName, false);
|
||||||
return new QueryStreamIndexJoin(this, index.storeName, index.indexName, keyFn);
|
return new QueryStreamIndexJoin(this, index.storeName, index.indexName, keyFn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
keyJoin<S, I extends IDBValidKey>(store: Store<S>,
|
||||||
|
keyFn: (obj: T) => I): QueryStream<JoinResult<T, S>> {
|
||||||
|
this.root.addStoreAccess(store.name, false);
|
||||||
|
return new QueryStreamKeyJoin(this, store.name, keyFn);
|
||||||
|
}
|
||||||
|
|
||||||
filter(f: (x: any) => boolean): QueryStream<T> {
|
filter(f: (x: any) => boolean): QueryStream<T> {
|
||||||
return new QueryStreamFilter(this, f);
|
return new QueryStreamFilter(this, f);
|
||||||
}
|
}
|
||||||
@ -234,6 +250,42 @@ class QueryStreamIndexJoin<T, S> extends QueryStreamBase<[T, S]> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class QueryStreamKeyJoin<T, S> extends QueryStreamBase<JoinResult<T, S>> {
|
||||||
|
s: QueryStreamBase<T>;
|
||||||
|
storeName: string;
|
||||||
|
key: any;
|
||||||
|
|
||||||
|
constructor(s: QueryStreamBase<T>, storeName: string,
|
||||||
|
key: any) {
|
||||||
|
super(s.root);
|
||||||
|
this.s = s;
|
||||||
|
this.storeName = storeName;
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
subscribe(f: SubscribeFn) {
|
||||||
|
this.s.subscribe((isDone, value, tx) => {
|
||||||
|
if (isDone) {
|
||||||
|
f(true, undefined, tx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log("joining on", this.key(value));
|
||||||
|
let s = tx.objectStore(this.storeName);
|
||||||
|
let req = s.openCursor(IDBKeyRange.only(this.key(value)));
|
||||||
|
req.onsuccess = () => {
|
||||||
|
let cursor = req.result;
|
||||||
|
if (cursor) {
|
||||||
|
f(false, {left:value, right: cursor.value}, tx);
|
||||||
|
cursor.continue();
|
||||||
|
} else {
|
||||||
|
f(true, undefined, tx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class IterQueryStream<T> extends QueryStreamBase<T> {
|
class IterQueryStream<T> extends QueryStreamBase<T> {
|
||||||
private storeName: string;
|
private storeName: string;
|
||||||
private options: any;
|
private options: any;
|
||||||
@ -304,7 +356,8 @@ export class QueryRoot {
|
|||||||
return new IterQueryStream(this, store.name, {});
|
return new IterQueryStream(this, store.name, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
iterIndex<S extends IDBValidKey,T>(index: Index<S,T>, only?: S): QueryStream<T> {
|
iterIndex<S extends IDBValidKey,T>(index: Index<S,T>,
|
||||||
|
only?: S): QueryStream<T> {
|
||||||
this.stores.add(index.storeName);
|
this.stores.add(index.storeName);
|
||||||
return new IterQueryStream(this, index.storeName, {
|
return new IterQueryStream(this, index.storeName, {
|
||||||
only,
|
only,
|
||||||
@ -326,6 +379,30 @@ export class QueryRoot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mutate<T>(store: Store<T>, key: any, f: (v: T) => T): QueryRoot {
|
||||||
|
let doPut = (tx: IDBTransaction) => {
|
||||||
|
let reqGet = tx.objectStore(store.name).get(key);
|
||||||
|
reqGet.onsuccess = () => {
|
||||||
|
let r = reqGet.result;
|
||||||
|
let m: T;
|
||||||
|
try {
|
||||||
|
m = f(r);
|
||||||
|
} catch (e) {
|
||||||
|
if (e == AbortTransaction) {
|
||||||
|
tx.abort();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.objectStore(store.name).put(m);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.addWork(doPut, store.name, true);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add all object from an iterable to the given object store.
|
* Add all object from an iterable to the given object store.
|
||||||
* Fails if the object's key is already present
|
* Fails if the object's key is already present
|
||||||
@ -380,7 +457,8 @@ export class QueryRoot {
|
|||||||
/**
|
/**
|
||||||
* Get one object from a store by its key.
|
* Get one object from a store by its key.
|
||||||
*/
|
*/
|
||||||
getIndexed<I extends IDBValidKey,T>(index: Index<I,T>, key: I): Promise<T|undefined> {
|
getIndexed<I extends IDBValidKey,T>(index: Index<I,T>,
|
||||||
|
key: I): Promise<T|undefined> {
|
||||||
if (key === void 0) {
|
if (key === void 0) {
|
||||||
throw Error("key must not be undefined");
|
throw Error("key must not be undefined");
|
||||||
}
|
}
|
||||||
@ -388,7 +466,9 @@ export class QueryRoot {
|
|||||||
const {resolve, promise} = openPromise();
|
const {resolve, promise} = openPromise();
|
||||||
|
|
||||||
const doGetIndexed = (tx: IDBTransaction) => {
|
const doGetIndexed = (tx: IDBTransaction) => {
|
||||||
const req = tx.objectStore(index.storeName).index(index.indexName).get(key);
|
const req = tx.objectStore(index.storeName)
|
||||||
|
.index(index.indexName)
|
||||||
|
.get(key);
|
||||||
req.onsuccess = () => {
|
req.onsuccess = () => {
|
||||||
resolve(req.result);
|
resolve(req.result);
|
||||||
};
|
};
|
||||||
@ -417,6 +497,9 @@ export class QueryRoot {
|
|||||||
tx.oncomplete = () => {
|
tx.oncomplete = () => {
|
||||||
resolve();
|
resolve();
|
||||||
};
|
};
|
||||||
|
tx.onabort = () => {
|
||||||
|
reject(Error("transaction aborted"));
|
||||||
|
};
|
||||||
for (let w of this.work) {
|
for (let w of this.work) {
|
||||||
w(tx);
|
w(tx);
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,12 @@ export class AmountJson {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface SignedAmountJson {
|
||||||
|
amount: AmountJson;
|
||||||
|
isNegative: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface ReserveRecord {
|
export interface ReserveRecord {
|
||||||
reserve_pub: string;
|
reserve_pub: string;
|
||||||
reserve_priv: string,
|
reserve_priv: string,
|
||||||
@ -194,6 +200,12 @@ export interface RefreshSession {
|
|||||||
*/
|
*/
|
||||||
valueWithFee: AmountJson
|
valueWithFee: AmountJson
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sum of the value of denominations we want
|
||||||
|
* to withdraw in this session, without fees.
|
||||||
|
*/
|
||||||
|
valueOutput: AmountJson;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signature to confirm the melting.
|
* Signature to confirm the melting.
|
||||||
*/
|
*/
|
||||||
@ -308,6 +320,15 @@ export class ExchangeHandle {
|
|||||||
static checked: (obj: any) => ExchangeHandle;
|
static checked: (obj: any) => ExchangeHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface WalletBalance {
|
||||||
|
[currency: string]: WalletBalanceEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WalletBalanceEntry {
|
||||||
|
available: AmountJson;
|
||||||
|
pendingIncoming: AmountJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Checkable.Class
|
@Checkable.Class
|
||||||
export class Contract {
|
export class Contract {
|
||||||
|
@ -27,10 +27,11 @@ import {
|
|||||||
IExchangeInfo,
|
IExchangeInfo,
|
||||||
Denomination,
|
Denomination,
|
||||||
Notifier,
|
Notifier,
|
||||||
WireInfo, RefreshSession, ReserveRecord, CoinPaySig
|
WireInfo, RefreshSession, ReserveRecord, CoinPaySig, WalletBalance,
|
||||||
|
WalletBalanceEntry
|
||||||
} from "./types";
|
} from "./types";
|
||||||
import {HttpResponse, RequestException} from "./http";
|
import {HttpResponse, RequestException} from "./http";
|
||||||
import {QueryRoot, Store, Index} from "./query";
|
import {QueryRoot, Store, Index, JoinResult, AbortTransaction} from "./query";
|
||||||
import {Checkable} from "./checkable";
|
import {Checkable} from "./checkable";
|
||||||
import {canonicalizeBaseUrl} from "./helpers";
|
import {canonicalizeBaseUrl} from "./helpers";
|
||||||
import {ReserveCreationInfo, Amounts} from "./types";
|
import {ReserveCreationInfo, Amounts} from "./types";
|
||||||
@ -904,10 +905,31 @@ export class Wallet {
|
|||||||
console.log("creating pre coin at", new Date());
|
console.log("creating pre coin at", new Date());
|
||||||
let preCoin = await this.cryptoApi
|
let preCoin = await this.cryptoApi
|
||||||
.createPreCoin(denom, reserve);
|
.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()
|
await this.q()
|
||||||
.put(Stores.precoins, preCoin)
|
.put(Stores.precoins, preCoin)
|
||||||
|
.mutate(Stores.reserves, reserve.reserve_pub, mutateReserve)
|
||||||
.finish();
|
.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
|
* Retrieve a mapping from currency name to the amount
|
||||||
* that is currenctly available for spending in the wallet.
|
* that is currenctly available for spending in the wallet.
|
||||||
*/
|
*/
|
||||||
async getBalances(): Promise<any> {
|
async getBalances(): Promise<WalletBalance> {
|
||||||
function collectBalances(c: Coin, byCurrency: any) {
|
function ensureEntry(balance: WalletBalance, currency: string) {
|
||||||
if (c.suspended) {
|
let entry: WalletBalanceEntry|undefined = balance[currency];
|
||||||
return byCurrency;
|
let z = Amounts.getZero(currency);
|
||||||
|
if (!entry) {
|
||||||
|
balance[currency] = entry = {
|
||||||
|
available: z,
|
||||||
|
pendingIncoming: z,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
let acc: AmountJson = byCurrency[c.currentAmount.currency];
|
return entry;
|
||||||
if (!acc) {
|
|
||||||
acc = Amounts.getZero(c.currentAmount.currency);
|
|
||||||
}
|
|
||||||
byCurrency[c.currentAmount.currency] = Amounts.add(c.currentAmount,
|
|
||||||
acc).amount;
|
|
||||||
return byCurrency;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let byCurrency = await (
|
function collectBalances(c: Coin, balance: WalletBalance) {
|
||||||
this.q()
|
if (c.suspended) {
|
||||||
.iter(Stores.coins)
|
return balance;
|
||||||
.reduce(collectBalances, {}));
|
}
|
||||||
|
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 entry = ensureEntry(balance, r.requested_amount.currency);
|
||||||
|
let amount = r.current_amount;
|
||||||
|
if (!amount) {
|
||||||
|
amount = r.requested_amount;
|
||||||
|
}
|
||||||
|
if (Amounts.cmp(smallestWithdraw[r.exchange_base_url], amount) < 0) {
|
||||||
|
entry.pendingIncoming = Amounts.add(entry.pendingIncoming,
|
||||||
|
amount).amount;
|
||||||
|
}
|
||||||
|
return balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
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};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,7 +28,10 @@
|
|||||||
import {substituteFulfillmentUrl} from "../lib/wallet/helpers";
|
import {substituteFulfillmentUrl} from "../lib/wallet/helpers";
|
||||||
import BrowserClickedEvent = chrome.browserAction.BrowserClickedEvent;
|
import BrowserClickedEvent = chrome.browserAction.BrowserClickedEvent;
|
||||||
import {HistoryRecord, HistoryLevel} from "../lib/wallet/wallet";
|
import {HistoryRecord, HistoryLevel} from "../lib/wallet/wallet";
|
||||||
import {AmountJson} from "../lib/wallet/types";
|
import {
|
||||||
|
AmountJson, WalletBalance, Amounts,
|
||||||
|
WalletBalanceEntry
|
||||||
|
} from "../lib/wallet/types";
|
||||||
import {abbrev, prettyAmount} from "../lib/wallet/renderHtml";
|
import {abbrev, prettyAmount} from "../lib/wallet/renderHtml";
|
||||||
|
|
||||||
declare var i18n: any;
|
declare var i18n: any;
|
||||||
@ -104,11 +107,11 @@ export function main() {
|
|||||||
<div>
|
<div>
|
||||||
<WalletNavBar />
|
<WalletNavBar />
|
||||||
<div style="margin:1em">
|
<div style="margin:1em">
|
||||||
<Router>
|
<Router>
|
||||||
<WalletBalance route="/balance" default/>
|
<WalletBalanceView route="/balance" default/>
|
||||||
<WalletHistory route="/history"/>
|
<WalletHistory route="/history"/>
|
||||||
<WalletDebug route="/debug"/>
|
<WalletDebug route="/debug"/>
|
||||||
</Router>
|
</Router>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -183,8 +186,8 @@ function ExtensionLink(props: any) {
|
|||||||
</a>)
|
</a>)
|
||||||
}
|
}
|
||||||
|
|
||||||
class WalletBalance extends preact.Component<any, any> {
|
class WalletBalanceView extends preact.Component<any, any> {
|
||||||
myWallet: any;
|
balance: WalletBalance;
|
||||||
gotError = false;
|
gotError = false;
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
@ -203,22 +206,31 @@ class WalletBalance extends preact.Component<any, any> {
|
|||||||
}
|
}
|
||||||
this.gotError = false;
|
this.gotError = false;
|
||||||
console.log("got wallet", resp);
|
console.log("got wallet", resp);
|
||||||
this.myWallet = resp.balances;
|
this.balance = resp;
|
||||||
this.setState({});
|
this.setState({});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderEmpty() : JSX.Element {
|
renderEmpty(): JSX.Element {
|
||||||
let helpLink = (
|
let helpLink = (
|
||||||
<ExtensionLink target="pages/help/empty-wallet.html">
|
<ExtensionLink target="pages/help/empty-wallet.html">
|
||||||
help
|
help
|
||||||
</ExtensionLink>
|
</ExtensionLink>
|
||||||
);
|
);
|
||||||
return <div>You have no balance to show. Need some {helpLink} getting started?</div>;
|
return <div>You have no balance to show. Need some {helpLink}
|
||||||
|
getting started?</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
formatPending(amount: AmountJson) {
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
(<span style="color: darkgreen">{prettyAmount(amount)}</span> pending)
|
||||||
|
</span>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
render(): JSX.Element {
|
render(): JSX.Element {
|
||||||
let wallet = this.myWallet;
|
let wallet = this.balance;
|
||||||
if (this.gotError) {
|
if (this.gotError) {
|
||||||
return i18n`Error: could not retrieve balance information.`;
|
return i18n`Error: could not retrieve balance information.`;
|
||||||
}
|
}
|
||||||
@ -227,7 +239,18 @@ class WalletBalance extends preact.Component<any, any> {
|
|||||||
}
|
}
|
||||||
console.log(wallet);
|
console.log(wallet);
|
||||||
let listing = Object.keys(wallet).map((key) => {
|
let listing = Object.keys(wallet).map((key) => {
|
||||||
return <p>{prettyAmount(wallet[key])}</p>
|
let entry: WalletBalanceEntry = wallet[key];
|
||||||
|
return (
|
||||||
|
<p>
|
||||||
|
{prettyAmount(entry.available)}
|
||||||
|
{ " "}
|
||||||
|
{Amounts.isNonZero(entry.pendingIncoming)
|
||||||
|
? this.formatPending(entry.pendingIncoming)
|
||||||
|
: []
|
||||||
|
}
|
||||||
|
|
||||||
|
</p>
|
||||||
|
);
|
||||||
});
|
});
|
||||||
if (listing.length > 0) {
|
if (listing.length > 0) {
|
||||||
return <div>{listing}</div>;
|
return <div>{listing}</div>;
|
||||||
|
Loading…
Reference in New Issue
Block a user