diff --git a/package.json b/package.json index 64355d676..9f3964fd9 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "ajv": "^5.5.2", "angular2-moment": "^1.7.1", "autoprefixer": "^7.2.4", - "bitcore-wallet-client": "^6.4.0", + "bitcore-wallet-client": "^6.5.0", "buffer-compare": "^1.1.1", "cordova-android": "6.4.0", "cordova-clipboard": "^1.1.1", diff --git a/src/pages/incoming-data-menu/incoming-data-menu.ts b/src/pages/incoming-data-menu/incoming-data-menu.ts index 3f6d90166..a3507d7e2 100644 --- a/src/pages/incoming-data-menu/incoming-data-menu.ts +++ b/src/pages/incoming-data-menu/incoming-data-menu.ts @@ -6,10 +6,11 @@ import { NavParams, ViewController } from 'ionic-angular'; templateUrl: 'incoming-data-menu.html', }) export class IncomingDataMenuPage { + public https: boolean; public data: string; public type: string; - public https: boolean; + public coin: string; constructor( private viewCtrl: ViewController, @@ -21,6 +22,7 @@ export class IncomingDataMenuPage { ionViewDidLoad() { this.data = this.navParams.data.data; this.type = this.navParams.data.type; + this.coin = this.navParams.data.coin; if (this.type === 'url') { if (this.data.indexOf('https://') === 0) { this.https = true; @@ -29,6 +31,11 @@ export class IncomingDataMenuPage { } public close(redirTo: string, value: string) { + if (redirTo == 'AmountPage') { + let coin = this.coin ? this.coin : 'btc'; + this.viewCtrl.dismiss({ redirTo: redirTo, value: value, coin: coin }); + return; + } this.viewCtrl.dismiss({ redirTo: redirTo, value: value }); } } \ No newline at end of file diff --git a/src/pages/receive/custom-amount/custom-amount.ts b/src/pages/receive/custom-amount/custom-amount.ts index 218150c62..10f1edddf 100644 --- a/src/pages/receive/custom-amount/custom-amount.ts +++ b/src/pages/receive/custom-amount/custom-amount.ts @@ -2,6 +2,9 @@ import { Component } from '@angular/core'; import { NavParams } from 'ionic-angular'; import { Logger } from '@nsalaun/ng-logger'; +// Native +import { SocialSharing } from '@ionic-native/social-sharing'; + //providers import { ProfileProvider } from '../../../providers/profile/profile'; import { PlatformProvider } from '../../../providers/platform/platform'; @@ -26,14 +29,17 @@ export class CustomAmountPage { private profileProvider: ProfileProvider, private platformProvider: PlatformProvider, private walletProvider: WalletProvider, - private logger: Logger + private logger: Logger, + private socialSharing: SocialSharing ) { - this.address = this.navParams.data.toAddress; this.amount = this.navParams.data.amount; this.coin = this.navParams.data.coin; let walletId = this.navParams.data.walletId; this.wallet = this.profileProvider.getWallet(walletId); this.showShareButton = this.platformProvider.isCordova; + + let addr = this.navParams.data.toAddress; + this.address = this.walletProvider.getAddressView(this.wallet, addr); } ionViewDidLoad() { @@ -42,16 +48,11 @@ export class CustomAmountPage { } private updateQrAddress(): void { - this.setProtocolHandler(); - this.qrAddress = this.protocolHandler + ":" + this.address + "?amount=" + this.amount; + this.qrAddress = this.walletProvider.getProtoAddress(this.wallet, this.address) + "?amount=" + this.amount; } - private setProtocolHandler(): void { - this.protocolHandler = this.walletProvider.getProtocolHandler(this.wallet.coin); - } - - public shareAddress = function () { - //window.plugins.socialsharing.share(this.qrAddress, null, null, null); TODO + public shareAddress(): void { + this.socialSharing.share(this.qrAddress); } } diff --git a/src/pages/receive/receive.ts b/src/pages/receive/receive.ts index 9277bf4f0..f530b113d 100644 --- a/src/pages/receive/receive.ts +++ b/src/pages/receive/receive.ts @@ -2,15 +2,15 @@ import { Component } from '@angular/core'; import { Logger } from '@nsalaun/ng-logger'; import { NavController, Events, AlertController } from 'ionic-angular'; -//native +// Native import { SocialSharing } from '@ionic-native/social-sharing'; -//pages +// Pages import { AmountPage } from '../send/amount/amount'; import { CopayersPage } from './../add/copayers/copayers'; import { BackupGamePage } from '../backup/backup-game/backup-game'; -//providers +// Providers import { WalletProvider } from '../../providers/wallet/wallet'; import { ProfileProvider } from '../../providers/profile/profile'; import { PlatformProvider } from '../../providers/platform/platform'; @@ -62,15 +62,10 @@ export class ReceivePage { private onWalletSelect(wallet: any): any { this.wallet = wallet; if (this.wallet) { - this.setProtocolHandler(); this.setAddress(); } } - private setProtocolHandler(): void { - this.protocolHandler = this.walletProvider.getProtocolHandler(this.wallet.coin); - } - private checkSelectedWallet(wallet: any, wallets: any): any { if (!wallet) return wallets[0]; let w = _.find(wallets, (w: any) => { @@ -99,7 +94,7 @@ export class ReceivePage { this.walletProvider.getAddress(this.wallet, newAddr).then((addr) => { this.loading = false - this.address = addr; + this.address = this.walletProvider.getAddressView(this.wallet, addr); this.updateQrAddress(); }).catch((err) => { this.loading = false; @@ -108,13 +103,12 @@ export class ReceivePage { } private updateQrAddress(): void { - this.qrAddress = this.protocolHandler + ":" + this.address; + this.qrAddress = this.walletProvider.getProtoAddress(this.wallet, this.address); } public shareAddress(): void { - let protocol = 'bitcoin'; - if (this.wallet.coin == 'bch') protocol += 'cash'; - this.socialSharing.share(protocol + ':' + this.address); + if (!this.showShareButton) return; + this.socialSharing.share(this.qrAddress); } public showWallets(): void { diff --git a/src/pages/scan/scan.ts b/src/pages/scan/scan.ts index 54adadaff..719a88ef0 100644 --- a/src/pages/scan/scan.ts +++ b/src/pages/scan/scan.ts @@ -96,7 +96,7 @@ export class ScanPage { this.modalIsOpen = false; switch (data.redirTo) { case 'AmountPage': - this.sendPaymentToAddress(data.value); + this.sendPaymentToAddress(data.value, data.coin); break; case 'AddressBookPage': this.addToAddressBook(data.value); @@ -125,9 +125,9 @@ export class ScanPage { this.externalLinkProvider.open(url); } - private sendPaymentToAddress(bitcoinAddress: string): void { + private sendPaymentToAddress(bitcoinAddress: string, coin: string): void { //this.navCtrl.parent.select(3); TODO go to send and then amount page - this.navCtrl.push(AmountPage, { toAddress: bitcoinAddress }); + this.navCtrl.push(AmountPage, { toAddress: bitcoinAddress, coin: coin }); } private addToAddressBook(bitcoinAddress: string): void { diff --git a/src/pages/send/confirm/confirm.html b/src/pages/send/confirm/confirm.html index 105044f37..79bbe6c96 100644 --- a/src/pages/send/confirm/confirm.html +++ b/src/pages/send/confirm/confirm.html @@ -55,9 +55,9 @@
-
- - {{tx.toAddress}} +
+ + {{tx.origToAddress}} {{tx.name}}
@@ -76,9 +76,9 @@ -
- - {{tx.toAddress}} +
+ + {{tx.origToAddress}} {{tx.name}}
@@ -128,4 +128,4 @@ - + \ No newline at end of file diff --git a/src/pages/send/confirm/confirm.ts b/src/pages/send/confirm/confirm.ts index abf679ea3..bc1c2c9ec 100644 --- a/src/pages/send/confirm/confirm.ts +++ b/src/pages/send/confirm/confirm.ts @@ -11,6 +11,7 @@ import { FeeWarningPage } from '../fee-warning/fee-warning'; import { SuccessModalPage } from '../../success/success'; // Providers +import { BwcProvider } from '../../../providers/bwc/bwc'; import { ConfigProvider } from '../../../providers/config/config'; import { PlatformProvider } from '../../../providers/platform/platform'; import { ProfileProvider } from '../../../providers/profile/profile'; @@ -28,6 +29,8 @@ import { TxFormatProvider } from '../../../providers/tx-format/tx-format'; }) export class ConfirmPage { + private bitcoreCash: any; + public countDown = null; public CONFIRM_LIMIT_USD: number; public FEE_TOO_HIGH_LIMIT_PER: number; @@ -55,6 +58,7 @@ export class ConfirmPage { public usingCustomFee: boolean = false; constructor( + private bwcProvider: BwcProvider, private navCtrl: NavController, private navParams: NavParams, private logger: Logger, @@ -71,6 +75,7 @@ export class ConfirmPage { private txFormatProvider: TxFormatProvider, private events: Events ) { + this.bitcoreCash = this.bwcProvider.getBitcoreCash(); this.CONFIRM_LIMIT_USD = 20; this.FEE_TOO_HIGH_LIMIT_PER = 15; this.config = this.configProvider.get(); @@ -95,8 +100,15 @@ export class ConfirmPage { coin: this.navParams.data.coin, txp: {}, }; + this.tx.origToAddress = this.tx.toAddress; + + if (this.tx.coin && this.tx.coin == 'bch') { + this.tx.feeLevel = 'normal'; + + // Use legacy address + this.tx.toAddress = this.bitcoreCash.Address(this.tx.toAddress).toString(); + } - if (this.tx.coin && this.tx.coin == 'bch') this.tx.feeLevel = 'normal'; this.tx.feeLevelName = this.feeProvider.feeOpts[this.tx.feeLevel]; this.showAddress = false; this.walletSelectorTitle = 'Send from'; // TODO gettextCatalog diff --git a/src/pages/settings/advanced/advanced.html b/src/pages/settings/advanced/advanced.html index 1f152dc8d..a7119c1f8 100644 --- a/src/pages/settings/advanced/advanced.html +++ b/src/pages/settings/advanced/advanced.html @@ -12,7 +12,7 @@
{{'Use Unconfirmed Funds' | translate}} - +
@@ -20,11 +20,23 @@ + + +
+ {{'Use Bitcoin Cash Copay Style Addresses' | translate}} + +
+
+ + If enabled, Bitcoin Cash addresses will be shown using Copay style address, and not the new cashaddr format. + +
+
{{'Recent Transaction Card' | translate}} - +
@@ -37,7 +49,7 @@
{{'Show Next Steps Card' | translate}} - +
diff --git a/src/pages/settings/advanced/advanced.ts b/src/pages/settings/advanced/advanced.ts index 2788616c6..3891bdfef 100644 --- a/src/pages/settings/advanced/advanced.ts +++ b/src/pages/settings/advanced/advanced.ts @@ -13,6 +13,7 @@ export class AdvancedPage { public spendUnconfirmed: boolean; public recentTransactionsEnabled: boolean; public showNextSteps: boolean; + public useLegacyAddress: boolean; constructor( private configProvider: ConfigProvider, @@ -30,6 +31,7 @@ export class AdvancedPage { this.spendUnconfirmed = config.wallet.spendUnconfirmed; this.recentTransactionsEnabled = config.recentTransactions.enabled; this.showNextSteps = config.showNextSteps.enabled; + this.useLegacyAddress = config.wallet.useLegacyAddress; } public spendUnconfirmedChange(): void { @@ -50,6 +52,15 @@ export class AdvancedPage { this.configProvider.set(opts); } + public useLegacyAddressChange(): void { + let opts = { + wallet: { + useLegacyAddress: this.useLegacyAddress + } + }; + this.configProvider.set(opts); + } + public nextStepsChange(): void { let opts = { showNextSteps: { diff --git a/src/pages/tx-details/tx-details.ts b/src/pages/tx-details/tx-details.ts index 722261c1c..5f1931424 100644 --- a/src/pages/tx-details/tx-details.ts +++ b/src/pages/tx-details/tx-details.ts @@ -63,7 +63,11 @@ export class TxDetailsPage { this.txsUnsubscribedForNotifications = this.config.confirmedTxsNotifications ? !this.config.confirmedTxsNotifications.enabled : true; if (this.wallet.coin == 'bch') { - this.blockexplorerUrl = 'bch-insight.bitpay.com'; + if (this.walletProvider.useLegacyAddress()) { + this.blockexplorerUrl = 'bch-insight.bitpay.com'; + } else { + this.blockexplorerUrl = 'blockdozer.com/insight'; + } } else { this.blockexplorerUrl = 'insight.bitpay.com'; } @@ -153,7 +157,7 @@ export class TxDetailsPage { this.walletProvider.getTx(this.wallet, this.txId).then((tx: any) => { if (!opts.hideLoading) this.onGoingProcess.set('loadingTxInfo', false); - this.btx = this.txFormatProvider.processTx(this.wallet.coin, tx); + this.btx = this.txFormatProvider.processTx(this.wallet.coin, tx, this.walletProvider.useLegacyAddress()); let v: string = this.txFormatProvider.formatAlternativeStr(this.wallet.coin, tx.fees); this.btx.feeFiatStr = v; this.btx.feeRateStr = (this.btx.fees / (this.btx.amount + this.btx.fees) * 100).toFixed(2) + '%'; diff --git a/src/providers/config/config.ts b/src/providers/config/config.ts index 0d9d2ccdd..5b8e45eaa 100644 --- a/src/providers/config/config.ts +++ b/src/providers/config/config.ts @@ -11,6 +11,7 @@ interface Config { }; wallet: { + useLegacyAddress: boolean, requiredCopayers: number; totalCopayers: number; spendUnconfirmed: boolean; @@ -101,6 +102,7 @@ const configDefault: Config = { // wallet default config wallet: { + useLegacyAddress: false, requiredCopayers: 2, totalCopayers: 3, spendUnconfirmed: false, diff --git a/src/providers/incoming-data/incoming-data.ts b/src/providers/incoming-data/incoming-data.ts index 42fbef7c3..6bf6e8827 100644 --- a/src/providers/incoming-data/incoming-data.ts +++ b/src/providers/incoming-data/incoming-data.ts @@ -80,6 +80,12 @@ export class IncomingDataProvider { coin = 'bch'; parsed = this.bwcProvider.getBitcoreCash().URI(data); addr = parsed.address ? parsed.address.toString() : ''; + + // keep address in original format + if (parsed.address && data.indexOf(addr) < 0) { + addr = parsed.address.toCashAddress(); + }; + message = parsed.message; amount = parsed.amount ? parsed.amount : ''; @@ -156,7 +162,8 @@ export class IncomingDataProvider { if (this.navCtrl.getActive().name === 'ScanPage') { this.showMenu({ data: data, - type: 'bitcoinAddress' + type: 'bitcoinAddress', + coin: 'btc' }); } else { let coin = 'btc'; diff --git a/src/providers/tx-format/tx-format.ts b/src/providers/tx-format/tx-format.ts index fa9c5d50c..13bd2656c 100644 --- a/src/providers/tx-format/tx-format.ts +++ b/src/providers/tx-format/tx-format.ts @@ -10,17 +10,30 @@ import * as _ from "lodash"; @Injectable() export class TxFormatProvider { + private bitcoreCash: any; + // TODO: implement configService public pendingTxProposalsCountForUs: number constructor( - private bwc: BwcProvider, + private bwcProvider: BwcProvider, private rate: RateProvider, private config: ConfigProvider, private filter: FilterProvider, private logger: Logger ) { this.logger.info('TxFormatProvider initialized.'); + this.bitcoreCash = this.bwcProvider.getBitcoreCash(); + } + + public toCashAddress(address: string, withPrefix?: boolean): string { + let cashAddr: string = (this.bitcoreCash.Address(address)).toCashAddress(); + + if (withPrefix) { + return cashAddr; + } + + return cashAddr.split(':')[1]; // rm prefix } public formatAmount(satoshis: number, fullPrecision?: boolean): number { @@ -32,7 +45,7 @@ export class TxFormatProvider { var opts = { fullPrecision: !!fullPrecision }; - return this.bwc.getUtils().formatAmount(satoshis, settings.unitCode, opts); + return this.bwcProvider.getUtils().formatAmount(satoshis, settings.unitCode, opts); } public formatAmountStr(coin: string, satoshis: number): string { @@ -78,7 +91,7 @@ export class TxFormatProvider { return val(); }; - public processTx(coin: string, tx: any): any { + public processTx(coin: string, tx: any, useLegacyAddress?: boolean): any { if (!tx || tx.action == 'invalid') return tx; @@ -99,6 +112,11 @@ export class TxFormatProvider { }, 0); } tx.toAddress = tx.outputs[0].toAddress; + + // toDo: translate all tx.outputs[x].toAddress ? + if (tx.toAddress && coin == 'bch' && !useLegacyAddress) { + tx.toAddress = this.toCashAddress(tx.toAddress); + } } tx.amountStr = this.formatAmountStr(coin, tx.amount); @@ -110,6 +128,10 @@ export class TxFormatProvider { tx.amountUnitStr = tx.amountStr.split(' ')[1]; } + if (tx.addressTo && coin == 'bch' && !useLegacyAddress) { + tx.addressTo = this.toCashAddress(tx.addressTo); + } + return tx; }; diff --git a/src/providers/wallet/wallet.ts b/src/providers/wallet/wallet.ts index 6b1c51d82..5f71a603d 100644 --- a/src/providers/wallet/wallet.ts +++ b/src/providers/wallet/wallet.ts @@ -1,7 +1,9 @@ import { Injectable } from '@angular/core'; import { Events } from 'ionic-angular'; import { Logger } from '@nsalaun/ng-logger'; +import * as lodash from 'lodash'; +// Providers import { ConfigProvider } from '../config/config'; import { BwcProvider } from '../bwc/bwc'; import { TxFormatProvider } from '../tx-format/tx-format'; @@ -12,8 +14,6 @@ import { FilterProvider } from '../filter/filter'; import { PopupProvider } from '../popup/popup'; import { OnGoingProcessProvider } from '../on-going-process/on-going-process'; import { TouchIdProvider } from '../touchid/touchid'; - -import * as lodash from 'lodash'; import { FeeProvider } from '../fee/fee'; @@ -322,6 +322,29 @@ export class WalletProvider { }); } + public useLegacyAddress(): boolean { + let config = this.configProvider.get(); + let walletSettings = config.wallet; + + return walletSettings.useLegacyAddress; + } + + public getAddressView(wallet: any, address: string): string { + if (wallet.coin != 'bch' || this.useLegacyAddress()) return address; + return this.txFormatProvider.toCashAddress(address); + } + + public getProtoAddress(wallet: any, address: string) { + let proto: string = this.getProtocolHandler(wallet); + let protoAddr: string = proto + ':' + address; + + if (wallet.coin != 'bch' || this.useLegacyAddress()) { + return protoAddr; + } else { + return protoAddr.toUpperCase(); + }; + }; + public getAddress(wallet: any, forceNew: boolean): Promise { return new Promise((resolve, reject) => { this.persistenceProvider.getLastAddress(wallet.id).then((addr) => { @@ -1299,7 +1322,7 @@ export class WalletProvider { return reject(err); }); }); - }; + } public getSendMaxInfo(wallet: any, opts: any): Promise { return new Promise((resolve, reject) => { @@ -1309,11 +1332,14 @@ export class WalletProvider { return resolve(res); }); }); - }; + } public getProtocolHandler(coin: string): string { - if (coin == 'bch') return 'bitcoincash'; - else return 'bitcoin'; + if (coin == 'bch') { + return 'bitcoincash'; + } else { + return 'bitcoin'; + } } public copyCopayers(wallet: any, newWallet: any): Promise {