mirror of https://github.com/BTCPrivate/copay.git
commit
c7f5ad439c
|
@ -26,6 +26,7 @@ import { CopayApp } from './app.component';
|
||||||
/* Pages */
|
/* Pages */
|
||||||
import { AddPage } from '../pages/add/add';
|
import { AddPage } from '../pages/add/add';
|
||||||
import { CreateWalletPage } from '../pages/add/create-wallet/create-wallet';
|
import { CreateWalletPage } from '../pages/add/create-wallet/create-wallet';
|
||||||
|
import { ImportWalletPage } from '../pages/add/import-wallet/import-wallet';
|
||||||
import { BackupRequestPage } from '../pages/onboarding/backup-request/backup-request';
|
import { BackupRequestPage } from '../pages/onboarding/backup-request/backup-request';
|
||||||
import { DisclaimerPage } from '../pages/onboarding/disclaimer/disclaimer';
|
import { DisclaimerPage } from '../pages/onboarding/disclaimer/disclaimer';
|
||||||
import { EmailPage } from '../pages/onboarding/email/email';
|
import { EmailPage } from '../pages/onboarding/email/email';
|
||||||
|
@ -69,6 +70,7 @@ import { TouchIdProvider } from '../providers/touchid/touchid';
|
||||||
import { TxFormatProvider } from '../providers/tx-format/tx-format';
|
import { TxFormatProvider } from '../providers/tx-format/tx-format';
|
||||||
import { WalletProvider } from '../providers/wallet/wallet';
|
import { WalletProvider } from '../providers/wallet/wallet';
|
||||||
import { ReleaseProvider } from '../providers/release/release';
|
import { ReleaseProvider } from '../providers/release/release';
|
||||||
|
import { DerivationPathHelperProvider } from '../providers/derivationPathHelper/derivationPathHelper';
|
||||||
|
|
||||||
export function createTranslateLoader(http: Http) {
|
export function createTranslateLoader(http: Http) {
|
||||||
return new TranslatePoHttpLoader(http, 'assets/i18n', '.po');
|
return new TranslatePoHttpLoader(http, 'assets/i18n', '.po');
|
||||||
|
@ -77,6 +79,7 @@ export function createTranslateLoader(http: Http) {
|
||||||
let pages: any = [
|
let pages: any = [
|
||||||
AddPage,
|
AddPage,
|
||||||
CreateWalletPage,
|
CreateWalletPage,
|
||||||
|
ImportWalletPage,
|
||||||
AboutPage,
|
AboutPage,
|
||||||
AdvancedPage,
|
AdvancedPage,
|
||||||
AltCurrencyPage,
|
AltCurrencyPage,
|
||||||
|
@ -121,6 +124,7 @@ let providers: any = [
|
||||||
TxFormatProvider,
|
TxFormatProvider,
|
||||||
WalletProvider,
|
WalletProvider,
|
||||||
ReleaseProvider,
|
ReleaseProvider,
|
||||||
|
DerivationPathHelperProvider,
|
||||||
{
|
{
|
||||||
provide: ErrorHandler,
|
provide: ErrorHandler,
|
||||||
useClass: IonicErrorHandler
|
useClass: IonicErrorHandler
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { NavController } from 'ionic-angular';
|
import { NavController } from 'ionic-angular';
|
||||||
import { CreateWalletPage } from "./create-wallet/create-wallet";
|
import { CreateWalletPage } from "./create-wallet/create-wallet";
|
||||||
|
import { ImportWalletPage } from "./import-wallet/import-wallet";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'page-add',
|
selector: 'page-add',
|
||||||
|
@ -22,6 +23,6 @@ export class AddPage {
|
||||||
}
|
}
|
||||||
|
|
||||||
goToImportWallet() {
|
goToImportWallet() {
|
||||||
// this.navCtrl.push();
|
this.navCtrl.push(ImportWalletPage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
<ion-header>
|
||||||
|
<ion-navbar>
|
||||||
|
<ion-title>Import wallet</ion-title>
|
||||||
|
</ion-navbar>
|
||||||
|
</ion-header>
|
||||||
|
|
||||||
|
<ion-content>
|
||||||
|
<div class="tabs">
|
||||||
|
<div class="tab" [ngClass]="{'selected': selectedTab == 'words'}" (click)="selectTab('words')"><span>Recovery phrase</span></div>
|
||||||
|
<div class="tab" [ngClass]="{'selected': selectedTab == 'file'}" (click)="selectTab('file')"><span>File/Text</span></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form [formGroup]="importForm" (ngSubmit)="import()">
|
||||||
|
<ion-item *ngIf="selectedTab == 'words'">
|
||||||
|
<ion-label stacked>Type the recovery phrase (usually 12 words)</ion-label>
|
||||||
|
<ion-textarea [(ngModel)]="formData.words" formControlName="words"></ion-textarea>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<div *ngIf="selectedTab == 'file'">
|
||||||
|
<ion-item>
|
||||||
|
<ion-label stacked>Choose a backup file from your computer</ion-label>
|
||||||
|
<ion-input type="file" [(ngModel)]="formData.file" formControlName="file"></ion-input>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
<ion-label stacked>Password</ion-label>
|
||||||
|
<ion-input type="password" [(ngModel)]="formData.filePassword" formControlName="filePassword"></ion-input>
|
||||||
|
</ion-item>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ion-item-divider color="light"></ion-item-divider>
|
||||||
|
|
||||||
|
<ion-item (click)="showAdvOpts = !showAdvOpts">
|
||||||
|
<ion-label *ngIf="!showAdvOpts">Show advanced options</ion-label>
|
||||||
|
<ion-label *ngIf="showAdvOpts">Hide advanced options</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<div *ngIf="showAdvOpts">
|
||||||
|
<div *ngIf="selectedTab == 'words'">
|
||||||
|
<ion-item>
|
||||||
|
<ion-label stacked>Password</ion-label>
|
||||||
|
<ion-input type="password" [(ngModel)]="formData.mnemonicPassword" formControlName="mnemonicPassword"></ion-input>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
<ion-label stacked>Derivation path</ion-label>
|
||||||
|
<ion-input type="text" [(ngModel)]="formData.derivationPath" formControlName="derivationPath"></ion-input>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
<ion-label stacked>Testnet</ion-label>
|
||||||
|
<ion-toggle [(ngModel)]="formData.testnet" formControlName="testnet" (ionChange)="setDerivationPath()"></ion-toggle>
|
||||||
|
</ion-item>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
<ion-label stacked>Wallet service URL</ion-label>
|
||||||
|
<ion-input type="text" [(ngModel)]="formData.bwsURL" formControlName="bwsURL"></ion-input>
|
||||||
|
</ion-item>
|
||||||
|
</div>
|
||||||
|
<button ion-button block type="submit" [disabled]="!importForm.valid">Import wallet</button>
|
||||||
|
</form>
|
||||||
|
</ion-content>
|
|
@ -0,0 +1,14 @@
|
||||||
|
.tabs {
|
||||||
|
display: flex;
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 13px;
|
||||||
|
padding-bottom: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected {
|
||||||
|
border-bottom: 2px solid;
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { NavController } from 'ionic-angular';
|
||||||
|
import { Validators, FormBuilder, FormGroup } from '@angular/forms';
|
||||||
|
|
||||||
|
import { BwcProvider } from '../../../providers/bwc/bwc';
|
||||||
|
import { WalletProvider } from '../../../providers/wallet/wallet';
|
||||||
|
import { DerivationPathHelperProvider } from '../../../providers/derivationPathHelper/derivationPathHelper';
|
||||||
|
import { ConfigProvider } from '../../../providers/config/config';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'page-import-wallet',
|
||||||
|
templateUrl: 'import-wallet.html'
|
||||||
|
})
|
||||||
|
export class ImportWalletPage implements OnInit{
|
||||||
|
public formData: any;
|
||||||
|
public showAdvOpts: boolean;
|
||||||
|
public selectedTab: string;
|
||||||
|
public seedOptions: any;
|
||||||
|
|
||||||
|
private derivationPathByDefault: string;
|
||||||
|
private derivationPathForTestnet: string;
|
||||||
|
private importForm: FormGroup;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public navCtrl: NavController,
|
||||||
|
private form: FormBuilder,
|
||||||
|
private bwc: BwcProvider,
|
||||||
|
private pathHelper: DerivationPathHelperProvider,
|
||||||
|
private walletProvider: WalletProvider,
|
||||||
|
private configProvider: ConfigProvider,
|
||||||
|
) {
|
||||||
|
this.selectedTab = 'words';
|
||||||
|
this.derivationPathByDefault = this.pathHelper.default;
|
||||||
|
this.derivationPathForTestnet = this.pathHelper.defaultTestnet;
|
||||||
|
this.showAdvOpts = false;
|
||||||
|
this.formData = {
|
||||||
|
words: null,
|
||||||
|
mnemonicPassword: null,
|
||||||
|
file: null,
|
||||||
|
filePassword: null,
|
||||||
|
derivationPath: this.derivationPathByDefault,
|
||||||
|
testnet: false,
|
||||||
|
bwsURL: this.configProvider.get()['bws']['url'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.importForm = this.form.group({
|
||||||
|
words: ['', Validators.required],
|
||||||
|
mnemonicPassword: [''],
|
||||||
|
file: [''],
|
||||||
|
filePassword: [''],
|
||||||
|
derivationPath: [''],
|
||||||
|
testnet: [''],
|
||||||
|
bwsURL: [''],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
selectTab(tab: string) {
|
||||||
|
this.selectedTab = tab;
|
||||||
|
|
||||||
|
switch (tab) {
|
||||||
|
case 'words':
|
||||||
|
this.importForm.get('words').setValidators([Validators.required]);
|
||||||
|
this.importForm.get('file').clearValidators();
|
||||||
|
this.importForm.get('filePassword').clearValidators();
|
||||||
|
break;
|
||||||
|
case 'file':
|
||||||
|
this.importForm.get('file').setValidators([Validators.required]);
|
||||||
|
this.importForm.get('filePassword').setValidators([Validators.required]);
|
||||||
|
this.importForm.get('words').clearValidators();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
this.importForm.get('words').clearValidators();
|
||||||
|
this.importForm.get('file').clearValidators();
|
||||||
|
this.importForm.get('filePassword').clearValidators();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.importForm.get('words').updateValueAndValidity();
|
||||||
|
this.importForm.get('file').updateValueAndValidity();
|
||||||
|
this.importForm.get('filePassword').updateValueAndValidity();
|
||||||
|
}
|
||||||
|
|
||||||
|
setDerivationPath() {
|
||||||
|
this.formData.derivationPath = this.formData.testnet ? this.derivationPathForTestnet : this.derivationPathByDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
normalizeMnemonic(words: string) {
|
||||||
|
if (!words || !words.indexOf) return words;
|
||||||
|
var isJA = words.indexOf('\u3000') > -1;
|
||||||
|
var wordList = words.split(/[\u3000\s]+/);
|
||||||
|
|
||||||
|
return wordList.join(isJA ? '\u3000' : ' ');
|
||||||
|
};
|
||||||
|
|
||||||
|
import() {
|
||||||
|
console.log(this.formData);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class DerivationPathHelperProvider {
|
||||||
|
public default: string;
|
||||||
|
public defaultTestnet: string;
|
||||||
|
|
||||||
|
public constructor() {
|
||||||
|
this.default = "m/44'/0'/0'";
|
||||||
|
this.defaultTestnet = "m/44'/1'/0'";
|
||||||
|
}
|
||||||
|
|
||||||
|
parse(str: string) {
|
||||||
|
var arr = str.split('/');
|
||||||
|
var ret = {
|
||||||
|
derivationStrategy: '',
|
||||||
|
networkName: '',
|
||||||
|
account: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
if (arr[0] != 'm')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (arr[1]) {
|
||||||
|
case "44'":
|
||||||
|
ret.derivationStrategy = 'BIP44';
|
||||||
|
break;
|
||||||
|
case "45'":
|
||||||
|
return {
|
||||||
|
derivationStrategy: 'BIP45',
|
||||||
|
networkName: 'livenet',
|
||||||
|
account: 0,
|
||||||
|
}
|
||||||
|
case "48'":
|
||||||
|
ret.derivationStrategy = 'BIP48';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (arr[2]) {
|
||||||
|
case "0'":
|
||||||
|
ret.networkName = 'livenet';
|
||||||
|
break;
|
||||||
|
case "1'":
|
||||||
|
ret.networkName = 'testnet';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
var match = arr[3].match(/(\d+)'/);
|
||||||
|
if (!match)
|
||||||
|
return false;
|
||||||
|
ret.account = +match[1]
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue