diff --git a/www/i18n/locale-en-GB.json b/www/i18n/locale-en-GB.json
index ce1488a92e67a179c3c7f71df1652cf97619c81b..d63ff55904228ef387a18eb26e09950ebb2a865c 100644
--- a/www/i18n/locale-en-GB.json
+++ b/www/i18n/locale-en-GB.json
@@ -329,7 +329,9 @@
     "LOOKUP": {
       "TITLE": "Registry",
       "NEWCOMERS": "New members:",
+      "NEWCOMERS_COUNT": "{{count}} members",
       "PENDING": "Pending registrations:",
+      "PENDING_COUNT": "{{count}} pending registrations",
       "REGISTERED": "Registered {{sigDate | formatFromNow}}",
       "MEMBER_FROM": "Member since {{memberDate|formatFromNowShort}}",
       "BTN_NEWCOMERS": "Latest members",
@@ -436,15 +438,17 @@
     "ERROR_TX_SENT": "Sent transactions",
     "PENDING_TX_RECEIVED": "Transactions awaiting receipt",
     "EVENTS": "Events",
-    "WAITING_MEMBERSHIP": "Membership request sent. Waiting validation.",
+    "WAITING_MEMBERSHIP": "Membership application sent. Waiting validation.",
     "WAITING_CERTIFICATIONS": "You need {{needCertificationCount}} certification(s) to become a member",
     "WILL_MISSING_CERTIFICATIONS": "You will <b>lack certifications</b> soon (at least {{willNeedCertificationCount}} more are needed)",
     "WILL_NEED_RENEW_MEMBERSHIP": "Your membership <b>will expire {{membershipExpiresIn|formatDurationTo}}</b>. Remember to <a ng-click=\"doQuickFix('renew')\">renew your membership</a> before then.",
     "NEED_RENEW_MEMBERSHIP": "You are no longer a member because your membership <b>has expired</b>. Remember to <a ng-click=\"doQuickFix('renew')\">renew your membership</a>.",
+    "NO_WAITING_MEMBERSHIP": "No membership application pending. If you'd like to <b>become a member</ b>, please <a ng-click=\"doQuickFix('membership')\">send the membership application</a>.",
     "CERTIFICATION_COUNT": "Received certifications",
     "CERTIFICATION_COUNT_SHORT": "Certifications",
     "SIG_STOCK": "Stock of certifications to give",
     "BTN_RECEIVE_MONEY": "Receive",
+    "BTN_SELECT_ALTERNATIVES_IDENTITIES": "Switch to another identity...",
     "BTN_MEMBERSHIP_IN_DOTS": "Register as member...",
     "BTN_MEMBERSHIP_RENEW": "Renew membership",
     "BTN_MEMBERSHIP_RENEW_DOTS": "Renew membership...",
@@ -498,6 +502,10 @@
       "TITLE": "Enter a pseudonym",
       "HELP": "A pseudonym is needed to let other members find you."
     },
