diff --git a/backupRecovery.md b/backupRecovery.md new file mode 100644 index 000000000..5634f4b72 --- /dev/null +++ b/backupRecovery.md @@ -0,0 +1,59 @@ + + +# Copay Mnemonic Notes + +## Definitions + +### Backup Formats: + * Backup Words: 12 words mnemonic created as backup in Copay (from version v1.2) + * Backup File: Exported file from Copay, containing an AES encrypted JSON (see #export-format). + +### Backup recovery cases + * Case 1: Lost of device holding the wallet + * Case 2: Change to a new Bitcore Wallet Service (BWS) + * Case 3: Lost device + new Bitcore Wallet Service + +### Wallet Recovery Scope + * Partial Recovery: Wallet access is restored. It is possible to see wallet balance and past transactions. It is possible to send and receive coins. + * Full Recovery: All the features of Partial Recovery + Wallet Name, Copayer Names are recovered, Past Spend proposal metadata (who signed, and notes) are recoved. + +## Wallet Restore Scenarios + +### Non multisig wallets + + Case 1: From both Backup Words and Backup file, full recovery is possible. + - Enter the backup words or file at 'Import wallet' in a new device. + + Case 2: Partial recovery is possible using the device where the wallet is installed, pointing the the new server (Recreate Wallet feature). + - Point to the new server + - If the wallet is not registered at the new Wallet service, a "Recreate" buttom will appear at wallet's home. Click it to recreate the wallet. + - If the wallet existed, it could be needed to rescan Wallet's addresses for fund (from Settings -> Advanced -> Scan Addresses for Funds) + + Case 3: From both Backup Words and Backup file, partial recovery is possible. + (Using Backup Words) + - Enter the Backup Words at 'Import Wallet' + If the error "This wallet is not registered at the wallet service" appear: + - Go to 'Create Wallet', and enter the Backup Words at 'Advanced Options' + (Using Backup File) + - Enter the Backup File at 'Import Wallet' + + +### Multisig wallets + + Case 1: From both Backup Words and Backup file, full recovery is possible. + - Enter the backup words or file at 'Import wallet' in a new device. + + Case 2: Partial recovery is possible using the device where the wallet is installed, pointing the the new server (Recreate Wallet feature). + - Point to the new server + - If the wallet is not registered at the new Wallet service, a "Recreate" buttom will appear at wallet's home. Click it to recreate the wallet. + - If the wallet existed, it could be needed to rescan Wallet's addresses for fund (from Settings -> Advanced -> Scan Addresses for Funds) + + Case 3: Partial recovery is possible using: + + A) All the Backup Words of the copayers of the wallet or + - Enter Backup Words at Create or Join Wallet ( at the Advanced option sections). Note that the wallet's configuration (M-N and network paramenters) need to be entered and need to match the parameters that where enterered when the wallet was created. Name and Nickname of Copayers need to be entered also, but there is no need for them to match the original wallet setup. + - Ask other copayers to join the wallet using the given invitation code. All copayers need to enter their Backup Words at Join -> Advanced Options -> Backup Words. + + B) One File Backup and a quorum of Backup Words of the other members. + - Using the File Backup, import the wallet. + - Ask other copayers to import the wallet using the their Backup words. diff --git a/src/js/controllers/create.js b/src/js/controllers/create.js index 6bbb16c7d..e6941c631 100644 --- a/src/js/controllers/create.js +++ b/src/js/controllers/create.js @@ -87,7 +87,7 @@ angular.module('copayApp.controllers').controller('createController', this._create = function (opts) { $timeout(function() { - profileService.createWallet(opts, function(err, secret) { + profileService.createWallet(opts, function(err, secret, walletId) { self.loading = false; if (err) { if (err == "Error creating wallet" && opts.extendedPublicKey) { @@ -100,7 +100,11 @@ angular.module('copayApp.controllers').controller('createController', }); } else { - go.walletHome(); + if (opts.mnemonic && opts.n==1) { + $rootScope.$emit('Local/WalletImported', walletId); + } else { + go.walletHome(); + } } }); }, 100); diff --git a/src/js/controllers/import.js b/src/js/controllers/import.js index c8d77aae3..6dbc20d0d 100644 --- a/src/js/controllers/import.js +++ b/src/js/controllers/import.js @@ -65,7 +65,7 @@ angular.module('copayApp.controllers').controller('importController', self.loading = true; $timeout(function() { - profileService.importWalletMnemonic(words, opts, function(err, ret) { + profileService.importWalletMnemonic(words, opts, function(err, walletId) { self.loading = false; if (err) { self.error = err; @@ -73,7 +73,6 @@ angular.module('copayApp.controllers').controller('importController', $scope.$apply(); }); } - return $rootScope.$emit('Local/WalletImported', walletId); notification.success(gettext('Success'), gettext('Your wallet has been imported correctly')); go.walletHome(); diff --git a/src/js/controllers/index.js b/src/js/controllers/index.js index 6fb934e33..72b62a98a 100644 --- a/src/js/controllers/index.js +++ b/src/js/controllers/index.js @@ -394,7 +394,7 @@ angular.module('copayApp.controllers').controller('indexController', function($r self.updateTxHistory = function(skip) { var fc = profileService.focusedClient; - if (!fc.isComplete()) return; + if (!fc || !fc.isComplete()) return; if (!skip) { self.txHistory = []; } diff --git a/src/js/controllers/join.js b/src/js/controllers/join.js index 8e338f751..bf1f08914 100644 --- a/src/js/controllers/join.js +++ b/src/js/controllers/join.js @@ -153,6 +153,8 @@ angular.module('copayApp.controllers').controller('joinController', var opts = { secret: form.secret.$modelValue, + mnemonic: form.privateKey.$modelValue, + myName: form.myName.$modelValue extendedPrivateKey: form.privateKey.$modelValue, myName: form.myName.$modelValue } @@ -189,7 +191,12 @@ angular.module('copayApp.controllers').controller('joinController', return } $timeout(function() { - go.walletHome(); + var fc = profileService.focusedClient; + if (opts.mnemonic && fc.isComplete()) { + $rootScope.$emit('Local/WalletImported', fc.credentials.walletId); + } else { + go.walletHome(); + } }, 2000); }); }, 100); diff --git a/src/js/services/profileService.js b/src/js/services/profileService.js index b47cb312c..97cf78172 100644 --- a/src/js/services/profileService.js +++ b/src/js/services/profileService.js @@ -236,7 +236,7 @@ angular.module('copayApp.services') root.setAndStoreFocus(walletClient.credentials.walletId, function() { storageService.storeProfile(root.profile, function(err) { - return cb(null, secret); + return cb(null, secret, walletClient.credentials.walletId); }); }); }) @@ -347,13 +347,10 @@ angular.module('copayApp.services') var walletClient = bwcService.getClient(); $log.debug('Importing Wallet Mnemonic'); -console.log('[profileService.js.340]', words, opts); //TODO walletClient.importFromMnemonic(words, { network: opts.networkName, passphrase: opts.passphrase, }, function(err) { -console.log('[profileService.js.342:err:]',err); //TODO -console.log('[profileService.js.341:walletClient:]',walletClient.credentials.credentials); //TODO if (err) return bwsError.cb(err, gettext('Could not import'), cb);