Skip to content

Commit

Permalink
Merge pull request #11727 from gabrielbazan7/feat/sync-wallets
Browse files Browse the repository at this point in the history
[FEAT] Sync wallets across devices
  • Loading branch information
cmgustavo authored Jul 8, 2021
2 parents 54448b8 + 23e22ba commit 6a32d6f
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 4 deletions.
6 changes: 6 additions & 0 deletions src/components/info-sheet/info-sheet.html
Original file line number Diff line number Diff line change
Expand Up @@ -591,5 +591,11 @@
</span>
<span sheet-second-button-text translate>GOT IT</span>
</info-sheet-template>

<info-sheet-template *ngSwitchCase="'sync-wallets'" type="success">
<span sheet-title-text>{{params.title}}</span>
<span sheet-text>{{params.msg}}</span>
<span sheet-button-text translate>OK</span>
</info-sheet-template>
</div>
</action-sheet>
6 changes: 5 additions & 1 deletion src/pages/settings/key-settings/key-settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,11 @@


<ion-item-divider *ngIf="canSign">{{'Advanced' | translate}}</ion-item-divider>


<button ion-item *ngIf="!needsBackup" (click)="syncWallets()">
<span translate>Sync wallets across devices</span>
</button>

<button *ngIf="!needsBackup && canSign && !isDeletedSeed" ion-item (click)="openQrExport()">
<span translate>Export Key</span>
</button>
Expand Down
106 changes: 104 additions & 2 deletions src/pages/settings/key-settings/key-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,24 @@ import { ModalController, NavController, NavParams } from 'ionic-angular';
import * as _ from 'lodash';

// providers
import { AppProvider } from '../../../providers/app/app';
import { BwcErrorProvider } from '../../../providers/bwc-error/bwc-error';
import { ConfigProvider } from '../../../providers/config/config';
import { DerivationPathHelperProvider } from '../../../providers/derivation-path-helper/derivation-path-helper';
import { ErrorsProvider } from '../../../providers/errors/errors';
import { ExternalLinkProvider } from '../../../providers/external-link/external-link';
import { KeyProvider } from '../../../providers/key/key';
import { Logger } from '../../../providers/logger/logger';
import { LogsProvider } from '../../../providers/logs/logs';
import { OnGoingProcessProvider } from '../../../providers/on-going-process/on-going-process';
import { PlatformProvider } from '../../../providers/platform/platform';
import { PopupProvider } from '../../../providers/popup/popup';
import { ProfileProvider } from '../../../providers/profile/profile';
import { WalletProvider } from '../../../providers/wallet/wallet';
import { PushNotificationsProvider } from '../../../providers/push-notifications/push-notifications';
import {
WalletOptions,
WalletProvider
} from '../../../providers/wallet/wallet';

// pages
import { AddPage } from '../../add/add';
Expand Down Expand Up @@ -56,7 +67,15 @@ export class KeySettingsPage {
private keyProvider: KeyProvider,
private derivationPathHelperProvider: DerivationPathHelperProvider,
private modalCtrl: ModalController,
private errorsProvider: ErrorsProvider
private errorsProvider: ErrorsProvider,
private onGoingProcessProvider: OnGoingProcessProvider,
private pushNotificationsProvider: PushNotificationsProvider,
private bwcErrorProvider: BwcErrorProvider,
private popupProvider: PopupProvider,
private platformProvider: PlatformProvider,
private logsProvider: LogsProvider,
private appProvider: AppProvider,
private configProvider: ConfigProvider
) {
this.logger.info('Loaded: KeySettingsPage');
this.keyId = this.navParams.data.keyId;
Expand Down Expand Up @@ -240,4 +259,87 @@ export class KeySettingsPage {
});
modal.present();
}

public syncWallets(): void {
this.keyProvider
.handleEncryptedWallet(this.keyId)
.then((password: string) => {
let keys;
try {
keys = this.keyProvider.get(this.keyId, password);
} catch (err) {
const title =
'Your wallet is in a corrupt state. Please contact support and share the logs provided.';
let message;
try {
message =
err instanceof Error ? err.toString() : JSON.stringify(err);
} catch (error) {
message = 'Unknown error';
}
this.popupProvider.ionicAlert(title, message).then(() => {
// Share logs
const platform = this.platformProvider.isCordova
? this.platformProvider.isAndroid
? 'android'
: 'ios'
: 'desktop';
this.logsProvider.get(this.appProvider.info.nameCase, platform);
});
}

const opts: Partial<WalletOptions> = {};
const defaults = this.configProvider.getDefaults();
opts.bwsurl = defaults.bws.url;
opts.mnemonic = keys.mnemonic;

this._syncWallets(keys.mnemonic, opts);
})
.catch(err => {
if (
err &&
err.message != 'FINGERPRINT_CANCELLED' &&
err.message != 'PASSWORD_CANCELLED'
) {
const title = this.translate.instant('Could not decrypt wallet');
if (err.message == 'WRONG_PASSWORD') {
this.errorsProvider.showWrongEncryptPasswordError();
} else {
this.showErrorInfoSheet(this.bwcErrorProvider.msg(err), title);
}
}
});
}