+    "SELECT_IDENTITY_MODAL": {
+      "TITLE": "Identity selection",
+      "HELP": "Several <b>different identities</b> have been sent, for the public key <span class=\"gray\"> <i class=\"ion-key\"></i> {{pubkey | formatPubkey}}</span>.<br/>Please select the identity to use:"
+    },
     "SECURITY":{
       "ADD_QUESTION" : "Add custom question",
       "BTN_CLEAN" : "Clean",
@@ -665,6 +673,7 @@
     "MEMBERSHIP_OUT_SENT": "Membership revocation sent",
     "NOT_NEED_MEMBERSHIP": "Already a member.",
     "IDENTITY_WILL_MISSING_CERTIFICATIONS": "This identity will soon lack certification (at least {{willNeedCertificationCount}}).",
+    "IDENTITY_NEED_MEMBERSHIP": "This identity did not send a membership request. She will have to if she wishes to become a member.",
     "REVOCATION_SENT": "Revocation sent successfully",
     "REVOCATION_SENT_WAITING_PROCESS": "Revocation <b>has been sent successfully</b>. It is awaiting processing.",
     "FEATURES_NOT_IMPLEMENTED": "This features is not implemented yet.<br/><br/>Why not to contribute to get it faster? ;)",
@@ -683,6 +692,7 @@
     "LOGIN_UNUSED_WALLET": "The account seems to be <b>inactive</b>.<br/><br/>It's probably a <b>typing error</b> when sign in. Please try again, checking that <b>public key is yours<b/>.",
     "FIX_IDENTITY": "The pseudonym <b>{{uid}}</b> will be published again, replacing the old publication that has expired.<br/></br/><b>Are you sure</b> you want to continue?",
     "FIX_MEMBERSHIP": "Your application for membership will be sent.<br/></br/><b>Are you sure?</b>",
+    "MEMBERSHIP": "Your membership request will be sent. <br/></br/><b>Are you sure?</b>",
     "RENEW_MEMBERSHIP": "Your membership will be renewed.<br/></br/><b>Are you sure?</b>",
     "REVOKE_IDENTITY": "You will <b>definitely revoke this identity</b>.<br/><br/>The public key and the associated pseudonym <b>will never be used again</b> (for a member account).<br/></br/><b>Are you sure</b> you want to revoke this identity?",
     "REVOKE_IDENTITY_2": "This operation is <b>irreversible</b>!<br/><br/>Are you sure you want to <b>revoke this identity</b>?",
diff --git a/www/i18n/locale-en.json b/www/i18n/locale-en.json
index 4a3a5d1b2a039289d3739e497e2f951118b73f49..3068738159514369f8ee8d33cb33b6489eee5515 100644
--- a/www/i18n/locale-en.json
+++ b/www/i18n/locale-en.json
@@ -329,7 +329,9 @@
     "LOOKUP": {
       "TITLE": "Registry",
       "NEWCOMERS": "New members:",
+      "NEWCOMERS_COUNT": "{{count}} members",
       "PENDING": "Pending registrations:",
+      "PENDING_COUNT": "{{count}} pending registrations",
       "REGISTERED": "Registered {{sigDate | formatFromNow}}",
       "MEMBER_FROM": "Member since {{memberDate|formatFromNowShort}}",
       "BTN_NEWCOMERS": "Latest members",
@@ -436,15 +438,17 @@
     "ERROR_TX_SENT": "Sent transactions",
     "PENDING_TX_RECEIVED": "Transactions awaiting receipt",
     "EVENTS": "Events",
-    "WAITING_MEMBERSHIP": "Membership request sent. Waiting validation.",
+    "WAITING_MEMBERSHIP": "Membership application sent. Waiting validation.",
     "WAITING_CERTIFICATIONS": "You need {{needCertificationCount}} certification(s) to become a member",
     "WILL_MISSING_CERTIFICATIONS": "You will <b>lack certifications</b> soon (at least {{willNeedCertificationCount}} more are needed)",
     "WILL_NEED_RENEW_MEMBERSHIP": "Your membership <b>will expire {{membershipExpiresIn|formatDurationTo}}</b>. Remember to <a ng-click=\"doQuickFix('renew')\">renew your membership</a> before then.",
     "NEED_RENEW_MEMBERSHIP": "You are no longer a member because your membership <b>has expired</b>. Remember to <a ng-click=\"doQuickFix('renew')\">renew your membership</a>.",
+    "NO_WAITING_MEMBERSHIP": "No membership application pending. If you'd like to <b>become a member</ b>, please <a ng-click=\"doQuickFix('membership')\">send the membership application</a>.",
     "CERTIFICATION_COUNT": "Received certifications",
     "CERTIFICATION_COUNT_SHORT": "Certifications",
     "SIG_STOCK": "Stock of certifications to give",
     "BTN_RECEIVE_MONEY": "Receive",
+    "BTN_SELECT_ALTERNATIVES_IDENTITIES": "Switch to another identity...",
     "BTN_MEMBERSHIP_IN_DOTS": "Register as member...",
     "BTN_MEMBERSHIP_RENEW": "Renew membership",
     "BTN_MEMBERSHIP_RENEW_DOTS": "Renew membership...",
@@ -498,6 +502,10 @@
       "TITLE": "Enter a pseudonym",
       "HELP": "A pseudonym is needed to let other members find you."
     },
+    "SELECT_IDENTITY_MODAL": {
+      "TITLE": "Identity selection",
+      "HELP": "Several <b>different identities</b> have been sent, for the public key <span class=\"gray\"> <i class=\"ion-key\"></i> {{pubkey | formatPubkey}}</span>.<br/>Please select the identity to use:"
+    },
     "SECURITY":{
       "ADD_QUESTION" : "Add custom question",
       "BTN_CLEAN" : "Clean",
@@ -665,6 +673,7 @@
     "MEMBERSHIP_OUT_SENT": "Membership revocation sent",
     "NOT_NEED_MEMBERSHIP": "Already a member.",
     "IDENTITY_WILL_MISSING_CERTIFICATIONS": "This identity will soon lack certification (at least {{willNeedCertificationCount}}).",
+    "IDENTITY_NEED_MEMBERSHIP": "This identity did not send a membership request. She will have to if she wishes to become a member.",
     "REVOCATION_SENT": "Revocation sent successfully",
     "REVOCATION_SENT_WAITING_PROCESS": "Revocation <b>has been sent successfully</b>. It is awaiting processing.",
     "FEATURES_NOT_IMPLEMENTED": "This features is not implemented yet.<br/><br/>Why not to contribute to get it faster? ;)",
@@ -683,6 +692,7 @@
     "LOGIN_UNUSED_WALLET": "The account seems to be <b>inactive</b>.<br/><br/>It's probably a <b>typing error</b> when sign in. Please try again, checking that <b>public key is yours<b/>.",
     "FIX_IDENTITY": "The pseudonym <b>{{uid}}</b> will be published again, replacing the old publication that has expired.<br/></br/><b>Are you sure</b> you want to continue?",
     "FIX_MEMBERSHIP": "Your application for membership will be sent.<br/></br/><b>Are you sure?</b>",
+    "MEMBERSHIP": "Your membership request will be sent. <br/></br/><b>Are you sure?</b>",
     "RENEW_MEMBERSHIP": "Your membership will be renewed.<br/></br/><b>Are you sure?</b>",
     "REVOKE_IDENTITY": "You will <b>definitely revoke this identity</b>.<br/><br/>The public key and the associated pseudonym <b>will never be used again</b> (for a member account).<br/></br/><b>Are you sure</b> you want to revoke this identity?",
     "REVOKE_IDENTITY_2": "This operation is <b>irreversible</b>!<br/><br/>Are you sure you want to <b>revoke this identity</b>?",
diff --git a/www/i18n/locale-fr-FR.json b/www/i18n/locale-fr-FR.json
index 4ae6729a01b212fdeff9cfcbbc0cb95f9853150e..7afcaf03575eff00b5fd6d08d8552af58615f7b2 100644
--- a/www/i18n/locale-fr-FR.json
+++ b/www/i18n/locale-fr-FR.json
@@ -446,10 +446,12 @@
     "WILL_MISSING_CERTIFICATIONS": "Vous allez bientôt <b>manquer de certification</b> (au moins {{willNeedCertificationCount}} sont requises)",
     "WILL_NEED_RENEW_MEMBERSHIP": "Votre adhésion comme membre <b>va expirer {{membershipExpiresIn|formatDurationTo}}</b>. Pensez à <a ng-click=\"doQuickFix('renew')\">renouveler votre adhésion</a> d'ici là.",
     "NEED_RENEW_MEMBERSHIP": "Vous n'êtes plus membre, car votre adhésion <b>a expiré</b>. Pensez à <a ng-click=\"doQuickFix('renew')\">renouveler votre adhésion</a>.",
+    "NO_WAITING_MEMBERSHIP": "Aucune demande d'adhésion en attente. Si vous souhaitez <b>devenir membre</b>, pensez à <a ng-click=\"doQuickFix('membership')\">envoyer la demande d'adhésion</a>.",
     "CERTIFICATION_COUNT": "Certifications reçues",
     "CERTIFICATION_COUNT_SHORT": "Certifications",
     "SIG_STOCK": "Certifications envoyées",
     "BTN_RECEIVE_MONEY": "Encaisser",
+    "BTN_SELECT_ALTERNATIVES_IDENTITIES": "Basculer vers une autre identité...",
     "BTN_MEMBERSHIP_IN_DOTS": "Devenir membre...",
     "BTN_MEMBERSHIP_RENEW": "Renouveler l'adhésion",
     "BTN_MEMBERSHIP_RENEW_DOTS": "Renouveler l'adhésion...",
@@ -503,6 +505,10 @@
       "TITLE": "Choisissez un pseudonyme",
       "HELP": "Un pseudonyme est obligatoire pour devenir membre."
     },
+    "SELECT_IDENTITY_MODAL": {
+      "TITLE": "Sélection de l'identité",
+      "HELP": "Plusieurs <b>identités différentes</b> ont été envoyées, pour la clé publique <span class=\"gray\"><i class=\"ion-key\"></i> {{pubkey|formatPubkey}}</span>.<br/>Veuillez sélectionner le dossier à utiliser :"
+    },
     "SECURITY": {
       "ADD_QUESTION": "Ajouter une question personnalisée ",
       "BTN_CLEAN": "Vider",
@@ -670,6 +676,7 @@
     "MEMBERSHIP_OUT_SENT": "Résiliation envoyée",
     "NOT_NEED_MEMBERSHIP": "Vous êtes déjà membre.",
     "IDENTITY_WILL_MISSING_CERTIFICATIONS": "Cette identité va bientôt manquer de certification (au moins {{willNeedCertificationCount}}).",
+    "IDENTITY_NEED_MEMBERSHIP": "Cette identité n'a pas envoyée de demande d'adhésion. Elle devra si elle souhaite devenir membre.",
     "REVOCATION_SENT": "Revocation envoyée",
     "REVOCATION_SENT_WAITING_PROCESS": "La <b>révocation de cette identité</b> a été demandée et est en attente de traitement.",
     "FEATURES_NOT_IMPLEMENTED": "Cette fonctionnalité est encore en cours de développement.<br/>Pourquoi ne pas <b>contribuer à Cesium</b>, pour l'obtenir plus rapidement ? ;)",
@@ -688,6 +695,7 @@
     "LOGIN_UNUSED_WALLET": "Le compte connecté semble <b>inactif</b>.<br/><br/>Il s'agit probablement d'une <b>erreur de saisie</b> dans vos identifiants de connexion. Veuillez recommencer, en vérifiant que <b>la clé publique est celle de votre compte</b>.",
     "FIX_IDENTITY": "Le pseudonyme <b>{{uid}}</b> va être publiée à nouveau, en remplacement de l'ancienne publication qui a expirée.<br/></br/><b>Etes-vous sûr</b> de vouloir continuer ?",
     "FIX_MEMBERSHIP": "Votre demande d'adhésion comme membre va être renvoyée.<br/></br/><b>Etes-vous sûr</b> de vouloir continuer ?",
+    "MEMBERSHIP": "Votre demande d'adhésion comme membre va être envoyée.<br/></br/><b>Etes-vous sûr</b> de vouloir continuer ?",
     "RENEW_MEMBERSHIP": "Votre adhésion comme membre va être renouvellée.<br/></br/><b>Etes-vous sûr</b> de vouloir continuer ?",
     "REVOKE_IDENTITY": "Vous allez <b>revoquer définitivement cette identité</b>.<br/><br/>La clé publique et le pseudonyme associés <b>ne pourront plus jamais être utilisés</b> (pour un compte membre). <br/></br/><b>Etes-vous sûr</b> de vouloir révoquer définitivement ce compte ?",
     "REVOKE_IDENTITY_2": "Cette opération est <b>irreversible</b> !<br/><br/>Etes-vous vraiment sûr de vouloir <b>révoquer définitivement</b> ce compte ?",
diff --git a/www/js/controllers/wallet-controllers.js b/www/js/controllers/wallet-controllers.js
index 5b86b7da2abbb5ed08dcc0e7326374e4e55c803b..1c71d3139edfeff11953c96b5cf70c3358bc8504 100644
--- a/www/js/controllers/wallet-controllers.js
+++ b/www/js/controllers/wallet-controllers.js
@@ -55,11 +55,10 @@ angular.module('cesium.wallet.controllers', ['cesium.services', 'cesium.currency
   .controller('WalletTxErrorCtrl', WalletTxErrorController)
 
   .controller('WalletSecurityModalCtrl', WalletSecurityModalController)
-
 ;
 
 function WalletController($scope, $rootScope, $q, $ionicPopup, $timeout, $state, $translate, $ionicPopover,
-                          UIUtils, Modals, csConfig, csSettings, csWallet, csHelp) {
+                          UIUtils, Modals, BMA, csConfig, csSettings, csCurrency, csWallet, csHelp) {
   'ngInject';
 
   $scope.loading = true;
@@ -71,6 +70,7 @@ function WalletController($scope, $rootScope, $q, $ionicPopup, $timeout, $state,
     }
     else {
       // update view (to refresh avatar + plugin data, such as profile, subscriptions...)
+      UIUtils.loading.hide();
       $timeout($scope.updateView, 300);
     }
   });
@@ -186,56 +186,64 @@ function WalletController($scope, $rootScope, $q, $ionicPopup, $timeout, $state,
         UIUtils.loading.hide();
       })
       .catch(function(err) {
+        if (err == 'CANCELLED') throw err;
+        if (err && err.ucode != BMA.errorCodes.MEMBERSHIP_ALREADY_SEND) return;
         if (!retryCount || retryCount <= 2) {
-          $timeout(function() {
+          return $timeout(function() {
             $scope.doMembershipIn(retryCount ? retryCount+1 : 1);
           }, 1000);
         }
-        else {
-          UIUtils.onError('ERROR.SEND_MEMBERSHIP_IN_FAILED')(err)
-            .then(function() {
-              $scope.membershipIn(); // loop
-            });
-        }
+        throw err;
       });
   };
 
 
   // Send membership IN
-  $scope.membershipIn = function() {
+  $scope.membershipIn = function(keepSelf) {
     $scope.hideActionsPopover();
 
-    if ($scope.formData.isMember) {
+    if (csWallet.isMember()) {
       return UIUtils.alert.info("INFO.NOT_NEED_MEMBERSHIP");
     }
 
-    return $scope.showUidPopup()
-    .then(function (uid) {
-      UIUtils.loading.show();
-      // If uid changed, or self blockUid not retrieve : do self() first
-      if (!$scope.formData.blockUid || uid != $scope.formData.uid) {
-        $scope.formData.blockUid = null;
-        $scope.formData.uid = uid;
-        csWallet.self(uid, false/*do NOT load membership here*/)
-        .then(function() {
-          $scope.doMembershipIn();
-        })
-        .catch(function(err){
-          UIUtils.onError('ERROR.SEND_IDENTITY_FAILED')(err)
-            .then(function() {
-              $scope.membershipIn(); // loop
-            });
-        });
-      }
-      else {
-        $scope.doMembershipIn();
-      }
-    })
-    .catch(function(err){
-       UIUtils.loading.hide();
-       UIUtils.alert.info(err);
-       $scope.membershipIn(); // loop
-    });
+    // Select uid (or reuse it)
+    return ((keepSelf && !!$scope.formData.blockUid) ?
+        $q.when($scope.formData.uid) :
+        $scope.showUidPopup())
+
+      // Ask user confirmation
+      .then(function(uid) {
+        return UIUtils.alert.confirm("CONFIRM.MEMBERSHIP")
+          .then(function(confirm) {
+            if (!confirm) throw 'CANCELLED';
+            return uid;
+          });
+      })
+
+      // Send self (identity) - if need
+      .then(function (uid) {
+        UIUtils.loading.show();
+
+        // If uid changed, or self blockUid not retrieve : do self() first
+        if (!$scope.formData.blockUid || uid != $scope.formData.uid) {
+          $scope.formData.blockUid = null;
+          $scope.formData.uid = uid;
+
+          return csWallet.self(uid, false/*do NOT load membership here*/);
+        }
+      })
+
+      // Send membership
+      .then($scope.doMembershipIn)
+      .catch(function(err) {
+        if (err == 'CANCELLED') return;
+        if (!csWallet.data.uid) {
+          UIUtils.onError('ERROR.SEND_IDENTITY_FAILED')(err);
+        }
+        else {
+          UIUtils.onError('ERROR.SEND_MEMBERSHIP_IN_FAILED')(err);
+        }
+      });
   };
 
   // Send membership OUT
@@ -319,9 +327,7 @@ function WalletController($scope, $rootScope, $q, $ionicPopup, $timeout, $state,
       .catch(function(err){
         if (err == 'CANCELLED') return;
         UIUtils.loading.hide();
-        UIUtils.alert.error(err)
-          // loop
-          .then($scope.renewMembership);
+        UIUtils.alert.error(err);
       });
   };
 
@@ -332,27 +338,27 @@ function WalletController($scope, $rootScope, $q, $ionicPopup, $timeout, $state,
   $scope.fixIdentity = function() {
     if (!$scope.formData.uid) return;
 
-    return $translate('CONFIRM.FIX_IDENTITY', {uid: $scope.formData.uid})
-      .then(function(message) {
-        return UIUtils.alert.confirm(message);
+    return $q.all([
+      csWallet.auth(),
+      $translate('CONFIRM.FIX_IDENTITY', {uid: $scope.formData.uid})
+    ])
+      .then(function(res) {
+        return UIUtils.alert.confirm(res[1]);
       })
       .then(function(confirm) {
         if (!confirm) return;
         UIUtils.loading.show();
-        // Reset membership data
+        // Reset self data
         $scope.formData.blockUid = null;
+        // Reset membership data
         $scope.formData.sigDate = null;
         return csWallet.self($scope.formData.uid);
       })
-      .then(function() {
-        return $scope.doMembershipIn();
-      })
+      .then($scope.doMembershipIn)
       .catch(function(err){
+        if (err == 'CANCELLED') return;
         UIUtils.loading.hide();
-        UIUtils.alert.error(err)
-          .then(function() {
-            $scope.fixIdentity(); // loop
-          });
+        UIUtils.alert.error(err);
       });
   };
 
@@ -362,22 +368,28 @@ function WalletController($scope, $rootScope, $q, $ionicPopup, $timeout, $state,
   $scope.fixMembership = function() {
     if (!$scope.formData.uid) return;
 
-    return UIUtils.alert.confirm("CONFIRM.FIX_MEMBERSHIP")
+    if (csWallet.isMember()) {
+      return UIUtils.alert.info("INFO.NOT_NEED_MEMBERSHIP");
+    }
+
+    return csWallet.auth()
+      .then(function() {
+        UIUtils.alert.confirm("CONFIRM.FIX_MEMBERSHIP");
+      })
       .then(function(confirm) {
         if (!confirm) return;
         UIUtils.loading.show();
-        // Reset membership data
+        // Reset self data
         $scope.formData.blockUid = null;
+        // Reset membership data
         $scope.formData.sigDate = null;
-        return Wallet.self($scope.formData.uid, false/*do NOT load membership here*/);
-      })
-      .then(function() {
-        return $scope.doMembershipIn();
+        return csWallet.self($scope.formData.uid, false/*do NOT load membership here*/);
       })
+      .then($scope.doMembershipIn)
       .catch(function(err){
+        if (err == 'CANCELLED') return;
         UIUtils.loading.hide();
-        UIUtils.alert.info(err);
-        $scope.fixMembership(); // loop
+        UIUtils.alert.error(err);
       });
   };
 
@@ -389,6 +401,9 @@ function WalletController($scope, $rootScope, $q, $ionicPopup, $timeout, $state,
     if (event == 'renew') {
       $scope.renewMembership();
     }
+    else if (event == 'membership') {
+      $scope.membershipIn(true/*keep self*/);
+    }
     else if (event == 'fixMembership') {
       $scope.fixMembership();
     }
@@ -419,29 +434,10 @@ function WalletController($scope, $rootScope, $q, $ionicPopup, $timeout, $state,
   $scope.startWalletTour = function() {
     $scope.hideActionsPopover();
     return csHelp.wallet.tour();
-    //return $scope.showHelpTip(0, true);
   };
 
-  $scope.showHelpTip = function(index, isTour) {
+  $scope.showHelpTip = function() {
     return csHelp.wallet.helptip();
-    /*index = angular.isDefined(index) ? index : csSettings.data.helptip.wallet;
-    isTour = angular.isDefined(isTour) ? isTour : false;
-
-    if (index < 0 || index > 3/!*max step*!/) return;
-
-    // Create a new scope for the tour controller
-    var helptipScope = $scope.createHelptipScope(isTour);
-    if (!helptipScope) return; // could be undefined, if a global tour already is already started
-    helptipScope.tour = isTour;
-
-    return helptipScope.startWalletTour(index, false)
-      .then(function(endIndex) {
-        helptipScope.$destroy();
-        if (!isTour) {
-          csSettings.data.helptip.wallet = endIndex;
-          csSettings.store();
-        }
-      });*/
   };
 
   $scope.showQRCode = function(id, text, timeout) {
@@ -534,7 +530,28 @@ function WalletController($scope, $rootScope, $q, $ionicPopup, $timeout, $state,
 
   $scope.showSecurityModal = function(){
     $scope.hideActionsPopover();
-    Modals.showAccountSecurity();
+    return Modals.showAccountSecurity();
+  };
+
+  $scope.showSelectIdentitiesModal = function(){
+    $scope.hideActionsPopover();
+
+    return Modals.showSelectPubkeyIdentity({
+        identities: [$scope.formData.requirements].concat($scope.formData.requirements.alternatives)
+      })
+      .then(function(idty) {
+        if (!idty || !idty.uid) return;
+
+        $scope.loading = true;
+
+        // Set self (= uid + blockUid)
+        return csWallet.setSelf(idty.uid, idty.blockUid)
+          .then(function() {
+            $scope.loading=false;
+            $scope.updateView();
+            UIUtils.loading.hide();
+          });
+      });
   };
 
 }
@@ -777,7 +794,7 @@ function WalletTxErrorController($scope, UIUtils, csWallet) {
 
 }
 
-function WalletSecurityModalController($scope, UIUtils, csWallet, $translate, CryptoUtils){
+function WalletSecurityModalController($scope, UIUtils, csWallet, $translate){
 
   $scope.slides = {
     slider: null,
@@ -1132,3 +1149,5 @@ function WalletSecurityModalController($scope, UIUtils, csWallet, $translate, Cr
   };
 
 }
+
+
diff --git a/www/js/controllers/wot-controllers.js b/www/js/controllers/wot-controllers.js
index 52ea3821d70cb08b3a1867f43b9006bcea0d4bf5..730557fca9d419342d1e61257405db2d9cd83ff8 100644
--- a/www/js/controllers/wot-controllers.js
+++ b/www/js/controllers/wot-controllers.js
@@ -146,6 +146,7 @@ angular.module('cesium.wot.controllers', ['cesium.services'])
 
   .controller('WotCertificationsViewCtrl', WotCertificationsViewController)
 
+  .controller('WotSelectPubkeyIdentityModalCtrl', WotSelectPubkeyIdentityModalController)
 
 ;
 
@@ -945,7 +946,7 @@ function WotIdentityAbstractController($scope, $rootScope, $state, $translate, $
 /**
  * Identity view controller - should extend WotIdentityAbstractCtrl
  */
-function WotIdentityViewController($scope, $rootScope, $controller, $timeout, UIUtils, csWallet, csTx) {
+function WotIdentityViewController($scope, $rootScope, $controller, $timeout, UIUtils, csWallet) {
   'ngInject';
   // Initialize the super class and extend it.
   angular.extend(this, $controller('WotIdentityAbstractCtrl', {$scope: $scope}));
@@ -1264,3 +1265,46 @@ function WotCertificationsViewController($scope, $rootScope, $controller, csSett
 }
 
 
+/**
+ * Select identities from a pubkey (yusfull when many self on the same pubkey)
+ * @param $scope
+ * @param $q
+ * @param csWot
+ * @param parameters
+ * @constructor
+ */
+function WotSelectPubkeyIdentityModalController($scope, $q, csWot, parameters) {
+
+  $scope.loading = true;
+
+  $scope.load = function() {
+    // If list of identities given by parameters: use it
+    if (parameters && parameters.identities) {
+      $scope.identities = parameters.identities;
+      $scope.pubkey = $scope.identities[0].pubkey;
+      $scope.loading = false;
+      return $q.when();
+    }
+
+    // Or load from pubkey
+    $scope.pubkey = parameters && parameters.pubkey;
+    if (!pubkey) {
+      return $q.reject('Missing parameters: [pubkey] or [identities]');
+    }
+
+    return csWot.loadRequirements({pubkey: pubkey, uid: uid})
+      .then(function(data) {
+        if (data && data.requirements) {
+          $scope.identities = data.requirements;
+          if (data.requirements.alternatives) {
+            $scope.identities = [data.requirements].concat(data.requirements.alternatives);
+          }
+          else {
+            $scope.identities = [data.requirements];
+          }
+        }
+        $scope.loading = false;
+      });
+  };
+  $scope.$on('modal.shown', $scope.load);
+}
diff --git a/www/js/services/device-services.js b/www/js/services/device-services.js
index b0d86f152c3fc0817b201d1b58f0b0fc98678a0b..5ffe61da021a01d0ac810b47b61d6980af32f2b1 100644
--- a/www/js/services/device-services.js
+++ b/www/js/services/device-services.js
@@ -157,7 +157,6 @@ angular.module('cesium.device.services', ['cesium.utils.services', 'cesium.setti
               var property = paths.length && paths[paths.length-1];
               paths.reduce(function(res, path) {
                 if (path == property) {
-                  console.log("setting value");
                   res[property] = value;
                   return;
                 }
diff --git a/www/js/services/modal-services.js b/www/js/services/modal-services.js
index 9f2deaf32f45635ccbfd0cfe6cbab5aa6ef3abbd..3ad9f7cb029e44b487afafcf8d607f28ad3e4cc9 100644
--- a/www/js/services/modal-services.js
+++ b/www/js/services/modal-services.js
@@ -131,7 +131,7 @@ angular.module('cesium.modal.services', [])
   };
 })
 
-.factory('Modals', function(ModalUtils, UIUtils) {
+.factory('Modals', function($rootScope, ModalUtils, UIUtils) {
   'ngInject';
 
   function showTransfer(parameters) {
@@ -204,6 +204,11 @@ angular.module('cesium.modal.services', [])
       parameters);
   }
 
+  function showSelectPubkeyIdentity(parameters) {
+    return ModalUtils.show('templates/wot/modal_select_pubkey_identity.html', 'WotSelectPubkeyIdentityModalCtrl',
+      parameters);
+  }
+
   return {
     showTransfer: showTransfer,
     showLogin: showLogin,
@@ -216,7 +221,8 @@ angular.module('cesium.modal.services', [])
     showJoinWallet: showJoinWallet,
     showHelp: showHelp,
     showAccountSecurity: showAccountSecurity,
-    showLicense: showLicense
+    showLicense: showLicense,
+    showSelectPubkeyIdentity: showSelectPubkeyIdentity
   };
 
 });
diff --git a/www/js/services/wallet-services.js b/www/js/services/wallet-services.js
index 17474709e19f15288a61c2e8eb7bd8f6884221b2..fbe78518b08e9fa53191c8f76b4eaaf81548819b 100644
--- a/www/js/services/wallet-services.js
+++ b/www/js/services/wallet-services.js
@@ -15,6 +15,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
       // @Deprecated
       OLD_STORAGE_KEY: 'CESIUM_DATA',
       STORAGE_PUBKEY: 'pubkey',
+      STORAGE_UID: 'uid',
       STORAGE_SECKEY: 'seckey',
       /* Need for compat with old currencies (test_net and sou) */
       TX_VERSION:   csConfig.compatProtocol_0_80 ? 3 : BMA.constants.PROTOCOL_VERSION,
@@ -72,8 +73,8 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
 
     resetTxAndSources = function(){
       // reset sources data
-      data.sources = [];
-      data.sourcesIndexByKey = {};
+      data.sources = undefined;
+      data.sourcesIndexByKey = undefined;
       data.balance = 0;
       // reset TX data
       data.tx = data.tx || {};
@@ -93,6 +94,8 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
     },
 
     addSources = function(sources) {
+      data.sources = data.sources || [];
+      data.sourcesIndexByKey = data.sourcesIndexByKey || {};
       _(sources).forEach(function(src) {
         addSource(src, data.sources, data.sourcesIndexByKey);
       });
@@ -176,7 +179,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
           // Load data if need
           // If user just login, force data full load (even if min data asked)
           // because the user can wait (after the login modal)
-          var loadOptions = !needLogin && options && options.minData ? {minData: true} : undefined;
+          var loadOptions = !needLogin && options && options.minData ? {minData: true} : undefined/*=load all*/;
           if (!isDataLoaded(loadOptions)) {
             return loadData(loadOptions);
           }
@@ -264,7 +267,6 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
       return !!(data.pubkey && data.keypair && data.keypair.signSk);
     },
 
-
     getKeypair = function(options) {
       if (!started) {
         return (startPromise || start())
@@ -295,18 +297,20 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
 
     isNeverUsed = function() {
       if (!data.loaded) return undefined; // undefined if not full loaded
-      return !data.pubkey || (
+      return !data.pubkey || !(
          // Check registration
-         !data.isMember &&
-         !data.requirements.pendingMembership &&
-         !data.requirements.wasMember &&
+         data.isMember ||
+         data.requirements.pendingMembership ||
+         !data.requirements.needSelf ||
+         data.requirements.wasMember ||
 
          // Check TX history
-         !data.tx.history.length &&
-         !data.tx.pendings.length &&
+         data.tx.history.length ||
+         data.tx.pendings.length ||
 
          // Check extended data (name+avatar)
-         !data.name && !data.avatar
+         data.name ||
+         data.avatar
         );
     },
 
@@ -334,6 +338,15 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
 
           // Use local storage for pubkey
           jobs.push(localStorage.put(constants.STORAGE_PUBKEY, data.pubkey));
+
+          // Use local storage for uid - fix #625
+          if (data.uid) {
+            jobs.push(localStorage.put(constants.STORAGE_UID, data.uid));
+          }
+          else {
+            jobs.push(localStorage.put(constants.STORAGE_UID, null));
+          }
+
           // Clean old storage
           jobs.push(localStorage.put(constants.OLD_STORAGE_KEY, null));
 
@@ -345,6 +358,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
           return $q.all([
             sessionStorage.put(constants.STORAGE_SECKEY, null),
             localStorage.put(constants.STORAGE_PUBKEY, null),
+            localStorage.put(constants.STORAGE_UID, null),
             // Clean old storage
             localStorage.put(constants.OLD_STORAGE_KEY, null)
           ]);
@@ -354,6 +368,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
         return $q.all([
           sessionStorage.put(constants.STORAGE_SECKEY, null),
           localStorage.put(constants.STORAGE_PUBKEY, null),
+          localStorage.put(constants.STORAGE_UID, null),
           // Clean old storage
           localStorage.put(constants.OLD_STORAGE_KEY, null)
         ]);
@@ -364,11 +379,13 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
     restore = function() {
       return  $q.all([
           sessionStorage.get(constants.STORAGE_SECKEY),
-          localStorage.get(constants.STORAGE_PUBKEY)
+          localStorage.get(constants.STORAGE_PUBKEY),
+          localStorage.get(constants.STORAGE_UID)
         ])
         .then(function(res) {
           var seckey = res[0];
           var pubkey = res[1];
+          var uid = res[2];
           if (!pubkey || pubkey == 'null') return;
 
           var keypair;
@@ -386,6 +403,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
           }
 
           data.pubkey = pubkey;
+          data.uid = uid;
           data.keypair = keypair || {signPk: undefined, signSk: undefined};
 
           console.debug('[wallet] Restore \'{0}\' from local storage.'.format(pubkey.substring(0,8)));
@@ -402,93 +420,18 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
       return data;
     },
 
-    resetRequirements = function() {
-      data.requirements = {
-        needSelf: true,
-        needMembership: true,
-        canMembershipOut: false,
-        needRenew: false,
-        pendingMembership: false,
-        wasMember: false,
-        certificationCount: 0,
-        needCertifications: false,
-        needCertificationCount: 0,
-        willNeedCertificationCount: 0
-      };
-      data.blockUid = null;
-      data.isMember = false;
-      data.sigDate = null;
-      cleanEventsByContext('requirements');
-    },
-
     loadRequirements = function() {
-      return $q(function(resolve, reject) {
+      // Clean existing events
+      cleanEventsByContext('requirements');
 
-        // Clean existing events
-        cleanEventsByContext('requirements');
+      // Get requirements
+      return csWot.loadRequirements(data)
+        .then(function(){
 
-        // Get requirements
-        BMA.wot.requirements({pubkey: data.pubkey})
-        .then(function(res){
-          if (!res.identities || res.identities.length === 0) {
-            resetRequirements();
-            resolve();
-            return;
-          }
-          // Sort to select the best identity
-          if (res.identities.length > 1) {
-            // Select the best identity, by sorting using this order
-            //  - same wallet uid
-            //  - is member
-            //  - has a pending membership
-            //  - is not expired (in sandbox)
-            //  - is not outdistanced
-            //  - if has certifications
-            //      max(count(certification)
-            //    else
-            //      max(membershipPendingExpiresIn) = must recent membership
-            res.identities = _.sortBy(res.identities, function(idty) {
-              var score = 0;
-              score += (10000000000 * ((data.uid && idty.uid === data.uid) ? 1 : 0));
-              score += (1000000000  * (idty.membershipExpiresIn > 0 ? 1 : 0));
-              score += (100000000   * (idty.membershipPendingExpiresIn > 0 ? 1 : 0));
-              score += (10000000    * (!idty.expired ? 1 : 0));
-              score += (1000000     * (!idty.outdistanced ? 1 : 0));
-              score += (100000      * (idty.wasMember ? 1 : 0));
-              var certCount = !idty.expired && idty.certifications ? idty.certifications.length : 0;
-              score += (1         * (certCount ? certCount : 0));
-              score += (1         * (!certCount && idty.membershipPendingExpiresIn > 0 ? idty.membershipPendingExpiresIn/1000 : 0));
-              return -score;
-            });
-            console.debug('Found {0} identities. Will selected the best one'.format(res.identities.length));
-          }
+          if (!data.requirements.uid) return;
 
-          // Select the first identity
-          var idty = res.identities[0];
-
-          // Compute useful fields
-          idty.needSelf = false;
-          idty.wasMember = angular.isDefined(idty.wasMember) ? idty.wasMember : false; // Compat with Duniter 0.9
-          idty.needMembership = (idty.membershipExpiresIn <= 0 && idty.membershipPendingExpiresIn <= 0 && !idty.wasMember);
-          idty.needRenew = (!idty.needMembership &&
-                            idty.membershipExpiresIn <= csSettings.data.timeWarningExpireMembership &&
-                            idty.membershipPendingExpiresIn <= 0) ||
-                           (idty.wasMember && idty.membershipExpiresIn === 0 &&
-                            idty.membershipPendingExpiresIn === 0);
-          idty.canMembershipOut = (idty.membershipExpiresIn > 0);
-          idty.pendingMembership = (idty.membershipExpiresIn <= 0 && idty.membershipPendingExpiresIn > 0);
-          idty.certificationCount = (idty.certifications) ? idty.certifications.length : 0;
-          idty.willExpireCertificationCount = idty.certifications ? idty.certifications.reduce(function(count, cert){
-            return count + (cert.expiresIn <= csSettings.data.timeWarningExpire ? 1 : 0);
-          }, 0) : 0;
-          idty.pendingRevocation = !idty.revoked && !!idty.revocation_sig;
-
-          data.requirements = idty;
-          data.uid = idty.uid;
-          data.blockUid = idty.meta.timestamp;
-          data.isMember = (idty.membershipExpiresIn > 0);
-
-          var blockParts = idty.meta.timestamp.split('-', 2);
+          // Get sigDate
+          var blockParts = data.requirements.blockUid.split('-', 2);
           var blockNumber = parseInt(blockParts[0]);
           var blockHash = blockParts[1];
           // Retrieve registration date
@@ -506,32 +449,17 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
                 addEvent({type: 'error', message: 'ERROR.WALLET_IDENTITY_EXPIRED', context: 'requirements'});
                 console.debug("Identity expired for uid={0}.".format(data.uid));
               }
-              resolve();
             })
             .catch(function(err){
               // Special case for currency init (root block not exists): use now
               if (err && err.ucode == BMA.errorCodes.BLOCK_NOT_FOUND && blockNumber === 0) {
                 data.sigDate = Math.trunc(new Date().getTime() / 1000);
-                resolve();
               }
               else {
-                reject(err);
+                throw err;
               }
             });
-        })
-        .catch(function(err) {
-          resetRequirements();
-          // If not a member: continue
-          if (!!err &&
-              (err.ucode == BMA.errorCodes.NO_MATCHING_MEMBER ||
-               err.ucode == BMA.errorCodes.NO_IDTY_MATCHING_PUB_OR_UID)) {
-            resolve();
-          }
-          else {
-            reject(err);
-          }
         });
-      });
     },
 
     loadTxAndSources = function(fromTime) {
@@ -546,15 +474,8 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
         });
     },
 
-    // Must be call after loadCurrency() and loadRequirements()
-    finishLoadRequirements = function(currency) {
-      currency = currency || csCurrency.data;
-      data.requirements.needCertificationCount = (!data.requirements.needMembership && (data.requirements.certificationCount < currency.parameters.sigQty)) ?
-          (currency.parameters.sigQty - data.requirements.certificationCount) : 0;
-      data.requirements.willNeedCertificationCount = (!data.requirements.needMembership &&
-          data.requirements.needCertificationCount === 0 && (data.requirements.certificationCount - data.requirements.willExpireCertificationCount) < currency.parameters.sigQty) ?
-          (currency.parameters.sigQty - data.requirements.certificationCount + data.requirements.willExpireCertificationCount) : 0;
-      data.requirements.pendingCertificationCount = 0 ; // init to 0, because not loaded here (see wot-service.js)
+    // Generate events from requirements
+    addEvents = function() {
 
       // Add user events
       if (data.requirements.revoked) {
@@ -567,6 +488,10 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
         if (data.requirements.pendingMembership) {
           addEvent({type:'pending', message: 'ACCOUNT.WAITING_MEMBERSHIP', context: 'requirements'});
         }
+        // If user has send a SELF, ask for membership - fix #625
+        else if (!data.requirements.needSelf && data.requirements.needMembership){
+          addEvent({type:'warn', message: 'ACCOUNT.NO_WAITING_MEMBERSHIP', context: 'requirements'});
+        }
         if (data.requirements.needCertificationCount > 0) {
           addEvent({type:'warn', message: 'ACCOUNT.WAITING_CERTIFICATIONS', messageParams: data.requirements, context: 'requirements'});
         }
@@ -609,7 +534,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
       var alertIfUnusedWallet = !csCurrency.data.initPhase && (!csSettings.data.wallet || csSettings.data.wallet.alertIfUnusedWallet) &&
         !data.loaded && (!options || !options.minData);
 
-      // Make to load once
+      // Make sure to load once at a time
       if (loadPromise) {
         return loadPromise.then(function() {
           return isDataLoaded(options) ? data : refreshData(options);
@@ -668,9 +593,6 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
 
       return $q.all([
 
-          // Get currency
-          csCurrency.get(),
-
           // Get requirements
           loadRequirements(),
 
@@ -680,9 +602,10 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
           // Load sigStock
           loadSigStock()
         ])
-        .then(function(res) {
-          var currency = res[0];
-          finishLoadRequirements(currency); // must be call after csCurrency.get() and loadRequirements()
+        .then(function() {
+
+          // Load wallet events
+          addEvents();
 
           // API extension
           return api.data.raisePromise.load(data)
@@ -731,19 +654,17 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
 
       var jobs = [];
 
-      // Reset events
-      cleanEventsByContext('requirements');
-
       // Get requirements
       if (options.requirements) {
-        jobs.push($q.all([
-            csCurrency.get(),
-            loadRequirements()
-          ])
-          .then(function(res) {
-            var currency = res[0];
-            finishLoadRequirements(currency);
-          }));
+        // Reset events
+        cleanEventsByContext('requirements');
+
+        jobs.push(
+          loadRequirements()
+
+            // Add wallet events
+            .then(addEvents)
+        );
       }
 
       if (options.sources || (options.tx && options.tx.enable)) {
@@ -764,6 +685,30 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
       });
     },
 
+    setSelf = function(uid, blockUid){
+      // Skip if same self
+      if (data.uid == uid && (!blockUid || data.blockUid == blockUid)) return $q.when();
+
+      // Data not loaded
+      if (!data.loaded) {
+        return !loadPromise ?
+          // If no pending load: ok
+          $q.when() :
+          // If a load is running: force a reload
+          loadPromise.then(function() {
+            return setSelf(uid, blockUid); // loop
+          });
+      }
+
+      data.uid = uid;
+      data.blockUid = blockUid;
+
+      // Refresh requirements
+      return refreshData({requirements: true, sigStock: true})
+        // Store (to remember the new uid)
+        .then(store);
+    },
+
     isBase = function(amount, base) {
       if (!base) return true; // no base
       if (amount < Math.pow(10, base)) return false; // too small
@@ -1270,9 +1215,9 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
               return loadRequirements();
             }, 1000); // waiting for node to process membership doc
           })
-          .then(function() {
-            finishLoadRequirements();
-          });
+
+          // Add wallet events
+          .then(addEvents);
       };
     },
 
@@ -1488,9 +1433,9 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
           }, 1000); // waiting for node to process membership doc
         })
 
-        .then(function() {
-          finishLoadRequirements();
-        })
+        // Add wallet events
+        .then(addEvents)
+
         .catch(function(err) {
           if (err && err.ucode == BMA.errorCodes.REVOCATION_ALREADY_REGISTERED) {
             // Already registered by node: just add an event
@@ -1505,19 +1450,18 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
 
     revokeWithFile = function(revocation){
       return $q.all([
-          csCurrency.get(),
           BMA.wot.revoke({revocation: revocation})
         ])
         // Reload requirements
         .then(function(res) {
-          var currency = res[0];
           if (isLogin()) {
             return $timeout(function () {
               return loadRequirements();
             }, 1000) // waiting for node to process membership doc
-            .then(function () {
-              finishLoadRequirements(currency);
-            })
+
+             // Add wallet events
+            .then(addEvents)
+
             .catch(function (err) {
               if (err && err.ucode == BMA.errorCodes.REVOCATION_ALREADY_REGISTERED) {
                 // Already registered by node: just add an event
@@ -1750,6 +1694,10 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
       isAuth: isAuth,
       getKeypair: getKeypair,
       hasSelf: hasSelf,
+      setSelf: setSelf,
+      isMember: function() {
+        return data.isMember;
+      },
       isDataLoaded : isDataLoaded,
       isNeverUsed: isNeverUsed,
       isNew: isNew,
diff --git a/www/js/services/wot-services.js b/www/js/services/wot-services.js
index 80bb313cc0281a29db3fd272be8c0cab14e673cf..eaf473c83121e9a140ee1b9a6aa7fdfc26358453 100644
--- a/www/js/services/wot-services.js
+++ b/www/js/services/wot-services.js
@@ -56,11 +56,85 @@ angular.module('cesium.wot.services', ['ngApi', 'cesium.bma.services', 'cesium.c
         return certifications;
       },
 
-      loadRequirements = function(pubkey, uid) {
-        if (!pubkey) return $q.when({});
-        // Get requirements
-        return BMA.wot.requirements({pubkey: pubkey})
+      _resetRequirements = function(data) {
+        data.requirements = {
+          needSelf: true,
+          needMembership: true,
+          canMembershipOut: false,
+          needRenew: false,
+          pendingMembership: false,
+          wasMember: false,
+          certificationCount: 0,
+          needCertifications: false,
+          needCertificationCount: 0,
+          willNeedCertificationCount: 0,
+          alternatives: undefined
+        };
+        data.blockUid = null;
+        data.isMember = false;
+        data.sigDate = null;
+      },
+
+      _fillRequirements = function(requirements, currencyParameters) {
+        // Add useful custom fields
+        requirements.hasSelf = true;
+        requirements.needSelf = false;
+        requirements.wasMember = angular.isDefined(requirements.wasMember) ? requirements.wasMember : false; // Compat with Duniter 0.9
+        requirements.needMembership = (requirements.membershipExpiresIn <= 0 && requirements.membershipPendingExpiresIn <= 0 && !requirements.wasMember);
+        requirements.needRenew = (!requirements.needMembership &&
+          requirements.membershipExpiresIn <= csSettings.data.timeWarningExpireMembership &&
+          requirements.membershipPendingExpiresIn <= 0) ||
+          (requirements.wasMember && requirements.membershipExpiresIn === 0 &&
+          requirements.membershipPendingExpiresIn === 0);
+        requirements.canMembershipOut = (requirements.membershipExpiresIn > 0);
+        requirements.pendingMembership = (requirements.membershipExpiresIn <= 0 && requirements.membershipPendingExpiresIn > 0);
+        requirements.isMember = (requirements.membershipExpiresIn > 0);
+        requirements.blockUid = requirements.meta.timestamp;
+        // Force certification count to 0, is not a member yet - fix #269
+        requirements.certificationCount = (requirements.isMember && requirements.certifications) ? requirements.certifications.length : 0;
+        requirements.willExpireCertificationCount = requirements.certifications ? requirements.certifications.reduce(function(count, cert){
+          return count + (cert.expiresIn <= csSettings.data.timeWarningExpire ? 1 : 0);
+        }, 0) : 0;
+        requirements.willExpire = requirements.willExpireCertificationCount > 0;
+        requirements.pendingRevocation = !requirements.revoked && !!requirements.revocation_sig;
+
+        // Fix pending certifications count - Fix #624
+        if (!requirements.isMember && !requirements.wasMember) {
+          var certifiers = _.union(
+            _.pluck(requirements.pendingCerts || [], 'from'),
+            _.pluck(requirements.certifications || [], 'from')
+          );
+          requirements.pendingCertificationCount = _.size(certifiers);
+        }
+        else {
+          requirements.pendingCertificationCount = angular.isDefined(requirements.pendingCerts) ? requirements.pendingCerts.length : 0 ;
+        }
+
+        // Compute
+        requirements.needCertificationCount = (!requirements.needSelf && (requirements.certificationCount < currencyParameters.sigQty)) ?
+          (currencyParameters.sigQty - requirements.certificationCount) : 0;
+        requirements.willNeedCertificationCount = (!requirements.needMembership && !requirements.needCertificationCount &&
+        (requirements.certificationCount - requirements.willExpireCertificationCount) < currencyParameters.sigQty) ?
+          (currencyParameters.sigQty - requirements.certificationCount + requirements.willExpireCertificationCount) : 0;
+
+
+        return requirements;
+      },
+
+      loadRequirements = function(data) {
+        if (!data || (!data.pubkey && !data.uid)) return $q.when(data);
+
+        return $q.all([
+          // Get currency
+          csCurrency.get(),
+          // Get requirements
+          BMA.wot.requirements({pubkey: data.pubkey||data.uid})
+        ])
           .then(function(res){
+            var currency = res[0];
+
+            res = res[1];
+
             if (!res.identities || !res.identities.length)  return;
 
             // Sort to select the best identity
@@ -77,60 +151,53 @@ angular.module('cesium.wot.services', ['ngApi', 'cesium.bma.services', 'cesium.c
               //      max(membershipPendingExpiresIn) = must recent membership
               res.identities = _.sortBy(res.identities, function(idty) {
                 var score = 0;
-                score += (10000000000 * ((uid && idty.uid === uid) ? 1 : 0));
+                score += (10000000000 * ((data.uid && idty.uid === data.uid) ? 1 : 0));
+                score += (10000000000 * ((data.blockUid && idty.meta && idty.meta.timestamp === data.blockUid) ? 1 : 0));
                 score += (1000000000  * (idty.membershipExpiresIn > 0 ? 1 : 0));
                 score += (100000000   * (idty.membershipPendingExpiresIn > 0 ? 1 : 0));
                 score += (10000000    * (!idty.expired ? 1 : 0));
                 score += (1000000     * (!idty.outdistanced ? 1 : 0));
+                score += (100000      * (idty.wasMember ? 1 : 0));
                 var certCount = !idty.expired && idty.certifications ? idty.certifications.length : 0;
                 score += (1         * (certCount ? certCount : 0));
                 score += (1         * (!certCount && idty.membershipPendingExpiresIn > 0 ? idty.membershipPendingExpiresIn/1000 : 0));
                 return -score;
               });
-              console.debug('Found {0} identities. Will selected the best one'.format(res.identities.length));
+              console.debug('[wot] Found {0} identities. Will selected the best one'.format(res.identities.length));
             }
-            var requirements = res.identities[0];
-            // Add useful custom fields
-            requirements.hasSelf = true;
-            requirements.needMembership = (requirements.membershipExpiresIn <= 0 &&
-                                           requirements.membershipPendingExpiresIn <= 0 );
-            requirements.needRenew = (!requirements.needMembership &&
-                                      requirements.membershipExpiresIn <= csSettings.data.timeWarningExpire &&
-                                      requirements.membershipPendingExpiresIn <= 0 );
-            requirements.canMembershipOut = (requirements.membershipExpiresIn > 0);
-            requirements.pendingMembership = (requirements.membershipExpiresIn <= 0 && requirements.membershipPendingExpiresIn > 0);
-            requirements.isMember = (requirements.membershipExpiresIn > 0);
-            // Force certification count to 0, is not a member yet - fix #269
-            requirements.certificationCount = (requirements.isMember && requirements.certifications) ? requirements.certifications.length : 0;
-            requirements.willExpireCertificationCount = requirements.certifications ? requirements.certifications.reduce(function(count, cert){
-              if (cert.expiresIn <= csSettings.data.timeWarningExpire) {
-                cert.willExpire = true;
-                return count + 1;
-              }
-              return count;
-            }, 0) : 0;
-            requirements.pendingRevocation = !requirements.revoked && !!requirements.revocation_sig;
 
-            return requirements;
+            // Select the first identity
+            var requirements = _fillRequirements(res.identities[0], currency.parameters);
+
+            data.requirements = requirements;
+            data.pubkey = requirements.pubkey;
+            data.uid = requirements.uid;
+            data.isMember =  requirements.isMember;
+            data.blockUid =  requirements.blockUid;
+
+            // Prepare alternatives identities if any
+            if (!requirements.isMember && !requirements.wasMember && res.identities.length > 1) {
+              requirements.alternatives = res.identities.splice(1);
+              _.forEach(requirements.alternatives, function(requirements) {
+                _fillRequirements(requirements, currency.parameters);
+              });
+            }
+
+            // TODO : get sigDate from blockUid ??
+
+            return data;
           })
           .catch(function(err) {
+            _resetRequirements(data);
             // If not a member: continue
             if (!!err &&
                 (err.ucode == BMA.errorCodes.NO_MATCHING_MEMBER ||
                  err.ucode == BMA.errorCodes.NO_IDTY_MATCHING_PUB_OR_UID)) {
-              return {
-                hasSelf: false,
-                needMembership: true,
-                canMembershipOut: false,
-                needRenew: false,
-                pendingMembership: false,
-                needCertifications: false,
-                needCertificationCount: 0,
-                willNeedCertificationCount: 0
-              };
+              return data;
             }
             throw err;
-          });
+          })
+          ;
       },
 
       loadIdentityByLookup = function(pubkey, uid) {
@@ -177,6 +244,7 @@ angular.module('cesium.wot.services', ['ngApi', 'cesium.bma.services', 'cesium.c
               return res.uids.reduce(function(certsMap, idty) {
                 var idtyFullKey = idty.uid + '-' + (idty.meta ? idty.meta.timestamp : '');
                 certsMap[idtyFullKey] = idty.others.reduce(function(certs, cert) {
+                  var certFullKey = idtyFullKey + '-' + cert.pubkey;
                   var result = {
                     pubkey: cert.pubkey,
                     uid: cert.uids[0],
@@ -187,12 +255,12 @@ angular.module('cesium.wot.services', ['ngApi', 'cesium.bma.services', 'cesium.c
                     isMember: cert.isMember,
                     wasMember: cert.wasMember,
                   };
-                  if (!certPubkeys[cert.pubkey]) {
-                    certPubkeys[cert.pubkey] = result;
+                  if (!certPubkeys[certFullKey]) {
+                    certPubkeys[certFullKey] = result;
                   }
                   else { // if duplicated cert: keep the most recent
-                    if (result.cert_time.block > certPubkeys[cert.pubkey].cert_time.block) {
-                      certPubkeys[cert.pubkey] = result;
+                    if (result.cert_time.block > certPubkeys[certFullKey].cert_time.block) {
+                      certPubkeys[certFullKey] = result;
                       certs.splice(_.findIndex(certs, {pubkey: cert.pubkey}), 1, result);
                       return certs;
                     }
@@ -451,18 +519,9 @@ angular.module('cesium.wot.services', ['ngApi', 'cesium.bma.services', 'cesium.c
           ;
       },
 
-      finishLoadRequirements = function(data) {
-        data.requirements.needCertificationCount = (!data.requirements.needMembership && (data.requirements.certificationCount < data.sigQty)) ?
-          (data.sigQty - data.requirements.certificationCount) : 0;
-        data.requirements.willNeedCertificationCount = (!data.requirements.needMembership && !data.requirements.needCertificationCount &&
-          (data.requirements.certificationCount - data.requirements.willExpireCertificationCount) < data.sigQty) ?
-          (data.sigQty - data.requirements.certificationCount + data.requirements.willExpireCertificationCount) : 0;
-        data.requirements.pendingCertificationCount = data.received_cert_pending ? data.received_cert_pending.length : 0;
+      // Add events on given account
+      addEvents = function(data) {
 
-        // Use /wot/lookup.revoked when requirements not filled
-        data.requirements.revoked = angular.isDefined(data.requirements.revoked) ? data.requirements.revoked : data.revoked;
-
-        // Add events
         if (data.requirements.revoked) {
           delete data.hasBadSelfBlock;
           addEvent(data, {type: 'error', message: 'ERROR.IDENTITY_REVOKED', messageParams: {revocationTime: data.revocationTime}});
@@ -487,6 +546,10 @@ angular.module('cesium.wot.services', ['ngApi', 'cesium.bma.services', 'cesium.c
           addEvent(data, {type: 'error', message: 'INFO.IDENTITY_WILL_MISSING_CERTIFICATIONS', messageParams: data.requirements});
           console.debug("[wot] Identity {0} will need {1} certification(s)".format(data.uid, data.requirements.willNeedCertificationCount));
         }
+        else if (!data.requirements.needSelf && data.requirements.needMembership) {
+          addEvent(data, {type: 'error', message: 'INFO.IDENTITY_NEED_MEMBERSHIP'});
+          console.debug("[wot] Identity {0} has a self but no membership".format(data.uid));
+        }
       },
 
       loadData = function(pubkey, withCache, uid, force) {
@@ -510,11 +573,16 @@ angular.module('cesium.wot.services', ['ngApi', 'cesium.bma.services', 'cesium.c
             return $q.when(data);
           }
           console.debug("[wot] Loading identity " + pubkey.substring(0, 8) + "...");
-          data = {pubkey: pubkey};
+          data = {
+            pubkey: pubkey,
+            uid: uid
+          };
         }
         else {
           console.debug("[wot] Loading identity from uid " + uid);
-          data = {};
+          data = {
+            uid: uid
+          };
         }
 
         var now = new Date().getTime();
@@ -527,8 +595,7 @@ angular.module('cesium.wot.services', ['ngApi', 'cesium.bma.services', 'cesium.c
             BMA.blockchain.parameters()
               .then(function(res) {
                 parameters = res;
-                data.sigQty =  parameters.sigQty;
-                data.sigStock =  parameters.sigStock;
+
               }),
             // Get current time
             BMA.blockchain.current()
@@ -546,11 +613,7 @@ angular.module('cesium.wot.services', ['ngApi', 'cesium.bma.services', 'cesium.c
               }),
 
             // Get requirements
-            loadRequirements(pubkey, uid)
-              .then(function (requirements) {
-                data.requirements = requirements;
-                data.isMember = requirements.isMember;
-              }),
+            loadRequirements(data),
 
             // Get identity using lookup
             loadIdentityByLookup(pubkey, uid)
@@ -582,8 +645,14 @@ angular.module('cesium.wot.services', ['ngApi', 'cesium.bma.services', 'cesium.c
             ]);
           })
           .then(function() {
+
             // Add compute some additional requirements (that required all data like certifications)
-            finishLoadRequirements(data);
+            data.requirements.pendingCertificationCount = data.received_cert_pending ? data.received_cert_pending.length : data.requirements.pendingCertificationCount;
+            // Use /wot/lookup.revoked when requirements not filled
+            data.requirements.revoked = angular.isDefined(data.requirements.revoked) ? data.requirements.revoked : data.revoked;
+
+            // Add account events
+            addEvents(data);
 
             // API extension
             return api.data.raisePromise.load(data)
@@ -1005,6 +1074,7 @@ angular.module('cesium.wot.services', ['ngApi', 'cesium.bma.services', 'cesium.c
     return {
       id: id,
       load: loadData,
+      loadRequirements: loadRequirements,
       search: search,
       newcomers: getNewcomers,
       pending: getPending,
diff --git a/www/templates/wallet/popover_actions.html b/www/templates/wallet/popover_actions.html
index 108cf1b0b5bb909228325188b9f72fdf94f86bdc..8a5678635752f6665540e2fd728401b6322f5d0c 100644
--- a/www/templates/wallet/popover_actions.html
+++ b/www/templates/wallet/popover_actions.html
@@ -11,6 +11,16 @@
         {{'COMMON.BTN_SHARE' | translate}}
       </a>
 
+
+      <!-- alternatives identities -->
+      <a class="item item-icon-left ink"
+         ng-if="walletData.requirements.alternatives"
+         ng-click="showSelectIdentitiesModal()">
+        <i class="icon ion-person"></i>
+        <b class="icon-secondary ion-loop" style="margin-top: 4px; left: 15px;"></b>
+        {{'ACCOUNT.BTN_SELECT_ALTERNATIVES_IDENTITIES' | translate}}
+      </a>
+
       <!-- identity -->
       <a class="item item-icon-left ink"
          ng-if="walletData.requirements.needSelf"
diff --git a/www/templates/wallet/view_wallet.html b/www/templates/wallet/view_wallet.html
index dbcc318b4108926b921033fe36ac1a20cff0574a..43522adbb77c245bb3dd1791b12950dfe9ca09e6 100644
--- a/www/templates/wallet/view_wallet.html
+++ b/www/templates/wallet/view_wallet.html
@@ -124,13 +124,13 @@
           <!-- Certifications -->
           <a id="helptip-wallet-certifications"
              class="item item-icon-left item-icon-right item-text-wrap ink"
-             ng-if="formData.isMember||formData.requirements.pendingMembership"
+             ng-if="formData.isMember||formData.requirements.pendingMembership||!formData.requirements.needSelf"
              ng-click="showCertifications()">
             <i class="icon ion-ribbon-b"></i>
             <b ng-if="formData.requirements.isSentry" class="ion-star icon-secondary" style="color: yellow; font-size: 16px; left: 25px; top: -7px;"></b>
             {{:locale:'ACCOUNT.CERTIFICATION_COUNT'|translate}}
             <cs-badge-certification requirements="formData.requirements"
-                                    parameters="{sigQty: formData.parameters.sigQty}">
+                                    parameters="::currency.parameters">
             </cs-badge-certification>
             <i class="gray icon ion-ios-arrow-right"></i>
           </a>
diff --git a/www/templates/wot/items_given_certifications.html b/www/templates/wot/items_given_certifications.html
index b009bd55b1a12726173df42631b0160e468c2028..68d37d34a399af15bd2b39ec5418f603905420c1 100644
--- a/www/templates/wot/items_given_certifications.html
+++ b/www/templates/wot/items_given_certifications.html
@@ -11,7 +11,7 @@
     <span translate>WOT.GIVEN_CERTIFICATIONS.SENT</span>
 
     <cs-badge-given-certification identity="formData"
-                                  parameters="{sigStock: formData.sigStock}">
+                                  parameters="$root.currency.parameters">
     </cs-badge-given-certification>
   </div>
 
diff --git a/www/templates/wot/items_received_certifications.html b/www/templates/wot/items_received_certifications.html
index 2bcbc83a615cfac6b5196ec112a45b9f31ba2f86..b09d4864e3efd6f75614a508afc7b28af441fc4b 100644
--- a/www/templates/wot/items_received_certifications.html
+++ b/www/templates/wot/items_received_certifications.html
@@ -15,7 +15,7 @@
 
             <cs-badge-certification cs-id="helptip-wot-view-certifications-count"
                                     requirements="formData.requirements"
-                                    parameters="{sigQty: formData.sigQty}">
+                                    parameters="$root.currency.parameters">
             </cs-badge-certification>
           </div>
 
diff --git a/www/templates/wot/modal_select_pubkey_identity.html b/www/templates/wot/modal_select_pubkey_identity.html
new file mode 100644
index 0000000000000000000000000000000000000000..9c7cbfb8396d1d9320e14f1b1e61319d3c89a088
--- /dev/null
+++ b/www/templates/wot/modal_select_pubkey_identity.html
@@ -0,0 +1,48 @@
+<ion-modal-view id="transfer" class="modal-full-height modal-transfer">
+  <ion-header-bar class="bar-positive">
+    <button class="button button-clear" ng-click="closeModal()" translate>COMMON.BTN_CANCEL</button>
+    <h1 class="title" translate>ACCOUNT.SELECT_IDENTITY_MODAL.TITLE</h1>
+  </ion-header-bar>
+
+  <ion-content scroll="true">
+
+    <div class="padding">
+      <p trust-as-html="'ACCOUNT.SELECT_IDENTITY_MODAL.HELP'|translate:{pubkey: pubkey}"></p>
+    </div>
+
+    <ion-list>
+      <ion-item
+        class="item-avatar item-icon-right"
+        ng-repeat="item in identities"
+        ng-click="closeModal(item)">
+
+        <i class="item-image icon ion-person"></i>
+
+        <h2>{{item.uid}}</h2>
+
+        <h4 class="gray">
+          <b class="ion-key"></b>
+          {{::item.pubkey | formatPubkey}}
+          <span ng-if="::!item.revoked && !item.pendingRevocation && !item.isMember" class="assertive" translate>WOT.NOT_MEMBER_PARENTHESIS</span>
+          <span ng-if="::item.revoked || item.pendingRevocation" class="assertive bold" translate>WOT.IDENTITY_REVOKED_PARENTHESIS</span>
+        </h4>
+
+        <ng-if ng-if="::!item.revoked && !item.pendingRevocation && (item.certificationCount || item.pendingCertificationCount)">
+
+          <!-- certification count -->
+          <cs-badge-certification requirements="item"
+                                  parameters="$root.currency.parameters"></cs-badge-certification>
+
+          <!-- certification label -->
+          <div class="gray badge badge-secondary" >
+            <span translate>ACCOUNT.CERTIFICATION_COUNT</span>
+          </div>
+        </ng-if>
+
+        <i class="icon ion-ios-arrow-right "></i>
+      </ion-item>
+    </ion-list>
+
+  </ion-content>
+
+</ion-modal-view>