mirror of https://github.com/BTCPrivate/copay.git
[V4] Feat: Show wallet total inputs and fix getMinAmount function
This commit is contained in:
parent
4a042b9954
commit
89efc4ec1f
|
@ -7,12 +7,14 @@
|
||||||
<ion-content>
|
<ion-content>
|
||||||
<page-wallet-item [wallet]="wallet"></page-wallet-item>
|
<page-wallet-item [wallet]="wallet"></page-wallet-item>
|
||||||
<div class="comment">
|
<div class="comment">
|
||||||
<span translate>Each bitcoin wallet can generate billions of addresses from your 12-word backup.
|
<span translate>Each bitcoin wallet can generate billions of addresses from your 12-word backup. A new address is automatically generated
|
||||||
A new address is automatically generated and shown each time you receive a payment.
|
and shown each time you receive a payment.
|
||||||
</span><a (click)="showInfo = !showInfo" *ngIf="!showInfo" translate>Why?</a>
|
</span>
|
||||||
|
<a (click)="showInfo = !showInfo" *ngIf="!showInfo" translate>Why?</a>
|
||||||
|
|
||||||
<div *ngIf="showInfo">
|
<div *ngIf="showInfo">
|
||||||
<span translate>It's a good idea to avoid reusing addresses - this both protects your privacy and keeps your bitcoins secure against hypothetical attacks by quantum computers.</span>
|
<span translate>It's a good idea to avoid reusing addresses - this both protects your privacy and keeps your bitcoins secure against
|
||||||
|
hypothetical attacks by quantum computers.</span>
|
||||||
<a (click)="showInfo = !showInfo" translate>Hide</a>
|
<a (click)="showInfo = !showInfo" translate>Hide</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -41,10 +43,14 @@
|
||||||
<div *ngIf="latestUnused && latestUnused[0]">
|
<div *ngIf="latestUnused && latestUnused[0]">
|
||||||
<div *ngIf="gapReached">
|
<div *ngIf="gapReached">
|
||||||
<h5 translate>Unused addresses limit</h5>
|
<h5 translate>Unused addresses limit</h5>
|
||||||
<p><span translate>The maximum number of consecutive unused addresses (20) has been reached. When one of your unused addresses receives a payment, a new address will be generated and shown in your Receive tab.</span> 
|
<p>
|
||||||
|
<span translate>The maximum number of consecutive unused addresses (20) has been reached. When one of your unused addresses receives
|
||||||
|
a payment, a new address will be generated and shown in your Receive tab.</span> 
|
||||||
<a (click)="readMore()" *ngIf="!showMore" translate>Read more</a>
|
<a (click)="readMore()" *ngIf="!showMore" translate>Read more</a>
|
||||||
</p>
|
</p>
|
||||||
<p *ngIf="showMore"><span translate>The restore process will stop when 20 addresses are generated in a row which contain no funds. To safely generate more addresses, make a payment to one of the unused addresses which has already been generated.</span> 
|
<p *ngIf="showMore">
|
||||||
|
<span translate>The restore process will stop when 20 addresses are generated in a row which contain no funds. To safely generate
|
||||||
|
more addresses, make a payment to one of the unused addresses which has already been generated.</span> 
|
||||||
<a (click)="readMore()" translate>Read less</a>
|
<a (click)="readMore()" translate>Read less</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -65,7 +71,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="allUtxosNb">
|
<div *ngIf="allUtxosNb">
|
||||||
<ion-item-divider>{{'Wallet Inputs' | translate}}</ion-item-divider>
|
<ion-item-divider color="light">{{'Wallet Inputs' | translate}}</ion-item-divider>
|
||||||
|
|
||||||
<ion-item>
|
<ion-item>
|
||||||
<span translate>Total wallet inputs</span>
|
<span translate>Total wallet inputs</span>
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { WalletProvider } from '../../../../../providers/wallet/wallet';
|
||||||
import { BwcErrorProvider } from '../../../../../providers/bwc-error/bwc-error';
|
import { BwcErrorProvider } from '../../../../../providers/bwc-error/bwc-error';
|
||||||
import { PopupProvider } from '../../../../../providers/popup/popup';
|
import { PopupProvider } from '../../../../../providers/popup/popup';
|
||||||
import { OnGoingProcessProvider } from '../../../../../providers/on-going-process/on-going-process';
|
import { OnGoingProcessProvider } from '../../../../../providers/on-going-process/on-going-process';
|
||||||
|
import { TxFormatProvider } from '../../../../../providers/tx-format/tx-format';
|
||||||
|
|
||||||
//pages
|
//pages
|
||||||
import { AllAddressesPage } from './all-addresses/all-addresses';
|
import { AllAddressesPage } from './all-addresses/all-addresses';
|
||||||
|
@ -28,6 +29,13 @@ export class WalletAddressesPage {
|
||||||
public latestWithBalance: any;
|
public latestWithBalance: any;
|
||||||
public viewAll: boolean;
|
public viewAll: boolean;
|
||||||
public gapReached: boolean;
|
public gapReached: boolean;
|
||||||
|
public lowUtxosNb: number;
|
||||||
|
public allUtxosNb: number;
|
||||||
|
public lowUtxosSum: string;
|
||||||
|
public allUtxosSum: string;
|
||||||
|
public minFee: string;
|
||||||
|
public minFeePer: string;
|
||||||
|
|
||||||
private UNUSED_ADDRESS_LIMIT: number;
|
private UNUSED_ADDRESS_LIMIT: number;
|
||||||
private BALANCE_ADDRESS_LIMIT: number;
|
private BALANCE_ADDRESS_LIMIT: number;
|
||||||
private withBalance: any;
|
private withBalance: any;
|
||||||
|
@ -43,6 +51,7 @@ export class WalletAddressesPage {
|
||||||
private popupProvider: PopupProvider,
|
private popupProvider: PopupProvider,
|
||||||
private onGoingProcessProvider: OnGoingProcessProvider,
|
private onGoingProcessProvider: OnGoingProcessProvider,
|
||||||
private modalCtrl: ModalController,
|
private modalCtrl: ModalController,
|
||||||
|
private txFormatProvider: TxFormatProvider
|
||||||
) {
|
) {
|
||||||
this.UNUSED_ADDRESS_LIMIT = 5;
|
this.UNUSED_ADDRESS_LIMIT = 5;
|
||||||
this.BALANCE_ADDRESS_LIMIT = 5;
|
this.BALANCE_ADDRESS_LIMIT = 5;
|
||||||
|
@ -79,6 +88,26 @@ export class WalletAddressesPage {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.popupProvider.ionicAlert(this.bwcErrorProvider.msg(err, 'Could not update wallet')); //TODO gettextcatalog
|
this.popupProvider.ionicAlert(this.bwcErrorProvider.msg(err, 'Could not update wallet')); //TODO gettextcatalog
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.walletProvider.getLowUtxos(this.wallet).then((resp) => {
|
||||||
|
|
||||||
|
if (resp && resp.allUtxos && resp.allUtxos.length) {
|
||||||
|
|
||||||
|
let allSum = _.sumBy(resp.allUtxos || 0, 'satoshis');
|
||||||
|
let per = (resp.minFee / allSum) * 100;
|
||||||
|
|
||||||
|
this.lowUtxosNb = resp.lowUtxos.length;
|
||||||
|
this.allUtxosNb = resp.allUtxos.length;
|
||||||
|
this.lowUtxosSum = this.txFormatProvider.formatAmountStr(this.wallet.coin, _.sumBy(resp.lowUtxos || 0, 'satoshis'));
|
||||||
|
this.allUtxosSum = this.txFormatProvider.formatAmountStr(this.wallet.coin, allSum);
|
||||||
|
this.minFee = this.txFormatProvider.formatAmountStr(this.wallet.coin, resp.minFee || 0);
|
||||||
|
this.minFeePer = per.toFixed(2) + '%';
|
||||||
|
|
||||||
|
}
|
||||||
|
}).catch((err) => {
|
||||||
|
this.logger.warn(err);
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private processPaths(list: any): void {
|
private processPaths(list: any): void {
|
||||||
|
|
|
@ -10,11 +10,13 @@
|
||||||
<ion-label stacked translate>Wallet Service URL</ion-label>
|
<ion-label stacked translate>Wallet Service URL</ion-label>
|
||||||
<ion-input type="text" formControlName="bwsurl" [value]="walletServiceForm.value.bwsurl" required></ion-input>
|
<ion-input type="text" formControlName="bwsurl" [value]="walletServiceForm.value.bwsurl" required></ion-input>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<div translate>
|
<div class="comment">
|
||||||
{{appName}} depends on Bitcore Wallet Service (BWS) for blockchain information, networking and Copayer synchronization. The
|
<span translate>{{appName}} depends on Bitcore Wallet Service (BWS) for blockchain information, networking and Copayer synchronization.
|
||||||
default configuration points to https://bws.bitpay.com (BitPay's public BWS instance).
|
The default configuration points to https://bws.bitpay.com (BitPay's public BWS instance).</span>
|
||||||
|
<a (click)="resetDefaultUrl()" translate>
|
||||||
|
Use default url
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<button ion-button (click)="resetDefaultUrl()"><ion-icon name="refresh"></ion-icon></button>
|
|
||||||
<button ion-button block type="submit" [disabled]="!walletServiceForm.valid">Save</button>
|
<button ion-button block type="submit" [disabled]="!walletServiceForm.valid">Save</button>
|
||||||
</form>
|
</form>
|
||||||
</ion-content>
|
</ion-content>
|
|
@ -0,0 +1,5 @@
|
||||||
|
page-wallet-service-url {
|
||||||
|
.comment {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,7 +26,7 @@
|
||||||
<span translate>Clear cache</span>
|
<span translate>Clear cache</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div translate>
|
<div class="comment" translate>
|
||||||
The transaction history and every new incoming transaction are cached in the app. This feature clean this up and synchronizes
|
The transaction history and every new incoming transaction are cached in the app. This feature clean this up and synchronizes
|
||||||
again from the server
|
again from the server
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,4 +4,7 @@ page-wallet-transaction-history {
|
||||||
color: color($colors, primary) !important;
|
color: color($colors, primary) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.comment {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -24,6 +24,7 @@ export class FeeProvider {
|
||||||
updateTs: 0,
|
updateTs: 0,
|
||||||
coin: ''
|
coin: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private configProvider: ConfigProvider,
|
private configProvider: ConfigProvider,
|
||||||
private logger: Logger,
|
private logger: Logger,
|
||||||
|
@ -106,5 +107,4 @@ export class FeeProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,8 +55,6 @@ export class ProfileProvider {
|
||||||
public setWalletOrder(walletId: string, index: number): void {
|
public setWalletOrder(walletId: string, index: number): void {
|
||||||
this.persistenceProvider.setWalletOrder(walletId, index);
|
this.persistenceProvider.setWalletOrder(walletId, index);
|
||||||
this.logger.debug('Wallet new order stored');
|
this.logger.debug('Wallet new order stored');
|
||||||
console.log(this.wallet);
|
|
||||||
console.log(walletId);
|
|
||||||
this.wallet[walletId].order = index;
|
this.wallet[walletId].order = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { OnGoingProcessProvider } from '../on-going-process/on-going-process';
|
||||||
import { TouchIdProvider } from '../touchid/touchid';
|
import { TouchIdProvider } from '../touchid/touchid';
|
||||||
|
|
||||||
import * as lodash from 'lodash';
|
import * as lodash from 'lodash';
|
||||||
|
import { FeeProvider } from '../fee/fee';
|
||||||
|
|
||||||
|
|
||||||
/* TODO LIST:
|
/* TODO LIST:
|
||||||
|
@ -55,7 +56,8 @@ export class WalletProvider {
|
||||||
private popupProvider: PopupProvider,
|
private popupProvider: PopupProvider,
|
||||||
private ongoingProcess: OnGoingProcessProvider,
|
private ongoingProcess: OnGoingProcessProvider,
|
||||||
private touchidProvider: TouchIdProvider,
|
private touchidProvider: TouchIdProvider,
|
||||||
private events: Events
|
private events: Events,
|
||||||
|
private feeProvider: FeeProvider
|
||||||
) {
|
) {
|
||||||
this.logger.info('WalletService initialized.');
|
this.logger.info('WalletService initialized.');
|
||||||
}
|
}
|
||||||
|
@ -426,7 +428,7 @@ export class WalletProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateLocalTxHistory(wallet: any, opts: any) {
|
private updateLocalTxHistory(wallet: any, opts: any): Promise<any> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
opts = opts ? opts : {};
|
opts = opts ? opts : {};
|
||||||
let FIRST_LIMIT = 5;
|
let FIRST_LIMIT = 5;
|
||||||
|
@ -436,10 +438,6 @@ export class WalletProvider {
|
||||||
this.progressFn[walletId] = opts.progressFn || (() => { });
|
this.progressFn[walletId] = opts.progressFn || (() => { });
|
||||||
let foundLimitTx = [];
|
let foundLimitTx = [];
|
||||||
|
|
||||||
if (opts.feeLevels) {
|
|
||||||
opts.lowAmount = this.getLowAmount(wallet, opts.feeLevels);
|
|
||||||
};
|
|
||||||
|
|
||||||
let fixTxsUnit = (txs: any): void => {
|
let fixTxsUnit = (txs: any): void => {
|
||||||
if (!txs || !txs[0] || !txs[0].amountStr) return;
|
if (!txs || !txs[0] || !txs[0].amountStr) return;
|
||||||
|
|
||||||
|
@ -570,7 +568,11 @@ export class WalletProvider {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.getLowAmount(wallet).then((fee) => {
|
||||||
|
opts.lowAmount = fee;
|
||||||
updateLowAmount(txs);
|
updateLowAmount(txs);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
updateNotes().then(() => {
|
updateNotes().then(() => {
|
||||||
|
|
||||||
|
@ -661,21 +663,31 @@ export class WalletProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Approx utxo amount, from which the uxto is economically redeemable
|
// Approx utxo amount, from which the uxto is economically redeemable
|
||||||
public getLowAmount(wallet: any, feeLevels?: any, nbOutputs?: number) {
|
public getLowAmount(wallet: any): Promise<any> {
|
||||||
let minFee: number = this.getMinFee(wallet, feeLevels, nbOutputs);
|
return new Promise((resolve, reject) => {
|
||||||
return (minFee / this.LOW_AMOUNT_RATIO);
|
this.getMinFee(wallet).then((fee) => {
|
||||||
|
let minFee: number = fee;
|
||||||
|
return resolve(minFee / this.LOW_AMOUNT_RATIO);
|
||||||
|
}).catch((err) => {
|
||||||
|
return reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Approx utxo amount, from which the uxto is economically redeemable
|
// Approx utxo amount, from which the uxto is economically redeemable
|
||||||
private getMinFee(wallet: any, feeLevels: any, nbOutputs?: number): number {
|
public getMinFee(wallet: any, nbOutputs?: number): Promise<any> {
|
||||||
let level: any = lodash.find(feeLevels[wallet.network], (o) => {
|
return new Promise((resolve, reject) => {
|
||||||
return o.level == 'normal';
|
this.feeProvider.getFeeLevels(wallet.coin).then((data) => {
|
||||||
|
let lowLevelRate = (lodash.find(data.levels[wallet.network], {
|
||||||
|
level: 'normal',
|
||||||
|
}).feePerKb / 1000).toFixed(0);
|
||||||
|
let size = this.getEstimatedTxSize(wallet, nbOutputs);
|
||||||
|
return resolve(size * parseInt(lowLevelRate));
|
||||||
|
}).catch((err) => {
|
||||||
|
return reject(err);
|
||||||
});
|
});
|
||||||
let lowLevelRate = parseInt((level.feePerKb / 1000).toFixed(0));
|
})
|
||||||
|
};
|
||||||
var size = this.getEstimatedTxSize(wallet, nbOutputs);
|
|
||||||
return size * lowLevelRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
// These 2 functions were taken from
|
// These 2 functions were taken from
|
||||||
// https://github.com/bitpay/bitcore-wallet-service/blob/master/lib/model/txproposal.js#L243
|
// https://github.com/bitpay/bitcore-wallet-service/blob/master/lib/model/txproposal.js#L243
|
||||||
|
@ -1007,19 +1019,20 @@ export class WalletProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public getLowUtxos(wallet: any, levels: any): Promise<any> {
|
public getLowUtxos(wallet: any): Promise<any> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
wallet.getUtxos({
|
wallet.getUtxos({
|
||||||
coin: wallet.coin
|
coin: wallet.coin
|
||||||
}, (err, resp) => {
|
}, (err, resp) => {
|
||||||
if (err || !resp || !resp.length) return reject(err);
|
if (err || !resp || !resp.length) return reject(err);
|
||||||
|
|
||||||
let minFee = this.getMinFee(wallet, levels, resp.length);
|
this.getMinFee(wallet, resp.length).then((fee) => {
|
||||||
|
let minFee = fee;
|
||||||
let balance = lodash.sumBy(resp, 'satoshis');
|
let balance = lodash.sumBy(resp, 'satoshis');
|
||||||
|
|
||||||
// for 2 outputs
|
// for 2 outputs
|
||||||
let lowAmount = this.getLowAmount(wallet, levels);
|
this.getLowAmount(wallet).then((fee) => {
|
||||||
|
let lowAmount = fee;
|
||||||
let lowUtxos = lodash.filter(resp, (x: any) => {
|
let lowUtxos = lodash.filter(resp, (x: any) => {
|
||||||
return x.satoshis < lowAmount;
|
return x.satoshis < lowAmount;
|
||||||
});
|
});
|
||||||
|
@ -1034,6 +1047,8 @@ export class WalletProvider {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public isReady(wallet: any): string {
|
public isReady(wallet: any): string {
|
||||||
|
|
Loading…
Reference in New Issue