private _syncWallets(words: string, opts): void {
this.onGoingProcessProvider.set('syncWallets');
this.profileProvider
.syncWallets(words, opts)
.then((wallets: any[]) => {
this.onGoingProcessProvider.clear();
this.finish(wallets);
})
.catch(err => {
this.onGoingProcessProvider.clear();
const title = this.translate.instant('Error');
this.showErrorInfoSheet(title, this.bwcErrorProvider.msg(err));
});
}

private async finish(wallets: any[]) {
wallets.forEach(wallet => {
this.walletProvider.updateRemotePreferences(wallet);
this.pushNotificationsProvider.updateSubscription(wallet);
this.profileProvider.setWalletBackup(wallet.credentials.walletId);
});
if (wallets && wallets[0]) {
this.profileProvider.setBackupGroupFlag(wallets[0].credentials.keyId);
await new Promise(resolve => setTimeout(resolve, 1000));
this.profileProvider.setNewWalletGroupOrder(wallets[0].credentials.keyId);
}
this.wallets = this.profileProvider.getWalletsFromGroup({
keyId: this.keyId,
showHidden: true
});
}
}
3 changes: 2 additions & 1 deletion src/providers/action-sheet/action-sheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ export type InfoSheetType =
| 'incorrect-recovery-prhase'
| 'correct-recovery-prhase'
| 'unsupported-alt-currency'
| 'custom-fee-warning';
| 'custom-fee-warning'
| 'sync-wallets';

export type OptionsSheetType =
| 'wallet-options'
Expand Down
1 change: 1 addition & 0 deletions src/providers/on-going-process/on-going-process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export class OnGoingProcessProvider {
generatingCSV: this.translate.instant('Generating .csv file...'),
gettingFeeLevels: this.translate.instant('Getting fee levels...'),
importingWallet: this.translate.instant('Importing Wallet...'),
syncWallets: this.translate.instant('Syncing Wallets...'),
joiningWallet: this.translate.instant('Joining Wallet...'),
rejectTx: this.translate.instant('Rejecting payment proposal...'),
removeTx: this.translate.instant('Deleting payment proposal...'),
Expand Down
56 changes: 56 additions & 0 deletions src/providers/profile/profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1016,6 +1016,62 @@ export class ProfileProvider {
});
}

public syncWallets(words, opts): Promise<any> {
this.logger.info('Syncing wallets');
words = this.normalizeMnemonic(words);
opts.words = words;
return this.serverAssistedImport(opts).then(async data => {
data.key = this.keyProvider.getMatchedKey(data.key);
data.walletClients.forEach(walletClient => {
walletClient.credentials.keyId = walletClient.keyId = data.key.id;
});
const boundWalletClients = [];
for (const walletClient of data.walletClients) {
const boundClient = await this.addAndBindWalletClient(walletClient, {
bwsurl: opts.bwsurl,
store: false
});
boundWalletClients.push(boundClient);
}
return this.storeProfileIfDirty()
.then(() => {
return this.countNewWallets(boundWalletClients).then(() => {
return Promise.resolve(_.compact(boundWalletClients));
});
})
.catch(err => {
return Promise.reject('failed to bind wallets:' + err);
});
});
}

private async countNewWallets(walletClients: any[]): Promise<any> {
let msg;
const title = this.translate.instant('Sync completed');
const newWalletsCount = _.compact(walletClients).length;
if (newWalletsCount > 0) {
const msg1 = this.translate.instant('New wallet found');
const msg2 = this.replaceParametersProvider.replace(
this.translate.instant('{{newWalletsCount}} wallets found'),
{
newWalletsCount
}
);

msg = newWalletsCount == 1 ? msg1 : msg2;
} else {
msg = this.translate.instant('Your key is already synced');
}
const infoSheet = this.actionSheetProvider.createInfoSheet('sync-wallets', {
title,
msg
});
await infoSheet.present();
await Observable.timer(4000).toPromise();
infoSheet.dismiss();
return Promise.resolve();
}

public importFile(str: string, opts): Promise<any> {
return this._importFile(str, opts).then(async data => {
if (opts.keyId) {
Expand Down

0 comments on commit 6a32d6f

Please sign in to comment.