Merge pull request #8268 from gabrielbazan7/fix/bchduplicate

FIX: Duplicate BCH UI
This commit is contained in:
Gabriel Masclef 2018-03-19 14:57:37 -03:00 committed by GitHub
commit ae35cd04ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 179 additions and 159 deletions

View File

@ -19,10 +19,18 @@
<ion-icon item-start>
<img [ngStyle]="{'background-color': wallet.color}" src="assets/img/icon-wallet.svg" class="icon-wallet" />
</ion-icon>
<h2>{{wallet.credentials.walletName}}</h2>
<p>
{{wallet.status && wallet.status.totalBalanceStr ? wallet.status.totalBalanceStr : wallet.cachedBalance}}
</p>
<div class="item-title">{{wallet.credentials.walletName}}</div>
<div class="item-subtitle">
<span *ngIf="!wallet.error">
<span class="success" *ngIf="!wallet.balanceHidden">
{{wallet.bchBalance || ('Checking...' | translate)}}
</span>
<span *ngIf="wallet.balanceHidden">[
<span translate>Balance Hidden</span>]</span>
<span class="text-gray" *ngIf="wallet.credentials.m > 1">{{wallet.credentials.m}}-of-{{wallet.credentials.n}}</span>
</span>
<span *ngIf="wallet.error" class="wallet-warning">{{wallet.error}}</span>
</div>
<ion-note item-end>
<button ion-button (click)="duplicate(wallet)" translate>Duplicate</button>
</ion-note>
@ -40,8 +48,10 @@
<ion-icon item-start>
<img [ngStyle]="{'background-color': 'gray'}" src="assets/img/icon-wallet.svg" class="icon-wallet" />
</ion-icon>
<h2>{{wallet.credentials.walletName}}</h2>
<p class="text-disabled">{{wallet.excludeReason}}</p>
<div class="item-title text-disabled">{{wallet.credentials.walletName}}</div>
<div class="item-subtitle">
<span class="text-disabled">{{wallet.excludeReason}}</span>
</div>
</ion-item>
</ion-list>

View File

@ -1,3 +1,5 @@
page-bitcoin-cash {
.success {
color: color($colors, success);
}
}

View File

@ -1,6 +1,6 @@
import { Component } from "@angular/core";
import { TranslateService } from '@ngx-translate/core';
import { NavController } from 'ionic-angular';
import { Events, NavController } from 'ionic-angular';
import * as lodash from 'lodash';
import { Logger } from "../../../providers/logger/logger";
@ -16,179 +16,187 @@ import { TxFormatProvider } from "../../../providers/tx-format/tx-format";
import { WalletProvider } from "../../../providers/wallet/wallet";
@Component({
selector: 'page-bitcoin-cash',
templateUrl: 'bitcoin-cash.html',
selector: 'page-bitcoin-cash',
templateUrl: 'bitcoin-cash.html',
})
export class BitcoinCashPage {
private walletsBTC: any[];
private walletsBCH: any[];
private errors: any;
private walletsBTC: any[];
private walletsBCH: any[];
private errors: any;
public availableWallets: any[];
public nonEligibleWallets: any[];
public error: any;
public availableWallets: any[];
public nonEligibleWallets: any[];
public error: any;
constructor(
private navCtrl: NavController,
private walletProvider: WalletProvider,
private profileProvider: ProfileProvider,
private txFormatProvider: TxFormatProvider,
private onGoingProcessProvider: OnGoingProcessProvider,
private popupProvider: PopupProvider,
private pushNotificationsProvider: PushNotificationsProvider,
private externalLinkProvider: ExternalLinkProvider,
private bwcErrorProvider: BwcErrorProvider,
private bwcProvider: BwcProvider,
private logger: Logger,
private translate: TranslateService
) {
this.walletsBTC = this.profileProvider.getWallets({
coin: 'btc',
onlyComplete: true,
network: 'livenet'
});
this.walletsBCH = [];
this.availableWallets = [];
this.nonEligibleWallets = [];
this.errors = this.bwcProvider.getErrors();
}
constructor(
private navCtrl: NavController,
private walletProvider: WalletProvider,
private profileProvider: ProfileProvider,
private txFormatProvider: TxFormatProvider,
private onGoingProcessProvider: OnGoingProcessProvider,
private popupProvider: PopupProvider,
private pushNotificationsProvider: PushNotificationsProvider,
private externalLinkProvider: ExternalLinkProvider,
private bwcErrorProvider: BwcErrorProvider,
private bwcProvider: BwcProvider,
private logger: Logger,
private translate: TranslateService,
private events: Events
) {
this.walletsBTC = [];
this.walletsBCH = [];
this.availableWallets = [];
this.nonEligibleWallets = [];
this.errors = this.bwcProvider.getErrors();
}
ionViewWillEnter() {
// Filter out already duplicated wallets
this.walletsBCH = this.profileProvider.getWallets({
coin: 'bch',
network: 'livenet'
});
ionViewWillEnter() {
let xPubKeyIndex = lodash.keyBy(this.walletsBCH, "credentials.xPubKey");
this.walletsBTC = this.profileProvider.getWallets({
coin: 'btc',
onlyComplete: true,
network: 'livenet'
});
this.walletsBTC = lodash.filter(this.walletsBTC, w => {
return !xPubKeyIndex[w.credentials.xPubKey];
});
// Filter out already duplicated wallets
this.walletsBCH = this.profileProvider.getWallets({
coin: 'bch',
network: 'livenet'
});
lodash.each(this.walletsBTC, (w) => {
if (w.credentials.derivationStrategy != 'BIP44') {
w.excludeReason = this.translate.instant('Non BIP44 wallet');
this.nonEligibleWallets.push(w);
} else if (!w.canSign()) {
w.excludeReason = this.translate.instant('Read only wallet');
this.nonEligibleWallets.push(w);
} else if (w.needsBackup) {
w.excludeReason = this.translate.instant('Needs backup recovery');
this.nonEligibleWallets.push(w);
} else {
this.availableWallets.push(w);
}
});
let xPubKeyIndex = lodash.keyBy(this.walletsBCH, "credentials.xPubKey");
this.availableWallets = this.availableWallets;
this.nonEligibleWallets = this.nonEligibleWallets;
this.walletsBTC = lodash.filter(this.walletsBTC, w => {
return !xPubKeyIndex[w.credentials.xPubKey];
});
lodash.each(this.availableWallets, (wallet) => {
this.walletProvider.getBalance(wallet, { coin: 'bch' }).then((balance) => {
wallet.bchBalance = this.txFormatProvider.formatAmountStr('bch', balance.availableAmount);
}).catch((err) => {
this.logger.error(err);
});
});
}
lodash.each(this.walletsBTC, (w) => {
if (w.credentials.derivationStrategy != 'BIP44') {
w.excludeReason = this.translate.instant('Non BIP44 wallet');
this.nonEligibleWallets.push(w);
} else if (!w.canSign()) {
w.excludeReason = this.translate.instant('Read only wallet');
this.nonEligibleWallets.push(w);
} else if (w.needsBackup) {
w.excludeReason = this.translate.instant('Needs backup recovery');
this.nonEligibleWallets.push(w);
} else {
this.availableWallets.push(w);
}
});
public openRecoveryToolLink(): void {
let url = 'https://bitpay.github.io/copay-recovery/';
let optIn = true;
let title = this.translate.instant('Open the recovery tool');
let okText = this.translate.instant('Open');
let cancelText = this.translate.instant('Go Back');
this.externalLinkProvider.open(url, optIn, title, null, okText, cancelText);
}
lodash.each(this.availableWallets, (wallet) => {
this.walletProvider.getBalance(wallet, { coin: 'bch' }).then((balance) => {
wallet.bchBalance = this.txFormatProvider.formatAmountStr('bch', balance.availableAmount);
wallet.error = null;
}).catch((err) => {
wallet.error = (err === 'WALLET_NOT_REGISTERED') ? this.translate.instant('Wallet not registered') : this.bwcErrorProvider.msg(err);
this.logger.error(err);
});
});
}
public duplicate(wallet: any) {
this.logger.debug('Duplicating wallet for BCH: ' + wallet.id + ': ' + wallet.name);
public openRecoveryToolLink(): void {
let url = 'https://bitpay.github.io/copay-recovery/';
let optIn = true;
let title = this.translate.instant('Open the recovery tool');
let okText = this.translate.instant('Open');
let cancelText = this.translate.instant('Go Back');
this.externalLinkProvider.open(url, optIn, title, null, okText, cancelText);
}
let opts: any = {
name: wallet.name + '[BCH]',
m: wallet.m,
n: wallet.n,
myName: wallet.credentials.copayerName,
networkName: wallet.network,
coin: 'bch',
walletPrivKey: wallet.credentials.walletPrivKey,
compliantDerivation: wallet.credentials.compliantDerivation,
};
public duplicate(wallet: any) {
this.logger.debug('Duplicating wallet for BCH: ' + wallet.id + ': ' + wallet.name);
let setErr = (err) => {
this.bwcErrorProvider.cb(err, 'Could not duplicate').then((errorMsg) => {
this.logger.warn(errorMsg);
this.popupProvider.ionicAlert(errorMsg, null, 'OK');
return;
});
}
let opts: any = {
name: wallet.name + '[BCH]',
m: wallet.m,
n: wallet.n,
myName: wallet.credentials.copayerName,
networkName: wallet.network,
coin: 'bch',
walletPrivKey: wallet.credentials.walletPrivKey,
compliantDerivation: wallet.credentials.compliantDerivation,
};
let importOrCreate = () => {
return new Promise((resolve, reject) => {
this.walletProvider.getStatus(wallet, {}).then((status: any) => {
opts.singleAddress = status.wallet.singleAddress;
let setErr = (err) => {
this.bwcErrorProvider.cb(err, 'Could not duplicate').then((errorMsg) => {
this.logger.warn(errorMsg);
this.popupProvider.ionicAlert(errorMsg, null, 'OK');
return;
});
}
// first try to import
this.profileProvider.importExtendedPrivateKey(opts.extendedPrivateKey, opts).then((newWallet) => {
return resolve({ newWallet });
}).catch((err) => {
if (!(err instanceof this.errors.NOT_AUTHORIZED)) {
return reject(err);
}
// create and store a wallet
this.profileProvider.createWallet(opts).then((newWallet) => {
return resolve({ newWallet, isNew: true });
});
});
}).catch((err) => {
return reject(err);
});
});
};
let importOrCreate = () => {
return new Promise((resolve, reject) => {
this.walletProvider.getStatus(wallet, {}).then((status: any) => {
opts.singleAddress = status.wallet.singleAddress;
// Multisig wallets? add Copayers
function addCopayers(newWallet, isNew, cb) {
if (!isNew) return cb();
if (wallet.n == 1) return cb();
// first try to import
this.profileProvider.importExtendedPrivateKey(opts.extendedPrivateKey, opts).then((newWallet) => {
return resolve({ newWallet });
}).catch((err) => {
if (!(err instanceof this.errors.NOT_AUTHORIZED)) {
return reject(err);
}
// create and store a wallet
this.profileProvider.createWallet(opts).then((newWallet) => {
return resolve({ newWallet, isNew: true });
}).catch((err) => {
return reject(err);
});
});
}).catch((err) => {
return reject(err);
});
});
};
this.logger.info('Adding copayers for BCH wallet config:' + wallet.m + '-' + wallet.n);
// Multisig wallets? add Copayers
function addCopayers(newWallet, isNew, cb) {
if (!isNew) return cb();
if (wallet.n == 1) return cb();
this.walletProvider.copyCopayers(wallet, newWallet, (err) => {
if (err) {
return setErr(err);
}
return cb();
});
};
this.logger.info('Adding copayers for BCH wallet config:' + wallet.m + '-' + wallet.n);
this.walletProvider.getKeys(wallet).then((keys) => {
opts.extendedPrivateKey = keys.xPrivKey;
this.onGoingProcessProvider.set('duplicatingWallet');
importOrCreate().then((result: any) => {
let newWallet = result.newWallet;
let isNew = result.isNew;
this.walletProvider.copyCopayers(wallet, newWallet, (err) => {
if (err) {
return cb(err);
}
return cb();
});
};
this.walletProvider.updateRemotePreferences(newWallet);
this.pushNotificationsProvider.updateSubscription(newWallet);
this.walletProvider.getKeys(wallet).then((keys) => {
opts.extendedPrivateKey = keys.xPrivKey;
this.onGoingProcessProvider.set('duplicatingWallet');
importOrCreate().then((result: any) => {
let newWallet = result.newWallet;
let isNew = result.isNew;
addCopayers(newWallet, isNew, (err) => {
this.onGoingProcessProvider.clear();
if (err) return setErr(err);
this.walletProvider.updateRemotePreferences(newWallet);
this.pushNotificationsProvider.updateSubscription(newWallet);
if (isNew)
this.walletProvider.startScan(newWallet);
addCopayers(newWallet, isNew, (err) => {
this.onGoingProcessProvider.clear();
if (err) {
return setErr(err);
}
if (isNew) {
this.walletProvider.startScan(newWallet);
}
this.navCtrl.popToRoot({ animate: false }).then(() => {
this.navCtrl.parent.select(0);
});
});
}).catch((err) => {
this.onGoingProcessProvider.clear();
setErr(err);
});
}).catch((err) => {
setErr(err);
});
}
this.events.publish('status:updated');
this.navCtrl.popToRoot({ animate: false }).then(() => {
this.navCtrl.parent.select(0);
});
});
}).catch((err) => {
this.onGoingProcessProvider.clear();
setErr(err);
});
}).catch((err) => {
setErr(err);
});
}
}