diff --git a/www/js/services/currency-services.js b/www/js/services/currency-services.js
index 828754ca38c7e8b18c9a4ce2ff1f8927d690fc49..a65054d00054a83f2e69969b345bb2c1fb415887 100644
--- a/www/js/services/currency-services.js
+++ b/www/js/services/currency-services.js
@@ -4,358 +4,345 @@ angular.module('cesium.currency.services', ['ngApi', 'cesium.bma.services'])
 .factory('csCurrency', function($rootScope, $q, $timeout, BMA, Api, csSettings) {
   'ngInject';
 
-  var defaultBMA = BMA;
+  var
+    constants = {
+      // Avoid to many call on well known currencies
+      WELL_KNOWN_CURRENCIES: {
+        g1: {
+          firstBlockTime: 1488987127,
+          medianTimeOffset: 3600
+        }
+      }
+    },
 
-  function CsCurrency(id, BMA) {
+    data = {},
+    started = false,
+    startPromise,
+    listeners,
+    api = new Api(this, "csCurrency");
 
-    BMA = BMA || defaultBMA;
+  function powBase(amount, base) {
+    return base <= 0 ? amount : amount * Math.pow(10, base);
+  }
 
-    var
-      constants = {
-        // Avoid to many call on well known currencies
-        WELL_KNOWN_CURRENCIES: {
-          g1: {
-            firstBlockTime: 1488987127,
-            medianTimeOffset: 3600
-          }
-        }
-      },
+  function resetData() {
+    data.name = null;
+    data.parameters = null;
+    data.firstBlockTime = null;
+    data.membersCount = null;
+    data.cache = {};
+    data.node = BMA;
+    data.currentUD = null;
+    data.medianTimeOffset = 0;
+    started = false;
+    startPromise = undefined;
+    api.data.raise.reset(data);
+  }
 
-      data = {},
-      started = false,
-      startPromise,
-      listeners,
-      api = new Api(this, "csCurrency-" + id);
+  function loadData() {
 
-    function powBase(amount, base) {
-      return base <= 0 ? amount : amount * Math.pow(10, base);
-    }
+    // Load currency from default node
+    return $q.all([
 
-    function resetData() {
-      data.name = null;
-      data.parameters = null;
-      data.firstBlockTime = null;
-      data.membersCount = null;
-      data.cache = {};
-      data.node = BMA;
-      data.currentUD = null;
-      data.medianTimeOffset = 0;
-      started = false;
-      startPromise = undefined;
-      api.data.raise.reset(data);
-    }
+      // get parameters
+      loadParameters()
+        .then(function(parameters) {
+          // load first block info
+          return loadFirstBlock(parameters.currency);
+        }),
 
-    function loadData() {
+      // get current UD
+      loadCurrentUD(),
 
-      // Load currency from default node
-      return $q.all([
+      // call extensions
+      api.data.raisePromise.load(data)
+    ])
+    .catch(function(err) {
+      resetData();
+      throw err;
+    });
+  }
 
-        // get parameters
-        loadParameters()
-          .then(function(parameters) {
-            // load first block info
-            return loadFirstBlock(parameters.currency);
-          }),
+  function loadParameters() {
+    return BMA.blockchain.parameters()
+      .then(function(res){
+        data.name = res.currency;
+        data.parameters = res;
+        data.medianTimeOffset = res.avgGenTime * res.medianTimeBlocks / 2;
+        return res;
+      });
+  }
 
-        // get current UD
-        loadCurrentUD(),
+  function loadFirstBlock(currencyName) {
+    // Well known currencies
+    if (constants.WELL_KNOWN_CURRENCIES[currencyName]){
+      angular.merge(data, constants.WELL_KNOWN_CURRENCIES[currencyName]);
+      return $q.when();
+    }
 
-        // call extensions
-        api.data.raisePromise.load(data)
-      ])
+    return BMA.blockchain.block({block:0})
+      .then(function(json) {
+        // Need by graph plugin
+        data.firstBlockTime = json.medianTime;
+      })
       .catch(function(err) {
-        resetData();
+        // Special case, when currency not started yet
+        if (err && err.ucode === BMA.errorCodes.BLOCK_NOT_FOUND) {
+          data.firstBlockTime = 0;
+          data.initPhase = true;
+          console.warn('[currency] Blockchain not launched: Enable init phase mode');
+          return;
+        }
         throw err;
       });
-    }
-
-    function loadParameters() {
-      return BMA.blockchain.parameters()
-        .then(function(res){
-          data.name = res.currency;
-          data.parameters = res;
-          data.medianTimeOffset = res.avgGenTime * res.medianTimeBlocks / 2;
-          return res;
-        });
-    }
+  }
 
-    function loadFirstBlock(currencyName) {
-      // Well known currencies
-      if (constants.WELL_KNOWN_CURRENCIES[currencyName]){
-        angular.merge(data, constants.WELL_KNOWN_CURRENCIES[currencyName]);
-        return $q.when();
-      }
+  function loadCurrentUD() {
+    return BMA.blockchain.stats.ud()
+      .then(function(res) {
+        // Special case for currency init
+        if (!res.result.blocks.length) {
+          data.currentUD = data.parameters ? data.parameters.ud0 : -1;
+          return data.currentUD ;
+        }
+        return _safeLoadCurrentUD(res, res.result.blocks.length - 1);
+      })
+      .catch(function(err) {
+        data.currentUD = null;
+        throw err;
+      });
+  }
 
-      return BMA.blockchain.block({block:0})
-        .then(function(json) {
-          // Need by graph plugin
-          data.firstBlockTime = json.medianTime;
-        })
-        .catch(function(err) {
-          // Special case, when currency not started yet
-          if (err && err.ucode === BMA.errorCodes.BLOCK_NOT_FOUND) {
-            data.firstBlockTime = 0;
-            data.initPhase = true;
-            console.warn('[currency] Blockchain not launched: Enable init phase mode');
-            return;
-          }
-          throw err;
-        });
+  /**
+   * Load the last UD, with a workaround if last block with UD is not found in the node
+   * @param res
+   * @param blockIndex
+   * @returns {*}
+   * @private
+   */
+  function _safeLoadCurrentUD(res, blockIndex) {
+    // Special case for currency init
+    if (!res.result.blocks.length || blockIndex < 0) {
+      data.currentUD = data.parameters ? data.parameters.ud0 : -1;
+      return data.currentUD ;
     }
-
-    function loadCurrentUD() {
-      return BMA.blockchain.stats.ud()
-        .then(function(res) {
-          // Special case for currency init
-          if (!res.result.blocks.length) {
-            data.currentUD = data.parameters ? data.parameters.ud0 : -1;
-            return data.currentUD ;
-          }
-          return _safeLoadCurrentUD(res, res.result.blocks.length - 1);
+    else {
+      var lastBlockWithUD = res.result.blocks[blockIndex];
+      return BMA.blockchain.block({ block: lastBlockWithUD })
+        .then(function(block){
+          data.currentUD = powBase(block.dividend, block.unitbase);
+          return data.currentUD;
         })
         .catch(function(err) {
+          console.error("[currency] Unable to load last block with UD, with number {0}".format(lastBlockWithUD));
+          if (blockIndex > 0) {
+            console.error("[currency] Retrying to load UD from a previous block...");
+            return _safeLoadCurrentUD(res, blockIndex-1);
+          }
           data.currentUD = null;
           throw err;
         });
     }
+  }
 
-    /**
-     * Load the last UD, with a workaround if last block with UD is not found in the node
-     * @param res
-     * @param blockIndex
-     * @returns {*}
-     * @private
-     */
-    function _safeLoadCurrentUD(res, blockIndex) {
-      // Special case for currency init
-      if (!res.result.blocks.length || blockIndex < 0) {
-        data.currentUD = data.parameters ? data.parameters.ud0 : -1;
-        return data.currentUD ;
-      }
-      else {
-        var lastBlockWithUD = res.result.blocks[blockIndex];
-        return BMA.blockchain.block({ block: lastBlockWithUD })
-          .then(function(block){
-            data.currentUD = powBase(block.dividend, block.unitbase);
-            return data.currentUD;
-          })
-          .catch(function(err) {
-            console.error("[currency] Unable to load last block with UD, with number {0}".format(lastBlockWithUD));
-            if (blockIndex > 0) {
-              console.error("[currency] Retrying to load UD from a previous block...");
-              return _safeLoadCurrentUD(res, blockIndex-1);
-            }
-            data.currentUD = null;
-            throw err;
-          });
-      }
+  function getData() {
+
+    if (started) { // load only once
+      return $q.when(data);
     }
 
-    function getData() {
+    // Previous load not finished: return the existing promise - fix #452
+    return startPromise || start();
+  }
 
+  function getDataField(field) {
+    return function() {
       if (started) { // load only once
-        return $q.when(data);
+        return $q.when(data[field]);
       }
 
       // Previous load not finished: return the existing promise - fix #452
-      return startPromise || start();
-    }
-
-    function getDataField(field) {
-      return function() {
-        if (started) { // load only once
-          return $q.when(data[field]);
-        }
-
-        // Previous load not finished: return the existing promise - fix #452
-        return startPromise || start() // load only once
-            .then(function(){
-              return data[field];
-            });
-      };
-    }
-
-    function onBlock(json) {
-      var block = new Block(json);
-      block.cleanData(); // Remove unused content (arrays...) and keep items count
+      return startPromise || start() // load only once
+          .then(function(){
+            return data[field];
+          });
+    };
+  }
 
-      //console.debug('[currency] Received new block', block);
-      console.debug('[currency] Received new block {' + block.number + '-' + block.hash + '}');
+  function onBlock(json) {
+    var block = new Block(json);
+    block.cleanData(); // Remove unused content (arrays...) and keep items count
 
-      data.currentBlock = block;
-      data.currentBlock.receivedAt = moment().utc().unix();
+    //console.debug('[currency] Received new block', block);
+    console.debug('[currency] Received new block {' + block.number + '-' + block.hash + '}');
 
-      data.medianTime = block.medianTime;
-      data.membersCount = block.membersCount;
+    data.currentBlock = block;
+    data.currentBlock.receivedAt = moment().utc().unix();
 
-      // Update UD
-      if (block.dividend) {
-        data.currentUD = block.dividend;
-      }
+    data.medianTime = block.medianTime;
+    data.membersCount = block.membersCount;
 
-      // Dispatch to extensions
-      api.data.raise.newBlock(block);
+    // Update UD
+    if (block.dividend) {
+      data.currentUD = block.dividend;
     }
 
-    function addListeners() {
-      listeners = [
-        // Listen if node changed
-        BMA.api.node.on.restart($rootScope, restart, this),
-        // open web socket on block
-        BMA.websocket.block().onListener(onBlock)
-      ];
-    }
+    // Dispatch to extensions
+    api.data.raise.newBlock(block);
+  }
 
-    function removeListeners() {
-      _.forEach(listeners, function(remove){
-        remove();
-      });
-      listeners = [];
-    }
+  function addListeners() {
+    listeners = [
+      // Listen if node changed
+      BMA.api.node.on.restart($rootScope, restart, this),
+      // open web socket on block
+      BMA.websocket.block().onListener(onBlock)
+    ];
+  }
 
-    function ready() {
-      if (started) return $q.when(data);
-      return startPromise || start();
-    }
+  function removeListeners() {
+    _.forEach(listeners, function(remove){
+      remove();
+    });
+    listeners = [];
+  }
 
-    function stop() {
-      console.debug('[currency] Stopping...');
-      removeListeners();
-      resetData();
-    }
+  function ready() {
+    if (started) return $q.when(data);
+    return startPromise || start();
+  }
 
-    function restart() {
-      stop();
-      return $timeout(start, 200);
-    }
+  function stop() {
+    console.debug('[currency] Stopping...');
+    removeListeners();
+    resetData();
+  }
 
-    function start() {
-      console.debug('[currency] Starting...');
-      var now = Date.now();
+  function restart() {
+    stop();
+    return $timeout(start, 200);
+  }
 
-      startPromise = BMA.ready()
+  function start() {
+    console.debug('[currency] Starting...');
+    var now = Date.now();
 
-        // Load data
-        .then(loadData)
+    startPromise = BMA.ready()
 
-        // Emit ready event
-        .then(function() {
-          addListeners();
+      // Load data
+      .then(loadData)
 
-          console.debug('[currency] Started in ' + (Date.now() - now) + 'ms');
+      // Emit ready event
+      .then(function() {
+        addListeners();
 
-          started = true;
-          startPromise = null;
+        console.debug('[currency] Started in ' + (Date.now() - now) + 'ms');
 
-          // Emit event (used by plugins)
-          api.data.raise.ready(data);
-        })
-        .then(function(){
-          return data;
-        });
+        started = true;
+        startPromise = null;
 
-      return startPromise;
-    }
+        // Emit event (used by plugins)
+        api.data.raise.ready(data);
+      })
+      .then(function(){
+        return data;
+      });
 
-    var currentBlockField = getDataField('currentBlock');
+    return startPromise;
+  }
 
-    function getCurrent(cache) {
-      // Get field (and make sure service is started)
-      return currentBlockField()
+  var currentBlockField = getDataField('currentBlock');
 
-        .then(function(currentBlock) {
+  function getCurrent(cache) {
+    // Get field (and make sure service is started)
+    return currentBlockField()
 
-          var now = moment().utc().unix();
+      .then(function(currentBlock) {
 
-          if (cache) {
-            if (currentBlock && currentBlock.receivedAt && (now - currentBlock.receivedAt) < 60/*1min*/) {
-              //console.debug('[currency] Use current block #'+ currentBlock.number +' from cache (age='+ (now - currentBlock.receivedAt) + 's)');
-              return currentBlock;
-            }
+        var now = moment().utc().unix();
 
-            if (!currentBlock) {
-              // Should never occur, if websocket /ws/block works !
-              console.warn('[currency] No current block in cache: get it from network. Websocket [/ws/block] may not be started ?');
-            }
+        if (cache) {
+          if (currentBlock && currentBlock.receivedAt && (now - currentBlock.receivedAt) < 60/*1min*/) {
+            //console.debug('[currency] Use current block #'+ currentBlock.number +' from cache (age='+ (now - currentBlock.receivedAt) + 's)');
+            return currentBlock;
           }
 
-          return BMA.blockchain.current(false)
-            .catch(function(err){
-              // Special case for currency init (root block not exists): use fixed values
-              if (err && err.ucode == BMA.errorCodes.NO_CURRENT_BLOCK) {
-                return {number: 0, hash: BMA.constants.ROOT_BLOCK_HASH, medianTime: now};
-              }
-              throw err;
-            })
-            .then(function(current) {
-              data.currentBlock = current;
-              data.currentBlock.receivedAt = now;
-              return current;
-            });
-        });
-    }
-
-    function getLastValidBlock() {
-      if (csSettings.data.blockValidityWindow <= 0) {
-        return getCurrent(true);
-      }
+          if (!currentBlock) {
+            // Should never occur, if websocket /ws/block works !
+            console.warn('[currency] No current block in cache: get it from network. Websocket [/ws/block] may not be started ?');
+          }
+        }
 
-      return getCurrent(true)
-        .then(function(current) {
-          var number = current.number - csSettings.data.blockValidityWindow;
-          return (number > 0) ? BMA.blockchain.block({block: number}) : current;
-        });
-    }
+        return BMA.blockchain.current(false)
+          .catch(function(err){
+            // Special case for currency init (root block not exists): use fixed values
+            if (err && err.ucode == BMA.errorCodes.NO_CURRENT_BLOCK) {
+              return {number: 0, hash: BMA.constants.ROOT_BLOCK_HASH, medianTime: now};
+            }
+            throw err;
+          })
+          .then(function(current) {
+            data.currentBlock = current;
+            data.currentBlock.receivedAt = now;
+            return current;
+          });
+      });
+  }
 
-    // Get time in second (UTC - medianTimeOffset)
-    function getDateNow() {
-      return moment().utc().unix() - (data.medianTimeOffset || constants.WELL_KNOWN_CURRENCIES.g1.medianTimeOffset);
+  function getLastValidBlock() {
+    if (csSettings.data.blockValidityWindow <= 0) {
+      return getCurrent(true);
     }
 
-    // TODO register new block event, to get new UD value
-
-    // Register extension points
-    api.registerEvent('data', 'ready');
-    api.registerEvent('data', 'load');
-    api.registerEvent('data', 'reset');
-    api.registerEvent('data', 'newBlock');
-
-    // init data
-    resetData();
+    return getCurrent(true)
+      .then(function(current) {
+        var number = current.number - csSettings.data.blockValidityWindow;
+        return (number > 0) ? BMA.blockchain.block({block: number}) : current;
+      });
+  }
 
-    // Default action
-    //start();
-
-    return {
-      ready: ready,
-      start: start,
-      stop: stop,
-      data: data,
-      get: getData,
-      name: getDataField('name'),
-      parameters: getDataField('parameters'),
-      currentUD: getDataField('currentUD'),
-      medianTimeOffset: getDataField('medianTimeOffset'),
-      blockchain: {
-        current: getCurrent,
-        lastValid: getLastValidBlock
-      },
-      date: {
-        now: getDateNow
-      },
-      // api extension
-      api: api,
-      // deprecated methods
-      default: function() {
-        console.warn('[currency] \'csCurrency.default()\' has been DEPRECATED - Please use \'csCurrency.get()\' instead.');
-        return getData();
-      }
-    };
+  // Get time in second (UTC - medianTimeOffset)
+  function getDateNow() {
+    return moment().utc().unix() - (data.medianTimeOffset || constants.WELL_KNOWN_CURRENCIES.g1.medianTimeOffset);
   }
 
-  var service = new CsCurrency('default');
-  service.instance = function(id, bma) {
-    return new CsCurrency(id, bma);
+  // TODO register new block event, to get new UD value
+
+  // Register extension points
+  api.registerEvent('data', 'ready');
+  api.registerEvent('data', 'load');
+  api.registerEvent('data', 'reset');
+  api.registerEvent('data', 'newBlock');
+
+  // init data
+  resetData();
+
+  // Default action
+  //start();
+
+  return {
+    ready: ready,
+    start: start,
+    stop: stop,
+    data: data,
+    get: getData,
+    name: getDataField('name'),
+    parameters: getDataField('parameters'),
+    currentUD: getDataField('currentUD'),
+    medianTimeOffset: getDataField('medianTimeOffset'),
+    blockchain: {
+      current: getCurrent,
+      lastValid: getLastValidBlock
+    },
+    date: {
+      now: getDateNow
+    },
+    // api extension
+    api: api,
+    // deprecated methods
+    default: function() {
+      console.warn('[currency] \'csCurrency.default()\' has been DEPRECATED - Please use \'csCurrency.get()\' instead.');
+      return getData();
+    }
   };
-  return service;
 });
diff --git a/www/js/services/device-services.js b/www/js/services/device-services.js
index cdb1df2078ec8cb56580c78c93c8a78bf4170bf7..4788424358174a9d8f991fb94b4aadc363e16926 100644
--- a/www/js/services/device-services.js
+++ b/www/js/services/device-services.js
@@ -2,8 +2,7 @@ var App;
 
 angular.module('cesium.device.services', ['cesium.utils.services', 'cesium.settings.services'])
 
-  .factory('Device',
-    function($rootScope, $translate, $ionicPopup, $q,
+  .factory('Device', function($rootScope, $translate, $ionicPopup, $q,
       // removeIf(no-device)
       $cordovaClipboard, $cordovaBarcodeScanner, $cordovaCamera,
       // endRemoveIf(no-device)
diff --git a/www/js/services/network-services.js b/www/js/services/network-services.js
index 037345ccfedab352211e1bc857c089111941e87b..7cdee80e5aa80009b025bf4226e32d5627730068 100644
--- a/www/js/services/network-services.js
+++ b/www/js/services/network-services.js
@@ -4,855 +4,843 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services',
 .factory('csNetwork', function($rootScope, $q, $interval, $timeout, $window, csConfig, BMA, csHttp, csCurrency, Api) {
   'ngInject';
 
-  function CsNetwork(id) {
-
-    var
-      interval,
-      constants = {
-        UNKNOWN_BUID: -1,
-        MAX_BLOCK_OFFSET: 1000
-      },
-      isHttpsMode = $window.location.protocol === 'https:',
-      api = new Api(this, "csNetwork-" + id),
-
-      data = {
-        bma: null,
-        listeners: [],
-        loading: true,
-        peers: [],
-        filter: {
-          member: true,
-          mirror: true,
-          endpoint: null,
-          online: false,
-          bma: false,
-          ssl: undefined,
-          tor: undefined
-        },
-        sort:{
-          type: null,
-          asc: true,
-          compact: true
-        },
-        groupBy: 'pubkey',
-        expertMode: false,
-        knownBlocks: [],
-        mainBlock: null,
-        minOnlineBlockNumber: 0,
-        uidsByPubkeys: null,
-        searchingPeersOnNetwork: false,
-        difficulties: null,
-        ws2pHeads: null,
-        timeout: csConfig.timeout
-      },
-
-      // Return the block uid
-      buid = function(block) {
-        return block && [block.number, block.hash].join('-');
+   var
+    interval,
+    constants = {
+      UNKNOWN_BUID: -1,
+      MAX_BLOCK_OFFSET: 1000
+    },
+    isHttpsMode = $window.location.protocol === 'https:',
+    api = new Api(this, "csNetwork"),
+
+    data = {
+      bma: null,
+      listeners: [],
+      loading: true,
+      peers: [],
+      filter: {
+        member: true,
+        mirror: true,
+        endpoint: null,
+        online: false,
+        bma: false,
+        ssl: undefined,
+        tor: undefined
       },
-
-      resetData = function() {
-        data.bma = null;
-        data.listeners = [];
-        data.peers.splice(0);
-        data.filter = {
-          member: true,
-          mirror: true,
-          endpoint: null,
-          online: true,
-          bma: false,
-          ssl: undefined,
-          tor: undefined
-        };
-        data.sort = {
-          type: null,
-          asc: true
-        };
-        data.groupBy = 'pubkey';
-        data.expertMode = false;
-        data.memberPeersCount = 0;
-        data.knownBlocks = [];
-        data.mainBlock = null;
-        data.minOnlineBlockNumber = 0;
-        data.uidsByPubkeys = {};
-        data.loading = true;
-        data.searchingPeersOnNetwork = false;
-        data.difficulties = null;
-        data.ws2pHeads = null;
-        data.timeout = csConfig.timeout;
-      },
-
-      hasPeers = function() {
-        return data.peers && data.peers.length > 0;
+      sort:{
+        type: null,
+        asc: true,
+        compact: true
       },
-
-      getPeers = function() {
-        return data.peers;
-      },
-
-      isBusy = function() {
-        return data.loading;
-      },
-
-      getKnownBlocks = function() {
-        return data.knownBlocks;
-      },
-
-      // Load WS2P heads
-      loadW2spHeads = function() {
-        return data.bma.network.ws2p.heads()
-          .then(function (res) {
-            data.ws2pHeads = res.heads ? res.heads.reduce(function (res, hit) {
-              if (hit.message && hit.sig) {
-                try {
-                  var head = new Ws2pMessage(hit.message);
-                  res[[head.pubkey, head.ws2pid].join('-')] = head;
-                }
-                catch(err) {
-                  // just log, then ignore
-                  console.error('[network] Ignoring WS2P head.', err && err.message || err);
-                }
+      groupBy: 'pubkey',
+      expertMode: false,
+      knownBlocks: [],
+      mainBlock: null,
+      minOnlineBlockNumber: 0,
+      uidsByPubkeys: null,
+      searchingPeersOnNetwork: false,
+      difficulties: null,
+      ws2pHeads: null,
+      timeout: csConfig.timeout
+    },
+
+    // Return the block uid
+    buid = function(block) {
+      return block && [block.number, block.hash].join('-');
+    },
+
+    resetData = function() {
+      data.bma = null;
+      data.listeners = [];
+      data.peers.splice(0);
+      data.filter = {
+        member: true,
+        mirror: true,
+        endpoint: null,
+        online: true,
+        bma: false,
+        ssl: undefined,
+        tor: undefined
+      };
+      data.sort = {
+        type: null,
+        asc: true
+      };
+      data.groupBy = 'pubkey';
+      data.expertMode = false;
+      data.memberPeersCount = 0;
+      data.knownBlocks = [];
+      data.mainBlock = null;
+      data.minOnlineBlockNumber = 0;
+      data.uidsByPubkeys = {};
+      data.loading = true;
+      data.searchingPeersOnNetwork = false;
+      data.difficulties = null;
+      data.ws2pHeads = null;
+      data.timeout = csConfig.timeout;
+    },
+
+    hasPeers = function() {
+      return data.peers && data.peers.length > 0;
+    },
+
+    getPeers = function() {
+      return data.peers;
+    },
+
+    isBusy = function() {
+      return data.loading;
+    },
+
+    getKnownBlocks = function() {
+      return data.knownBlocks;
+    },
+
+    // Load WS2P heads
+    loadW2spHeads = function() {
+      return data.bma.network.ws2p.heads()
+        .then(function (res) {
+          data.ws2pHeads = res.heads ? res.heads.reduce(function (res, hit) {
+            if (hit.message && hit.sig) {
+              try {
+                var head = new Ws2pMessage(hit.message);
+                res[[head.pubkey, head.ws2pid].join('-')] = head;
+              }
+              catch(err) {
+                // just log, then ignore
+                console.error('[network] Ignoring WS2P head.', err && err.message || err);
               }
-              return res;
-            }, {}) : {};
-          })
-          .catch(function(err) {
-            // When too many request, retry in 3s
-            if (err && err.ucode == BMA.errorCodes.HTTP_LIMITATION) {
-              return $timeout(function() {
-                return loadW2spHeads();
-              }, 3000);
             }
-            console.error(err); // can occur on duniter v1.6
-            data.ws2pHeads = {};
-          });
-      },
+            return res;
+          }, {}) : {};
+        })
+        .catch(function(err) {
+          // When too many request, retry in 3s
+          if (err && err.ucode == BMA.errorCodes.HTTP_LIMITATION) {
+            return $timeout(function() {
+              return loadW2spHeads();
+            }, 3000);
+          }
+          console.error(err); // can occur on duniter v1.6
+          data.ws2pHeads = {};
+        });
+    },
+
+    // Load personal difficulties
+    loadDifficulties = function() {
+      return data.bma.blockchain.stats.difficulties()
+        .then(function (res) {
+          data.difficulties = res.levels ? res.levels.reduce(function (res, hit) {
+            if (hit.uid && hit.level) res[hit.uid] = hit.level;
+            return res;
+          }, {}) : {};
+        })
+        .catch(function(err) {
+          // When too many request, retry in 3s
+          if (err && err.ucode == BMA.errorCodes.HTTP_LIMITATION) {
+            return $timeout(function() {
+              return loadDifficulties();
+            }, 3000);
+          }
+          console.error(err);
+          data.difficulties = {};
+        });
+    },
 
-      // Load personal difficulties
-      loadDifficulties = function() {
-        return data.bma.blockchain.stats.difficulties()
-          .then(function (res) {
-            data.difficulties = res.levels ? res.levels.reduce(function (res, hit) {
-              if (hit.uid && hit.level) res[hit.uid] = hit.level;
-              return res;
-            }, {}) : {};
-          })
-          .catch(function(err) {
-            // When too many request, retry in 3s
-            if (err && err.ucode == BMA.errorCodes.HTTP_LIMITATION) {
-              return $timeout(function() {
-                return loadDifficulties();
-              }, 3000);
-            }
-            console.error(err);
-            data.difficulties = {};
-          });
-      },
+    loadPeers = function() {
+      data.peers = [];
+      data.searchingPeersOnNetwork = true;
+      data.loading = true;
+      data.bma = data.bma || BMA;
+      var newPeers = [];
 
-      loadPeers = function() {
-        data.peers = [];
-        data.searchingPeersOnNetwork = true;
-        data.loading = true;
-        data.bma = data.bma || BMA;
-        var newPeers = [];
+      if (interval) {
+        $interval.cancel(interval);
+      }
 
-        if (interval) {
+      interval = $interval(function() {
+        // not same job instance
+        if (newPeers.length) {
+          flushNewPeersAndSort(newPeers);
+        }
+        else if (data.loading && !data.searchingPeersOnNetwork) {
+          data.loading = false;
           $interval.cancel(interval);
+          // The peer lookup end, we can make a clean final report
+          sortPeers(true/*update main buid*/);
+
+          console.debug('[network] Finish: {0} peers found.'.format(data.peers.length));
         }
+      }, 1000);
 
-        interval = $interval(function() {
-          // not same job instance
-          if (newPeers.length) {
-            flushNewPeersAndSort(newPeers);
-          }
-          else if (data.loading && !data.searchingPeersOnNetwork) {
-            data.loading = false;
-            $interval.cancel(interval);
-            // The peer lookup end, we can make a clean final report
-            sortPeers(true/*update main buid*/);
+      var initJobs = [
+        // Load uids
+        data.bma.wot.member.uids()
+          .then(function(uids) {
+            data.uidsByPubkeys = uids;
+          })
+          .catch(function(err) {
+            console.error(err);
+            data.uidsByPubkeys = {};
+          }),
 
-            console.debug('[network] Finish: {0} peers found.'.format(data.peers.length));
-          }
-        }, 1000);
+        // Load WS2P heads
+        loadW2spHeads()
+      ];
 
-        var initJobs = [
-          // Load uids
-          data.bma.wot.member.uids()
-            .then(function(uids) {
-              data.uidsByPubkeys = uids;
-            })
-            .catch(function(err) {
-              console.error(err);
-              data.uidsByPubkeys = {};
-            }),
+      // Get difficulties (expert mode only)
+      if (data.expertMode) {
+        initJobs.push(loadDifficulties());
+      }
 
-          // Load WS2P heads
-          loadW2spHeads()
-        ];
+      return $q.all(initJobs)
+        .then(function() {
+          return data.bma && data.bma.network.peers();
+        })
+        .then(function(res){
+          if (!res || !res.peers || !res.peers.length) return;
 
-        // Get difficulties (expert mode only)
-        if (data.expertMode) {
-          initJobs.push(loadDifficulties());
-        }
-
-        return $q.all(initJobs)
-          .then(function() {
-            return data.bma && data.bma.network.peers();
-          })
-          .then(function(res){
-            if (!res || !res.peers || !res.peers.length) return;
-
-            // If filter online peers
-            if (data.filter.online) {
-              var jobs = [];
-              _.forEach(res.peers, function(json) {
-                // Exclude, if not UP or on a too old block
-                if (json.status !== 'UP') return;
-                json.blockNumber = json.block && parseInt(json.block.split('-')[0]);
-                if (json.blockNumber && json.blockNumber < data.minOnlineBlockNumber) {
-                  console.debug("[network] Exclude a too old peer document, on pubkey {0}".format(json.pubkey.substring(0,6)));
-                  return;
-                }
+          // If filter online peers
+          if (data.filter.online) {
+            var jobs = [];
+            _.forEach(res.peers, function(json) {
+              // Exclude, if not UP or on a too old block
+              if (json.status !== 'UP') return;
+              json.blockNumber = json.block && parseInt(json.block.split('-')[0]);
+              if (json.blockNumber && json.blockNumber < data.minOnlineBlockNumber) {
+                console.debug("[network] Exclude a too old peer document, on pubkey {0}".format(json.pubkey.substring(0,6)));
+                return;
+              }
 
-                jobs.push(addOrRefreshPeerFromJson(json, newPeers));
+              jobs.push(addOrRefreshPeerFromJson(json, newPeers));
 
-                // Mark WS2P
-                _.forEach(json.endpoints||[], function(ep) {
-                  if (ep.startsWith('WS2P')) {
-                    var key = json.pubkey + '-' + ep.split(' ')[1];
-                    if (data.ws2pHeads[key]) {
-                      data.ws2pHeads[key].hasEndpoint = true;
-                    }
+              // Mark WS2P
+              _.forEach(json.endpoints||[], function(ep) {
+                if (ep.startsWith('WS2P')) {
+                  var key = json.pubkey + '-' + ep.split(' ')[1];
+                  if (data.ws2pHeads[key]) {
+                    data.ws2pHeads[key].hasEndpoint = true;
                   }
-                });
+                }
               });
+            });
 
-              // Add private WS2P endpoints
-              var privateWs2pHeads = _.values(data.ws2pHeads);
-              if (privateWs2pHeads && privateWs2pHeads.length) {
-                var privateEPCount = 0;
-                //console.debug("[http] Found WS2P endpoints without endpoint:", data.ws2pHeads);
-                _.forEach(privateWs2pHeads, function(head) {
-
-                  if (!head.hasEndPoint) {
-                    var currentNumber = head.buid && parseInt(head.buid.split('-')[0]);
-                    // Exclude if on a too old block
-                    if (currentNumber && currentNumber < data.minOnlineBlockNumber) {
-                      console.debug("[network] Exclude a too old WS2P message, on pubkey {0}".format(head.pubkey.substring(0,6)));
-                      return;
-                    }
-
-                    var peer = new Peer({
-                      buid: head.buid,
-                      currentNumber: currentNumber,
-                      pubkey: head.pubkey,
-                      version: head.version,
-                      powPrefix: head.powPrefix,
-                      online: true,
-                      uid: data.uidsByPubkeys[head.pubkey],
-                      bma: {
-                        useWs2p: true,
-                        private: true,
-                        ws2pid: head.ws2pid
-                      },
-                      endpoints: [
-                        // fake endpoint
-                        'WS2P ' + head.ws2pid
-                      ]
-                    });
-                    peer.id = peer.keyID();
-                    if (peer.uid && data.expertMode && data.difficulties) {
-                      peer.difficulty = data.difficulties[peer.uid];
-                    }
-                    if (applyPeerFilter(peer)) {
-                      newPeers.push(peer);
-                      privateEPCount++;
-                    }
+            // Add private WS2P endpoints
+            var privateWs2pHeads = _.values(data.ws2pHeads);
+            if (privateWs2pHeads && privateWs2pHeads.length) {
+              var privateEPCount = 0;
+              //console.debug("[http] Found WS2P endpoints without endpoint:", data.ws2pHeads);
+              _.forEach(privateWs2pHeads, function(head) {
+
+                if (!head.hasEndPoint) {
+                  var currentNumber = head.buid && parseInt(head.buid.split('-')[0]);
+                  // Exclude if on a too old block
+                  if (currentNumber && currentNumber < data.minOnlineBlockNumber) {
+                    console.debug("[network] Exclude a too old WS2P message, on pubkey {0}".format(head.pubkey.substring(0,6)));
+                    return;
                   }
-                });
 
-                if (privateEPCount) {
-                  console.debug("[http] Found {0} WS2P endpoints without endpoint (private ?)".format(privateEPCount));
+                  var peer = new Peer({
+                    buid: head.buid,
+                    currentNumber: currentNumber,
+                    pubkey: head.pubkey,
+                    version: head.version,
+                    powPrefix: head.powPrefix,
+                    online: true,
+                    uid: data.uidsByPubkeys[head.pubkey],
+                    bma: {
+                      useWs2p: true,
+                      private: true,
+                      ws2pid: head.ws2pid
+                    },
+                    endpoints: [
+                      // fake endpoint
+                      'WS2P ' + head.ws2pid
+                    ]
+                  });
+                  peer.id = peer.keyID();
+                  if (peer.uid && data.expertMode && data.difficulties) {
+                    peer.difficulty = data.difficulties[peer.uid];
+                  }
+                  if (applyPeerFilter(peer)) {
+                    newPeers.push(peer);
+                    privateEPCount++;
+                  }
                 }
-              }
+              });
 
-              if (jobs.length) return $q.all(jobs);
+              if (privateEPCount) {
+                console.debug("[http] Found {0} WS2P endpoints without endpoint (private ?)".format(privateEPCount));
+              }
             }
 
-            // If filter offline peers
-            else {
-              return $q.all(_(res && res.peers || []).reduce(function(res, json) {
-                return res.concat(addOrRefreshPeerFromJson(json, newPeers));
-              }, []));
-            }
-          })
-          .then(function(){
-            data.searchingPeersOnNetwork = false;
-          })
-          .catch(function(err){
-            console.error(err);
-            data.searchingPeersOnNetwork = false;
-          });
-      },
-
-      /**
-       * Apply filter on a peer. (peer uid should have been filled BEFORE)
-       */
-      applyPeerFilter = function(peer) {
-        // no filter
-        if (!data.filter) return true;
-
-        // Filter member and mirror
-        if ((data.filter.member && !data.filter.mirror && !peer.uid) ||
-            (data.filter.mirror && !data.filter.member && peer.uid)) {
-          return false;
-        }
+            if (jobs.length) return $q.all(jobs);
+          }
 
-        // Filter on endpoint
-        if (data.filter.endpoint && !peer.hasEndpoint(data.filter.endpoint)) {
-          return false;
-        }
+          // If filter offline peers
+          else {
+            return $q.all(_(res && res.peers || []).reduce(function(res, json) {
+              return res.concat(addOrRefreshPeerFromJson(json, newPeers));
+            }, []));
+          }
+        })
+        .then(function(){
+          data.searchingPeersOnNetwork = false;
+        })
+        .catch(function(err){
+          console.error(err);
+          data.searchingPeersOnNetwork = false;
+        });
+    },
+
+    /**
+     * Apply filter on a peer. (peer uid should have been filled BEFORE)
+     */
+    applyPeerFilter = function(peer) {
+      // no filter
+      if (!data.filter) return true;
+
+      // Filter member and mirror
+      if ((data.filter.member && !data.filter.mirror && !peer.uid) ||
+          (data.filter.mirror && !data.filter.member && peer.uid)) {
+        return false;
+      }
 
-        // Filter on status
-        if ((data.filter.online && peer.status !== 'UP' && peer.oldBlock) || (!data.filter.online && peer.status === 'UP' && !peer.oldBlock)) {
-          return false;
-        }
+      // Filter on endpoint
+      if (data.filter.endpoint && !peer.hasEndpoint(data.filter.endpoint)) {
+        return false;
+      }
 
-        // Filter on bma
-        if (angular.isDefined(data.filter.bma) && peer.isBma() != data.filter.bma) {
-          return false;
-        }
+      // Filter on status
+      if ((data.filter.online && peer.status !== 'UP' && peer.oldBlock) || (!data.filter.online && peer.status === 'UP' && !peer.oldBlock)) {
+        return false;
+      }
 
-        // Filter on ws2p
-        if (angular.isDefined(data.filter.ws2p) && peer.isWs2p() != data.filter.ws2p) {
-          return false;
-        }
+      // Filter on bma
+      if (angular.isDefined(data.filter.bma) && peer.isBma() != data.filter.bma) {
+        return false;
+      }
 
-        // Filter on ssl
-        if (angular.isDefined(data.filter.ssl) && peer.isSsl() != data.filter.ssl) {
-          return false;
-        }
+      // Filter on ws2p
+      if (angular.isDefined(data.filter.ws2p) && peer.isWs2p() != data.filter.ws2p) {
+        return false;
+      }
 
-        // Filter on tor
-        if (angular.isDefined(data.filter.tor) && peer.isTor() != data.filter.tor) {
-          return false;
-        }
+      // Filter on ssl
+      if (angular.isDefined(data.filter.ssl) && peer.isSsl() != data.filter.ssl) {
+        return false;
+      }
 
-        return true;
-      },
+      // Filter on tor
+      if (angular.isDefined(data.filter.tor) && peer.isTor() != data.filter.tor) {
+        return false;
+      }
 
-      addOrRefreshPeerFromJson = function(json, list) {
-        list = list || data.newPeers;
-
-        // Analyze the peer document, and exclude using the online filter
-        json.blockNumber = json.block && parseInt(json.block.split('-')[0]);
-        json.oldBlock = (json.status === 'UP' && json.blockNumber && json.blockNumber < data.minOnlineBlockNumber);
-
-        var peers = createPeerEntities(json);
-        var hasUpdates = false;
-
-        var jobs = peers.reduce(function(jobs, peer) {
-            var existingPeer = _.findWhere(data.peers, {id: peer.id});
-            var existingMainBuid = existingPeer ? existingPeer.buid : null;
-            var existingOnline = existingPeer ? existingPeer.online : false;
-
-            return jobs.concat(
-              refreshPeer(peer)
-                .then(function (refreshedPeer) {
-                  if (existingPeer) {
-                    // remove existing peers, when reject or offline
-                    if (!refreshedPeer || (refreshedPeer.online !== data.filter.online && data.filter.online !== 'all')) {
-                      var existingIndex = data.peers.indexOf(existingPeer);
-                      if (existingIndex !== -1) {
-                        console.debug('[network] Peer [{0}] removed (cause: {1})'.format(peer.server, !refreshedPeer ? 'filtered' : (refreshedPeer.online ? 'UP' : 'DOWN')));
-                        data.peers.splice(existingIndex, 1);
-                        hasUpdates = true;
-                      }
-                    }
-                    else if (refreshedPeer.buid !== existingMainBuid){
-                      console.debug('[network] {0} endpoint [{1}] new current block'.format(
-                        refreshedPeer.bma && (refreshedPeer.bma.useBma ? 'BMA' : 'WS2P') || 'null',
-                        refreshedPeer.server));
-                      hasUpdates = true;
-                    }
-                    else if (existingOnline !== refreshedPeer.online){
-                      console.debug('[network] {0} endpoint [{1}] is now {2}'.format(
-                        refreshedPeer.bma && (refreshedPeer.bma.useBma ? 'BMA' : 'WS2P') || 'null',
-                        refreshedPeer.server,
-                        refreshedPeer.online ? 'UP' : 'DOWN'));
+      return true;
+    },
+
+    addOrRefreshPeerFromJson = function(json, list) {
+      list = list || data.newPeers;
+
+      // Analyze the peer document, and exclude using the online filter
+      json.blockNumber = json.block && parseInt(json.block.split('-')[0]);
+      json.oldBlock = (json.status === 'UP' && json.blockNumber && json.blockNumber < data.minOnlineBlockNumber);
+
+      var peers = createPeerEntities(json);
+      var hasUpdates = false;
+
+      var jobs = peers.reduce(function(jobs, peer) {
+          var existingPeer = _.findWhere(data.peers, {id: peer.id});
+          var existingMainBuid = existingPeer ? existingPeer.buid : null;
+          var existingOnline = existingPeer ? existingPeer.online : false;
+
+          return jobs.concat(
+            refreshPeer(peer)
+              .then(function (refreshedPeer) {
+                if (existingPeer) {
+                  // remove existing peers, when reject or offline
+                  if (!refreshedPeer || (refreshedPeer.online !== data.filter.online && data.filter.online !== 'all')) {
+                    var existingIndex = data.peers.indexOf(existingPeer);
+                    if (existingIndex !== -1) {
+                      console.debug('[network] Peer [{0}] removed (cause: {1})'.format(peer.server, !refreshedPeer ? 'filtered' : (refreshedPeer.online ? 'UP' : 'DOWN')));
+                      data.peers.splice(existingIndex, 1);
                       hasUpdates = true;
                     }
-                    else {
-                      console.debug("[network] {0} endpoint [{1}] unchanged".format(
-                        refreshedPeer.bma && (refreshedPeer.bma.useBma ? 'BMA' : 'WS2P') || 'null',
-                        refreshedPeer.server));
-                    }
                   }
-                  else if (refreshedPeer && (refreshedPeer.online === data.filter.online || data.filter.online === 'all')) {
-                    console.debug("[network] {0} endpoint [{1}] is {2}".format(
+                  else if (refreshedPeer.buid !== existingMainBuid){
+                    console.debug('[network] {0} endpoint [{1}] new current block'.format(
+                      refreshedPeer.bma && (refreshedPeer.bma.useBma ? 'BMA' : 'WS2P') || 'null',
+                      refreshedPeer.server));
+                    hasUpdates = true;
+                  }
+                  else if (existingOnline !== refreshedPeer.online){
+                    console.debug('[network] {0} endpoint [{1}] is now {2}'.format(
                       refreshedPeer.bma && (refreshedPeer.bma.useBma ? 'BMA' : 'WS2P') || 'null',
                       refreshedPeer.server,
-                      refreshedPeer.online ? 'UP' : 'DOWN'
-                    ));
-                    list.push(refreshedPeer);
+                      refreshedPeer.online ? 'UP' : 'DOWN'));
                     hasUpdates = true;
                   }
-                })
-           );
-        }, []);
-        return (jobs.length === 1 ? jobs[0] : $q.all(jobs))
-          .then(function() {
-            return hasUpdates;
-          });
-      },
+                  else {
+                    console.debug("[network] {0} endpoint [{1}] unchanged".format(
+                      refreshedPeer.bma && (refreshedPeer.bma.useBma ? 'BMA' : 'WS2P') || 'null',
+                      refreshedPeer.server));
+                  }
+                }
+                else if (refreshedPeer && (refreshedPeer.online === data.filter.online || data.filter.online === 'all')) {
+                  console.debug("[network] {0} endpoint [{1}] is {2}".format(
+                    refreshedPeer.bma && (refreshedPeer.bma.useBma ? 'BMA' : 'WS2P') || 'null',
+                    refreshedPeer.server,
+                    refreshedPeer.online ? 'UP' : 'DOWN'
+                  ));
+                  list.push(refreshedPeer);
+                  hasUpdates = true;
+                }
+              })
+         );
+      }, []);
+      return (jobs.length === 1 ? jobs[0] : $q.all(jobs))
+        .then(function() {
+          return hasUpdates;
+        });
+    },
 
-      createPeerEntities = function(json, ep) {
-        if (!json) return [];
-        var peer = new Peer(json);
+    createPeerEntities = function(json, ep) {
+      if (!json) return [];
+      var peer = new Peer(json);
 
-        // Read bma endpoints
-        if (!ep) {
-          var endpointsAsString = peer.getEndpoints();
-          if (!endpointsAsString) return []; // no BMA
+      // Read bma endpoints
+      if (!ep) {
+        var endpointsAsString = peer.getEndpoints();
+        if (!endpointsAsString) return []; // no BMA
 
-          var endpoints = endpointsAsString.reduce(function (res, epStr) {
-            var ep = BMA.node.parseEndPoint(epStr);
-            return ep ? res.concat(ep) : res;
-          }, []);
+        var endpoints = endpointsAsString.reduce(function (res, epStr) {
+          var ep = BMA.node.parseEndPoint(epStr);
+          return ep ? res.concat(ep) : res;
+        }, []);
 
-          // recursive call, on each endpoint
-          if (endpoints.length > 1) {
-            return endpoints.reduce(function (res, ep) {
-              return res.concat(createPeerEntities(json, ep));
-            }, []);
-          }
-          else {
-            // if only one endpoint: use it and continue
-            ep = endpoints[0];
-          }
+        // recursive call, on each endpoint
+        if (endpoints.length > 1) {
+          return endpoints.reduce(function (res, ep) {
+            return res.concat(createPeerEntities(json, ep));
+          }, []);
         }
-        peer.bma = ep;
-        peer.server = peer.getServer();
-        peer.dns = peer.getDns();
-        peer.buid = peer.buid || peer.block;
-        peer.blockNumber = peer.buid && parseInt(peer.buid.split('-')[0]);
-        peer.uid = peer.pubkey && data.uidsByPubkeys[peer.pubkey];
-        peer.id = peer.keyID();
-        return [peer];
-      },
-
-      refreshPeer = function(peer) {
+        else {
+          // if only one endpoint: use it and continue
+          ep = endpoints[0];
+        }
+      }
+      peer.bma = ep;
+      peer.server = peer.getServer();
+      peer.dns = peer.getDns();
+      peer.buid = peer.buid || peer.block;
+      peer.blockNumber = peer.buid && parseInt(peer.buid.split('-')[0]);
+      peer.uid = peer.pubkey && data.uidsByPubkeys[peer.pubkey];
+      peer.id = peer.keyID();
+      return [peer];
+    },
+
+    refreshPeer = function(peer) {
+
+      // Apply filter
+      if (!applyPeerFilter(peer)) return $q.when();
+
+      if (!data.filter.online || (!data.filter.online && peer.status === 'DOWN') || !peer.getHost() /*fix #537*/) {
+        peer.online = false;
+        return $q.when(peer);
+      }
 
-        // Apply filter
-        if (!applyPeerFilter(peer)) return $q.when();
+      if (peer.bma.useWs2p && data.ws2pHeads) {
+        var ws2pHeadKey = [peer.pubkey, peer.bma.ws2pid].join('-');
+        var head = data.ws2pHeads[ws2pHeadKey];
+        delete data.ws2pHeads[ws2pHeadKey];
+        if (head) {
+          peer.buid = head.buid;
+          peer.currentNumber=head.buid && parseInt(head.buid.split('-')[0]);
+          peer.version = head.version;
+          peer.powPrefix = head.powPrefix;
+        }
+        peer.online = !!peer.buid;
 
-        if (!data.filter.online || (!data.filter.online && peer.status === 'DOWN') || !peer.getHost() /*fix #537*/) {
-          peer.online = false;
-          return $q.when(peer);
+        if (peer.uid && data.expertMode && data.difficulties) {
+          peer.difficulty = data.difficulties[peer.uid];
         }
 
-        if (peer.bma.useWs2p && data.ws2pHeads) {
-          var ws2pHeadKey = [peer.pubkey, peer.bma.ws2pid].join('-');
-          var head = data.ws2pHeads[ws2pHeadKey];
-          delete data.ws2pHeads[ws2pHeadKey];
-          if (head) {
-            peer.buid = head.buid;
-            peer.currentNumber=head.buid && parseInt(head.buid.split('-')[0]);
-            peer.version = head.version;
-            peer.powPrefix = head.powPrefix;
-          }
-          peer.online = !!peer.buid;
+        return $q.when(peer);
+      }
 
-          if (peer.uid && data.expertMode && data.difficulties) {
-            peer.difficulty = data.difficulties[peer.uid];
-          }
+      // Cesium running in SSL: Do not try to access not SSL node,
+      if (!peer.bma.useWs2p && isHttpsMode && !peer.bma.useSsl) {
+        peer.online = (peer.status === 'UP');
+        peer.buid = constants.UNKNOWN_BUID;
+        delete peer.version;
 
-          return $q.when(peer);
+        if (peer.uid && data.expertMode && data.difficulties) {
+          peer.difficulty = data.difficulties[peer.uid];
         }
 
-        // Cesium running in SSL: Do not try to access not SSL node,
-        if (!peer.bma.useWs2p && isHttpsMode && !peer.bma.useSsl) {
-          peer.online = (peer.status === 'UP');
-          peer.buid = constants.UNKNOWN_BUID;
-          delete peer.version;
+        return $q.when(peer);
+      }
 
-          if (peer.uid && data.expertMode && data.difficulties) {
-            peer.difficulty = data.difficulties[peer.uid];
-          }
+      // Do not try to access TOR or WS2P endpoints
+      if (peer.bma.useTor || peer.bma.useWs2p) {
+        peer.online = (peer.status === 'UP');
+        peer.buid = constants.UNKNOWN_BUID;
+        delete peer.version;
 
-          return $q.when(peer);
+        if (peer.uid && data.expertMode && data.difficulties) {
+          peer.difficulty = data.difficulties[peer.uid];
         }
+        return $q.when(peer);
+      }
 
-        // Do not try to access TOR or WS2P endpoints
-        if (peer.bma.useTor || peer.bma.useWs2p) {
-          peer.online = (peer.status === 'UP');
-          peer.buid = constants.UNKNOWN_BUID;
-          delete peer.version;
-
-          if (peer.uid && data.expertMode && data.difficulties) {
-            peer.difficulty = data.difficulties[peer.uid];
+      peer.api = peer.api ||  BMA.lightInstance(peer.getHost(), peer.getPort(), peer.isSsl(), data.timeout);
+
+      // Get current block
+      return peer.api.blockchain.current(false/*no cache*/)
+        .then(function(block) {
+          peer.currentNumber = block.number;
+          peer.online = true;
+          peer.buid = buid(block);
+          peer.medianTime = block.medianTime;
+          if (data.knownBlocks.indexOf(peer.buid) === -1) {
+            data.knownBlocks.push(peer.buid);
           }
-          return $q.when(peer);
-        }
-
-        peer.api = peer.api ||  BMA.lightInstance(peer.getHost(), peer.getPort(), peer.isSsl(), data.timeout);
-
-        // Get current block
-        return peer.api.blockchain.current(false/*no cache*/)
-          .then(function(block) {
-            peer.currentNumber = block.number;
+          return peer;
+        })
+        .catch(function(err) {
+          // Special case for currency init (root block not exists): use fixed values
+          if (err && err.ucode == BMA.errorCodes.NO_CURRENT_BLOCK) {
             peer.online = true;
-            peer.buid = buid(block);
-            peer.medianTime = block.medianTime;
-            if (data.knownBlocks.indexOf(peer.buid) === -1) {
-              data.knownBlocks.push(peer.buid);
-            }
+            peer.buid = buid({number:0, hash: BMA.constants.ROOT_BLOCK_HASH});
+            peer.difficulty  = 0;
             return peer;
-          })
-          .catch(function(err) {
-            // Special case for currency init (root block not exists): use fixed values
-            if (err && err.ucode == BMA.errorCodes.NO_CURRENT_BLOCK) {
-              peer.online = true;
-              peer.buid = buid({number:0, hash: BMA.constants.ROOT_BLOCK_HASH});
-              peer.difficulty  = 0;
-              return peer;
-            }
-            if (!peer.secondTry) {
-              var bma = peer.bma || peer.getBMA();
-              if (bma.dns && peer.server.indexOf(bma.dns) === -1) {
-                // try again, using DNS instead of IPv4 / IPV6
-                peer.secondTry = true;
-                peer.api = BMA.lightInstance(bma.dns, bma.port, bma.useSsl);
-                return refreshPeer(peer); // recursive call
-              }
-            }
-
-            peer.buid = null;
-            peer.blockNumber = null;
-            peer.currentNumber = null;
-            peer.online=false;
-            peer.uid = data.uidsByPubkeys[peer.pubkey];
-            return peer;
-          })
-          .then(function(peer) {
-            // Exit if offline, or not expert mode or too small device
-            if (!data.filter.online || !peer || !peer.online || !data.expertMode) return peer;
-            var jobs = [];
-
-            // Get hardship (only for a member peer)
-            if (peer.uid) {
-              jobs.push(peer.api.blockchain.stats.hardship({pubkey: peer.pubkey})
-                .then(function (res) {
-                  peer.difficulty = res ? res.level : null;
-                })
-                .catch(function() {
-                  peer.difficulty = null; // continue
-                }));
+          }
+          if (!peer.secondTry) {
+            var bma = peer.bma || peer.getBMA();
+            if (bma.dns && peer.server.indexOf(bma.dns) === -1) {
+              // try again, using DNS instead of IPv4 / IPV6
+              peer.secondTry = true;
+              peer.api = BMA.lightInstance(bma.dns, bma.port, bma.useSsl);
+              return refreshPeer(peer); // recursive call
             }
+          }
 
-            // Get Version
-            jobs.push(peer.api.node.summary()
-              .then(function(res){
-                peer.software = res && res.duniter && res.duniter.software || undefined;
-                peer.version = res && res.duniter && res.duniter.version || '?';
+          peer.buid = null;
+          peer.blockNumber = null;
+          peer.currentNumber = null;
+          peer.online=false;
+          peer.uid = data.uidsByPubkeys[peer.pubkey];
+          return peer;
+        })
+        .then(function(peer) {
+          // Exit if offline, or not expert mode or too small device
+          if (!data.filter.online || !peer || !peer.online || !data.expertMode) return peer;
+          var jobs = [];
+
+          // Get hardship (only for a member peer)
+          if (peer.uid) {
+            jobs.push(peer.api.blockchain.stats.hardship({pubkey: peer.pubkey})
+              .then(function (res) {
+                peer.difficulty = res ? res.level : null;
               })
               .catch(function() {
-                peer.software = undefined;
-                peer.version = '?'; // continue
+                peer.difficulty = null; // continue
               }));
-
-            return $q.all(jobs)
-              .then(function(){
-                return peer;
-              });
-          });
-      },
-
-      flushNewPeersAndSort = function(newPeers, updateMainBuid) {
-        newPeers = newPeers || data.newPeers;
-        if (!newPeers.length) return;
-        var ids = _.map(data.peers, function(peer){
-          return peer.id;
-        });
-        var hasUpdates = false;
-        var newPeersAdded = 0;
-        _.forEach(newPeers.splice(0), function(peer) {
-          if (!ids[peer.id]) {
-            data.peers.push(peer);
-            ids[peer.id] = peer;
-            hasUpdates = true;
-            newPeersAdded++;
           }
-        });
-        if (hasUpdates) {
-          console.debug('[network] Flushing {0} new peers...'.format(newPeersAdded));
-          sortPeers(updateMainBuid);
-        }
-      },
 
-      computeScoreAlphaValue = function(value, nbChars, asc) {
-        if (!value) return 0;
-        var score = 0;
-        value = value.toLowerCase();
-        if (nbChars > value.length) {
-          nbChars = value.length;
-        }
-        score += value.charCodeAt(0);
-        for (var i=1; i < nbChars; i++) {
-          score += Math.pow(0.001, i) * value.charCodeAt(i);
-        }
-        return asc ? (1000 - score) : score;
-      },
+          // Get Version
+          jobs.push(peer.api.node.summary()
+            .then(function(res){
+              peer.software = res && res.duniter && res.duniter.software || undefined;
+              peer.version = res && res.duniter && res.duniter.version || '?';
+            })
+            .catch(function() {
+              peer.software = undefined;
+              peer.version = '?'; // continue
+            }));
 
-      sortPeers = function(updateMainBuid) {
-        // Construct a map of buid, with peer count and medianTime
-        var buids = {};
-        data.memberPeersCount = 0;
-        _.forEach(data.peers, function(peer){
-          if (peer.buid) {
-            var buid = buids[peer.buid];
-            if (!buid || !buid.medianTime) {
-              buid = {
-                buid: peer.buid,
-                medianTime: peer.medianTime,
-                count: 0
-              };
-              buids[peer.buid] = buid;
-            }
-            // If not already done, try to fill medianTime (need to compute consensusBlockDelta)
-            else if (!buid.medianTime && peer.medianTime) {
-              buid.medianTime = peer.medianTime;
-            }
-            if (buid.buid !== constants.UNKNOWN_BUID) {
-              buid.count++;
-            }
-          }
-          data.memberPeersCount += peer.uid ? 1 : 0;
+          return $q.all(jobs)
+            .then(function(){
+              return peer;
+            });
         });
-        var mainBlock = data.mainBlock;
-        if (data.filter.online) {
-          // Compute pct of use, per buid
-          _.forEach(_.values(buids), function(buid) {
-            buid.pct = buid.count * 100 / data.peers.length;
-          });
-          mainBlock = _.max(buids, function(obj) {
-            return obj.count;
-          });
-          _.forEach(data.peers, function(peer){
-            peer.hasMainConsensusBlock = peer.buid === mainBlock.buid;
-            peer.hasConsensusBlock = peer.buid && !peer.hasMainConsensusBlock && buids[peer.buid].count > 1;
-            if (peer.hasConsensusBlock) {
-              peer.consensusBlockDelta = buids[peer.buid].medianTime - mainBlock.medianTime;
-            }
-          });
+    },
+
+    flushNewPeersAndSort = function(newPeers, updateMainBuid) {
+      newPeers = newPeers || data.newPeers;
+      if (!newPeers.length) return;
+      var ids = _.map(data.peers, function(peer){
+        return peer.id;
+      });
+      var hasUpdates = false;
+      var newPeersAdded = 0;
+      _.forEach(newPeers.splice(0), function(peer) {
+        if (!ids[peer.id]) {
+          data.peers.push(peer);
+          ids[peer.id] = peer;
+          hasUpdates = true;
+          newPeersAdded++;
         }
-        data.peers = _.uniq(data.peers, false, function(peer) {
-          return peer.id;
-        });
-        data.peers = _.sortBy(data.peers, function(peer) {
-          var score = 0;
-          if (data.sort.type) {
-            score += (data.sort.type === 'uid' ? computeScoreAlphaValue(peer.uid||peer.pubkey, 3, data.sort.asc) : 0);
-            score += (data.sort.type === 'api') &&
-              ((peer.isWs2p() && (data.sort.asc ? 1 : -1) || 0) +
-              (peer.hasEndpoint('ES_USER_API') && (data.sort.asc ? 0.01 : -0.01) || 0) +
-              (peer.isSsl() && (data.sort.asc ? 0.75 : -0.75) || 0)) || 0;
-            score += (data.sort.type === 'difficulty' ? (peer.difficulty ? (data.sort.asc ? (10000-peer.difficulty) : peer.difficulty): 0) : 0);
-            score += (data.sort.type === 'current_block' ? (peer.currentNumber ? (data.sort.asc ? (1000000000 - peer.currentNumber) : peer.currentNumber) : 0) : 0);
+      });
+      if (hasUpdates) {
+        console.debug('[network] Flushing {0} new peers...'.format(newPeersAdded));
+        sortPeers(updateMainBuid);
+      }
+    },
+
+    computeScoreAlphaValue = function(value, nbChars, asc) {
+      if (!value) return 0;
+      var score = 0;
+      value = value.toLowerCase();
+      if (nbChars > value.length) {
+        nbChars = value.length;
+      }
+      score += value.charCodeAt(0);
+      for (var i=1; i < nbChars; i++) {
+        score += Math.pow(0.001, i) * value.charCodeAt(i);
+      }
+      return asc ? (1000 - score) : score;
+    },
+
+    sortPeers = function(updateMainBuid) {
+      // Construct a map of buid, with peer count and medianTime
+      var buids = {};
+      data.memberPeersCount = 0;
+      _.forEach(data.peers, function(peer){
+        if (peer.buid) {
+          var buid = buids[peer.buid];
+          if (!buid || !buid.medianTime) {
+            buid = {
+              buid: peer.buid,
+              medianTime: peer.medianTime,
+              count: 0
+            };
+            buids[peer.buid] = buid;
           }
-          score =  (10000000000 * score);
-          score += (1000000000 * (peer.online ? 1 : 0));
-          score += (100000000  * (peer.hasMainConsensusBlock ? 1 : 0));
-          score += (1000000    * (peer.hasConsensusBlock ? buids[peer.buid].pct : 0));
-          if (data.expertMode) {
-            score += (100     * (peer.difficulty ? (10000-peer.difficulty) : 0));
-            score += (1       * (peer.uid ? computeScoreAlphaValue(peer.uid, 2, true) : 0));
+          // If not already done, try to fill medianTime (need to compute consensusBlockDelta)
+          else if (!buid.medianTime && peer.medianTime) {
+            buid.medianTime = peer.medianTime;
           }
-          else {
-            score += (100     * (peer.uid ? computeScoreAlphaValue(peer.uid, 2, true) : 0));
-            score += (1       * (!peer.uid ? computeScoreAlphaValue(peer.pubkey, 2, true) : 0));
+          if (buid.buid !== constants.UNKNOWN_BUID) {
+            buid.count++;
           }
-          score += (peer.isBma() ? (peer.isSsl() ? 0.01 : 0.001) :0); // If many endpoints: BMAS first, then BMA
-          return -score;
+        }
+        data.memberPeersCount += peer.uid ? 1 : 0;
+      });
+      var mainBlock = data.mainBlock;
+      if (data.filter.online) {
+        // Compute pct of use, per buid
+        _.forEach(_.values(buids), function(buid) {
+          buid.pct = buid.count * 100 / data.peers.length;
         });
-
-        if (data.groupBy) {
-          var previousPeer;
-          data.peers.forEach(function(peer) {
-            peer.compacted = (previousPeer && peer[data.groupBy] && peer[data.groupBy] === previousPeer[data.groupBy]);
-            previousPeer = peer;
-          });
+        mainBlock = _.max(buids, function(obj) {
+          return obj.count;
+        });
+        _.forEach(data.peers, function(peer){
+          peer.hasMainConsensusBlock = peer.buid === mainBlock.buid;
+          peer.hasConsensusBlock = peer.buid && !peer.hasMainConsensusBlock && buids[peer.buid].count > 1;
+          if (peer.hasConsensusBlock) {
+            peer.consensusBlockDelta = buids[peer.buid].medianTime - mainBlock.medianTime;
+          }
+        });
+      }
+      data.peers = _.uniq(data.peers, false, function(peer) {
+        return peer.id;
+      });
+      data.peers = _.sortBy(data.peers, function(peer) {
+        var score = 0;
+        if (data.sort.type) {
+          score += (data.sort.type === 'uid' ? computeScoreAlphaValue(peer.uid||peer.pubkey, 3, data.sort.asc) : 0);
+          score += (data.sort.type === 'api') &&
+            ((peer.isWs2p() && (data.sort.asc ? 1 : -1) || 0) +
+            (peer.hasEndpoint('ES_USER_API') && (data.sort.asc ? 0.01 : -0.01) || 0) +
+            (peer.isSsl() && (data.sort.asc ? 0.75 : -0.75) || 0)) || 0;
+          score += (data.sort.type === 'difficulty' ? (peer.difficulty ? (data.sort.asc ? (10000-peer.difficulty) : peer.difficulty): 0) : 0);
+          score += (data.sort.type === 'current_block' ? (peer.currentNumber ? (data.sort.asc ? (1000000000 - peer.currentNumber) : peer.currentNumber) : 0) : 0);
         }
-
-        // Raise event on new main block
-        if (updateMainBuid && mainBlock && mainBlock.buid && (!data.mainBlock || data.mainBlock.buid !== mainBlock.buid)) {
-          data.mainBlock = mainBlock;
-          api.data.raise.mainBlockChanged(mainBlock);
+        score =  (10000000000 * score);
+        score += (1000000000 * (peer.online ? 1 : 0));
+        score += (100000000  * (peer.hasMainConsensusBlock ? 1 : 0));
+        score += (1000000    * (peer.hasConsensusBlock ? buids[peer.buid].pct : 0));
+        if (data.expertMode) {
+          score += (100     * (peer.difficulty ? (10000-peer.difficulty) : 0));
+          score += (1       * (peer.uid ? computeScoreAlphaValue(peer.uid, 2, true) : 0));
         }
-
-        // Raise event when changed
-        api.data.raise.changed(data); // raise event
-      },
-
-      removeListeners = function() {
-        _.forEach(data.listeners, function(remove){
-          remove();
+        else {
+          score += (100     * (peer.uid ? computeScoreAlphaValue(peer.uid, 2, true) : 0));
+          score += (1       * (!peer.uid ? computeScoreAlphaValue(peer.pubkey, 2, true) : 0));
+        }
+        score += (peer.isBma() ? (peer.isSsl() ? 0.01 : 0.001) :0); // If many endpoints: BMAS first, then BMA
+        return -score;
+      });
+
+      if (data.groupBy) {
+        var previousPeer;
+        data.peers.forEach(function(peer) {
+          peer.compacted = (previousPeer && peer[data.groupBy] && peer[data.groupBy] === previousPeer[data.groupBy]);
+          previousPeer = peer;
         });
-        data.listeners = [];
-      },
-
-      addListeners = function() {
-        data.listeners = [
-
-          // Listen for new block
-          data.bma.websocket.block().onListener(function(block) {
-            if (!block || data.loading) return;
-            var buid = [block.number, block.hash].join('-');
-            if (data.knownBlocks.indexOf(buid) === -1) {
-              console.debug('[network] Receiving block: ' + buid.substring(0, 20));
-              data.knownBlocks.push(buid);
-              // If first block: do NOT refresh peers (will be done in start() method)
-              var skipRefreshPeers = data.knownBlocks.length === 1;
-              if (!skipRefreshPeers) {
-                data.loading = true;
-                // We wait 2s when a new block is received, just to wait for network propagation
-                $timeout(function() {
-                  console.debug('[network] new block received by WS: will refresh peers');
-                  loadPeers();
-                }, 2000, false /*invokeApply*/);
-              }
-            }
-          }),
-
-          // Listen for new peer
-          data.bma.websocket.peer().onListener(function(json) {
-            if (!json || data.loading) return;
-            var newPeers = [];
-            addOrRefreshPeerFromJson(json, newPeers)
-              .then(function(hasUpdates) {
-                if (!hasUpdates) return;
-                if (newPeers.length>0) {
-                  flushNewPeersAndSort(newPeers, true);
-                }
-                else {
-                  console.debug('[network] [ws] Peers updated received');
-                  sortPeers(true);
-                }
-              });
-          })
-        ];
-      },
+      }
 
-      sort = function(options) {
-        options = options || {};
-        data.filter = options.filter ? angular.merge(data.filter, options.filter) : data.filter;
-        data.sort = options.sort ? angular.merge(data.sort, options.sort) : data.sort;
-        sortPeers(false);
-      },
+      // Raise event on new main block
+      if (updateMainBuid && mainBlock && mainBlock.buid && (!data.mainBlock || data.mainBlock.buid !== mainBlock.buid)) {
+        data.mainBlock = mainBlock;
+        api.data.raise.mainBlockChanged(mainBlock);
+      }
 
-      start = function(bma, options) {
-        options = options || {};
-        return BMA.ready()
-          .then(function() {
-            close();
-
-            data.bma = bma || BMA;
-            data.filter = options.filter ? angular.merge(data.filter, options.filter) : data.filter;
-            data.sort = options.sort ? angular.merge(data.sort, options.sort) : data.sort;
-            data.expertMode = angular.isDefined(options.expertMode) ? options.expertMode : data.expertMode;
-            data.timeout = angular.isDefined(options.timeout) ? options.timeout : csConfig.timeout;
-
-            // Init a min block number
-            data.minOnlineBlockNumber = data.mainBlock && data.mainBlock.buid && (parseInt(data.mainBlock.buid.split('-')[0]) - constants.MAX_BLOCK_OFFSET) || undefined;
-            if (data.minOnlineBlockNumber === undefined) {
-              return csCurrency.blockchain.current(true/*use cache*/)
-                .then(function(current) {
-                  data.minOnlineBlockNumber = current.number - constants.MAX_BLOCK_OFFSET;
-                });
+      // Raise event when changed
+      api.data.raise.changed(data); // raise event
+    },
+
+    removeListeners = function() {
+      _.forEach(data.listeners, function(remove){
+        remove();
+      });
+      data.listeners = [];
+    },
+
+    addListeners = function() {
+      data.listeners = [
+
+        // Listen for new block
+        data.bma.websocket.block().onListener(function(block) {
+          if (!block || data.loading) return;
+          var buid = [block.number, block.hash].join('-');
+          if (data.knownBlocks.indexOf(buid) === -1) {
+            console.debug('[network] Receiving block: ' + buid.substring(0, 20));
+            data.knownBlocks.push(buid);
+            // If first block: do NOT refresh peers (will be done in start() method)
+            var skipRefreshPeers = data.knownBlocks.length === 1;
+            if (!skipRefreshPeers) {
+              data.loading = true;
+              // We wait 2s when a new block is received, just to wait for network propagation
+              $timeout(function() {
+                console.debug('[network] new block received by WS: will refresh peers');
+                loadPeers();
+              }, 2000, false /*invokeApply*/);
             }
-          })
-          .then(function() {
-            console.info('[network] Starting network from [{0}]'.format(bma.server));
-            var now = Date.now();
-
-            addListeners();
-
-            return loadPeers()
-              .then(function(peers){
-                console.debug('[network] Started in '+(Date.now() - now)+'ms');
-                return peers;
+          }
+        }),
+
+        // Listen for new peer
+        data.bma.websocket.peer().onListener(function(json) {
+          if (!json || data.loading) return;
+          var newPeers = [];
+          addOrRefreshPeerFromJson(json, newPeers)
+            .then(function(hasUpdates) {
+              if (!hasUpdates) return;
+              if (newPeers.length>0) {
+                flushNewPeersAndSort(newPeers, true);
+              }
+              else {
+                console.debug('[network] [ws] Peers updated received');
+                sortPeers(true);
+              }
+            });
+        })
+      ];
+    },
+
+    sort = function(options) {
+      options = options || {};
+      data.filter = options.filter ? angular.merge(data.filter, options.filter) : data.filter;
+      data.sort = options.sort ? angular.merge(data.sort, options.sort) : data.sort;
+      sortPeers(false);
+    },
+
+    start = function(bma, options) {
+      options = options || {};
+      return BMA.ready()
+        .then(function() {
+          close();
+
+          data.bma = bma || BMA;
+          data.filter = options.filter ? angular.merge(data.filter, options.filter) : data.filter;
+          data.sort = options.sort ? angular.merge(data.sort, options.sort) : data.sort;
+          data.expertMode = angular.isDefined(options.expertMode) ? options.expertMode : data.expertMode;
+          data.timeout = angular.isDefined(options.timeout) ? options.timeout : csConfig.timeout;
+
+          // Init a min block number
+          data.minOnlineBlockNumber = data.mainBlock && data.mainBlock.buid && (parseInt(data.mainBlock.buid.split('-')[0]) - constants.MAX_BLOCK_OFFSET) || undefined;
+          if (data.minOnlineBlockNumber === undefined) {
+            return csCurrency.blockchain.current(true/*use cache*/)
+              .then(function(current) {
+                data.minOnlineBlockNumber = current.number - constants.MAX_BLOCK_OFFSET;
               });
-          });
-      },
-
-      close = function() {
-        if (data.bma) {
-          console.info('[network-service] Stopping...');
-          removeListeners();
-          resetData();
-        }
-      },
+          }
+        })
+        .then(function() {
+          console.info('[network] Starting network from [{0}]'.format(bma.server));
+          var now = Date.now();
 
-      isStarted = function() {
-        return !data.bma;
-      },
+          addListeners();
 
-      $q_started = function(callback) {
-        if (!isStarted()) { // start first
-          return start()
-            .then(function() {
-              return $q(callback);
+          return loadPeers()
+            .then(function(peers){
+              console.debug('[network] Started in '+(Date.now() - now)+'ms');
+              return peers;
             });
-        }
-        else {
-          return $q(callback);
-        }
-      },
-
-      getMainBlockUid = function() {
-        return $q_started(function(resolve, reject){
-          resolve (data.mainBuid);
         });
-      },
+    },
 
-      // Get peers on the main consensus blocks
-      getTrustedPeers = function() {
-        return $q_started(function(resolve, reject){
-          resolve(data.peers.reduce(function(res, peer){
-            return (peer.hasMainConsensusBlock && peer.uid) ? res.concat(peer) : res;
-          }, []));
-        });
+    close = function() {
+      if (data.bma) {
+        console.info('[network-service] Stopping...');
+        removeListeners();
+        resetData();
       }
-      ;
-
-    // Register extension points
-    api.registerEvent('data', 'changed');
-    api.registerEvent('data', 'mainBlockChanged');
-    api.registerEvent('data', 'rollback');
-
-    return {
-      id: id,
-      data: data,
-      start: start,
-      close: close,
-      hasPeers: hasPeers,
-      getPeers: getPeers,
-      sort: sort,
-      getTrustedPeers: getTrustedPeers,
-      getKnownBlocks: getKnownBlocks,
-      getMainBlockUid: getMainBlockUid,
-      loadPeers: loadPeers,
-      isBusy: isBusy,
-      // api extension
-      api: api
-    };
-  }
-
-  var service = new CsNetwork('default');
-
-  service.instance = function(id) {
-    return new CsNetwork(id);
-  };
+    },
+
+    isStarted = function() {
+      return !data.bma;
+    },
 
-  return service;
+    $q_started = function(callback) {
+      if (!isStarted()) { // start first
+        return start()
+          .then(function() {
+            return $q(callback);
+          });
+      }
+      else {
+        return $q(callback);
+      }
+    },
+
+    getMainBlockUid = function() {
+      return $q_started(function(resolve, reject){
+        resolve (data.mainBuid);
+      });
+    },
+
+    // Get peers on the main consensus blocks
+    getTrustedPeers = function() {
+      return $q_started(function(resolve, reject){
+        resolve(data.peers.reduce(function(res, peer){
+          return (peer.hasMainConsensusBlock && peer.uid) ? res.concat(peer) : res;
+        }, []));
+      });
+    }
+    ;
+
+  // Register extension points
+  api.registerEvent('data', 'changed');
+  api.registerEvent('data', 'mainBlockChanged');
+  api.registerEvent('data', 'rollback');
+
+  return {
+    data: data,
+    start: start,
+    close: close,
+    hasPeers: hasPeers,
+    getPeers: getPeers,
+    sort: sort,
+    getTrustedPeers: getTrustedPeers,
+    getKnownBlocks: getKnownBlocks,
+    getMainBlockUid: getMainBlockUid,
+    loadPeers: loadPeers,
+    isBusy: isBusy,
+    // api extension
+    api: api
+  };
 });
diff --git a/www/js/services/tx-services.js b/www/js/services/tx-services.js
index 6a45626c79d98a679123ffcdf46303232935907b..67979b0ec1f238aca5878628e9c9541631b7a2e6 100644
--- a/www/js/services/tx-services.js
+++ b/www/js/services/tx-services.js
@@ -2,476 +2,462 @@
 angular.module('cesium.tx.services', ['ngApi', 'cesium.bma.services',
   'cesium.settings.services', 'cesium.wot.services' ])
 
-  .factory('csTx', function($q, $timeout, $filter, $translate, FileSaver, UIUtils, BMA, Api,
-                            csConfig, csSettings, csWot, csCurrency) {
-    'ngInject';
-
-    const defaultBMA = BMA;
-
-    function CsTx(id, BMA) {
-
-      BMA = BMA || defaultBMA;
-      var
-        api = new Api(this, "csTx-" + id);
-
-      function reduceTxAndPush(pubkey, txArray, result, processedTxMap, allowPendings) {
-        if (!txArray || !txArray.length) return; // Skip if empty
-
-        _.forEach(txArray, function(tx) {
-          if (tx.block_number !== null || allowPendings) {
-            var walletIsIssuer = false;
-            var otherIssuers = tx.issuers.reduce(function(res, issuer) {
-              walletIsIssuer = walletIsIssuer || (issuer === pubkey);
-              return (issuer !== pubkey) ? res.concat(issuer) : res;
-            }, []);
-            var otherRecipients = [],
-              outputBase,
-              sources = [],
-              lockedOutputs;
-
-            var amount = tx.outputs.reduce(function(sum, output, noffset) {
-              // FIXME duniter v1.4.13
-              var outputArray = (typeof output === 'string') ? output.split(':',3) : [output.amount,output.base,output.conditions];
-              outputBase = parseInt(outputArray[1]);
-              var outputAmount = powBase(parseInt(outputArray[0]), outputBase);
-              var outputCondition = outputArray[2];
-              var sigMatches =  BMA.regexp.TX_OUTPUT_SIG.exec(outputCondition);
-
-              // Simple unlock condition
-              if (sigMatches) {
-                var outputPubkey = sigMatches[1];
-                if (outputPubkey === pubkey) { // output is for the wallet
-                  if (!walletIsIssuer) {
-                    return sum + outputAmount;
-                  }
-                  // If pending: use output as new sources
-                  else if (tx.block_number === null) {
-                    sources.push({
-                      amount: parseInt(outputArray[0]),
-                      base: outputBase,
-                      type: 'T',
-                      identifier: tx.hash,
-                      noffset: noffset,
-                      consumed: false,
-                      conditions: outputCondition
-                    });
-                  }
-                }
-
-                // The output is for someone else
-                else {
-                  // Add into recipients list(if not a issuer)
-                  if (outputPubkey !== '' && !_.contains(otherIssuers, outputPubkey)) {
-                    otherRecipients.push(outputPubkey);
-                  }
-                  if (walletIsIssuer) {
-                    // TODO: should be fix, when TX has multiple issuers (need a repartition)
-                    return sum - outputAmount;
-                  }
-                }
+.factory('csTx', function($q, $timeout, $filter, $translate, FileSaver, UIUtils, BMA, Api,
+                          csConfig, csSettings, csWot, csCurrency) {
+  'ngInject';
+
+  var
+    api = new Api(this, "csTx");
+
+  function reduceTxAndPush(pubkey, txArray, result, processedTxMap, allowPendings) {
+    if (!txArray || !txArray.length) return; // Skip if empty
+
+    _.forEach(txArray, function(tx) {
+      if (tx.block_number !== null || allowPendings) {
+        var walletIsIssuer = false;
+        var otherIssuers = tx.issuers.reduce(function(res, issuer) {
+          walletIsIssuer = walletIsIssuer || (issuer === pubkey);
+          return (issuer !== pubkey) ? res.concat(issuer) : res;
+        }, []);
+        var otherRecipients = [],
+          outputBase,
+          sources = [],
+          lockedOutputs;
+
+        var amount = tx.outputs.reduce(function(sum, output, noffset) {
+          // FIXME duniter v1.4.13
+          var outputArray = (typeof output === 'string') ? output.split(':',3) : [output.amount,output.base,output.conditions];
+          outputBase = parseInt(outputArray[1]);
+          var outputAmount = powBase(parseInt(outputArray[0]), outputBase);
+          var outputCondition = outputArray[2];
+          var sigMatches =  BMA.regexp.TX_OUTPUT_SIG.exec(outputCondition);
+
+          // Simple unlock condition
+          if (sigMatches) {
+            var outputPubkey = sigMatches[1];
+            if (outputPubkey === pubkey) { // output is for the wallet
+              if (!walletIsIssuer) {
+                return sum + outputAmount;
               }
-
-              // Complex unlock condition, on the issuer pubkey
-              else if (outputCondition.indexOf('SIG('+pubkey+')') !== -1) {
-                var lockedOutput = BMA.tx.parseUnlockCondition(outputCondition);
-                if (lockedOutput) {
-                  // Add a source
-                  sources.push(angular.merge({
-                    amount: parseInt(outputArray[0]),
-                    base: outputBase,
-                    type: 'T',
-                    identifier: tx.hash,
-                    noffset: noffset,
-                    conditions: outputCondition,
-                    consumed: false
-                  }, lockedOutput));
-                  lockedOutput.amount = outputAmount;
-                  lockedOutputs = lockedOutputs || [];
-                  lockedOutputs.push(lockedOutput);
-                  console.debug('[tx] has locked output:', lockedOutput);
-
-                  return sum + outputAmount;
-                }
+              // If pending: use output as new sources
+              else if (tx.block_number === null) {
+                sources.push({
+                  amount: parseInt(outputArray[0]),
+                  base: outputBase,
+                  type: 'T',
+                  identifier: tx.hash,
+                  noffset: noffset,
+                  consumed: false,
+                  conditions: outputCondition
+                });
               }
-              return sum;
-            }, 0);
-
-            var txPubkeys = amount > 0 ? otherIssuers : otherRecipients;
-            var time = tx.time || tx.blockstampTime;
-
-            // Avoid duplicated tx, or tx to him self
-            var txKey = amount + ':' + tx.hash + ':' + time;
-            if (!processedTxMap[txKey]) {
-              processedTxMap[txKey] = true; // Mark as processed
-              var newTx = {
-                time: time,
-                amount: amount,
-                pubkey: txPubkeys.length === 1 ? txPubkeys[0] : undefined,
-                pubkeys: txPubkeys.length > 1 ? txPubkeys : undefined,
-                comment: tx.comment,
-                isUD: false,
-                hash: tx.hash,
-                locktime: tx.locktime,
-                block_number: tx.block_number
-              };
-
-                // If pending: store sources and inputs for a later use - see method processTransactionsAndSources()
-              if (walletIsIssuer && tx.block_number === null) {
-                newTx.inputs = tx.inputs;
-                newTx.sources = sources;
+            }
+
+            // The output is for someone else
+            else {
+              // Add into recipients list(if not a issuer)
+              if (outputPubkey !== '' && !_.contains(otherIssuers, outputPubkey)) {
+                otherRecipients.push(outputPubkey);
               }
-              if (lockedOutputs) {
-                newTx.lockedOutputs = lockedOutputs;
+              if (walletIsIssuer) {
+                // TODO: should be fix, when TX has multiple issuers (need a repartition)
+                return sum - outputAmount;
               }
-              result.push(newTx);
             }
           }
-        });
-      }
-
 
-      function loadTx(pubkey, fromTime) {
-        return $q(function(resolve, reject) {
-
-          var nowInSec = moment().utc().unix();
-          fromTime = fromTime || (nowInSec - csSettings.data.walletHistoryTimeSecond);
-          var tx = {
-            pendings: [],
-            validating: [],
-            history: [],
-            errors: []
+          // Complex unlock condition, on the issuer pubkey
+          else if (outputCondition.indexOf('SIG('+pubkey+')') !== -1) {
+            var lockedOutput = BMA.tx.parseUnlockCondition(outputCondition);
+            if (lockedOutput) {
+              // Add a source
+              sources.push(angular.merge({
+                amount: parseInt(outputArray[0]),
+                base: outputBase,
+                type: 'T',
+                identifier: tx.hash,
+                noffset: noffset,
+                conditions: outputCondition,
+                consumed: false
+              }, lockedOutput));
+              lockedOutput.amount = outputAmount;
+              lockedOutputs = lockedOutputs || [];
+              lockedOutputs.push(lockedOutput);
+              console.debug('[tx] has locked output:', lockedOutput);
+
+              return sum + outputAmount;
+            }
+          }
+          return sum;
+        }, 0);
+
+        var txPubkeys = amount > 0 ? otherIssuers : otherRecipients;
+        var time = tx.time || tx.blockstampTime;
+
+        // Avoid duplicated tx, or tx to him self
+        var txKey = amount + ':' + tx.hash + ':' + time;
+        if (!processedTxMap[txKey]) {
+          processedTxMap[txKey] = true; // Mark as processed
+          var newTx = {
+            time: time,
+            amount: amount,
+            pubkey: txPubkeys.length === 1 ? txPubkeys[0] : undefined,
+            pubkeys: txPubkeys.length > 1 ? txPubkeys : undefined,
+            comment: tx.comment,
+            isUD: false,
+            hash: tx.hash,
+            locktime: tx.locktime,
+            block_number: tx.block_number
           };
 
-          var processedTxMap = {};
+            // If pending: store sources and inputs for a later use - see method processTransactionsAndSources()
+          if (walletIsIssuer && tx.block_number === null) {
+            newTx.inputs = tx.inputs;
+            newTx.sources = sources;
+          }
+          if (lockedOutputs) {
+            newTx.lockedOutputs = lockedOutputs;
+          }
+          result.push(newTx);
+        }
+      }
+    });
+  }
 
-          var jobs = [
-            // get current block
-            csCurrency.blockchain.current(true),
 
-            // get pending tx
-            BMA.tx.history.pending({pubkey: pubkey})
-              .then(function (res) {
-                reduceTxAndPush(pubkey, res.history.sending, tx.pendings, processedTxMap, true /*allow pendings*/);
-                reduceTxAndPush(pubkey, res.history.pending, tx.pendings, processedTxMap, true /*allow pendings*/);
-              })
-          ];
-
-          // get TX history since
-          if (fromTime !== 'pending') {
-            var reduceTxFn = function (res) {
-              reduceTxAndPush(pubkey, res.history.sent, tx.history, processedTxMap, false);
-              reduceTxAndPush(pubkey, res.history.received, tx.history, processedTxMap, false);
-            };
-
-            // get TX from a given time
-            if (fromTime > 0) {
-              // Use slice, to be able to cache requests result
-              var sliceTime = csSettings.data.walletHistorySliceSecond;
-              fromTime = fromTime - (fromTime % sliceTime);
-              for(var i = fromTime; i - sliceTime < nowInSec; i += sliceTime)  {
-                jobs.push(BMA.tx.history.times({pubkey: pubkey, from: i, to: i+sliceTime-1}, true /*with cache*/)
-                  .then(reduceTxFn)
-                );
-              }
+  function loadTx(pubkey, fromTime) {
+    return $q(function(resolve, reject) {
 
-              // Last slide: no cache
-              jobs.push(BMA.tx.history.times({pubkey: pubkey, from: nowInSec - (nowInSec % sliceTime), to: nowInSec+999999999}, false/*no cache*/)
-                .then(reduceTxFn));
-            }
+      var nowInSec = moment().utc().unix();
+      fromTime = fromTime || (nowInSec - csSettings.data.walletHistoryTimeSecond);
+      var tx = {
+        pendings: [],
+        validating: [],
+        history: [],
+        errors: []
+      };
 
-            // get all TX
-            else {
-              jobs.push(BMA.tx.history.all({pubkey: pubkey})
-                .then(reduceTxFn)
-              );
-            }
+      var processedTxMap = {};
 
-            // get UD history
-            if (csSettings.data.showUDHistory && fromTime > 0) {
-              /*jobs.push(
-                BMA.ud.history({pubkey: pubkey})
-                  .then(function(res){
-                    udHistory = !res.history || !res.history.history ? [] :
-                      _.forEach(res.history.history, function(ud){
-                        if (ud.time < fromTime) return res; // skip to old UD
-                        var amount = powBase(ud.amount, ud.base);
-                        udHistory.push({
-                          time: ud.time,
-                          amount: amount,
-                          isUD: true,
-                          block_number: ud.block_number
-                        });
-                      });
-                  }));*/
-              // API extension
-              jobs.push(
-                api.data.raisePromise.loadUDs({
-                  pubkey: pubkey,
-                  fromTime: fromTime
-                })
-                  .then(function(res) {
-                    if (!res || !res.length) return;
-                    _.forEach(res, function(hits) {
-                      tx.history.push(hits);
-                    });
-                  })
+      var jobs = [
+        // get current block
+        csCurrency.blockchain.current(true),
 
-                  .catch(function(err) {
-                    console.debug('Error while loading UDs history, on extension point.');
-                    console.error(err);
-                  })
-              );
-            }
+        // get pending tx
+        BMA.tx.history.pending({pubkey: pubkey})
+          .then(function (res) {
+            reduceTxAndPush(pubkey, res.history.sending, tx.pendings, processedTxMap, true /*allow pendings*/);
+            reduceTxAndPush(pubkey, res.history.pending, tx.pendings, processedTxMap, true /*allow pendings*/);
+          })
+      ];
+
+      // get TX history since
+      if (fromTime !== 'pending') {
+        var reduceTxFn = function (res) {
+          reduceTxAndPush(pubkey, res.history.sent, tx.history, processedTxMap, false);
+          reduceTxAndPush(pubkey, res.history.received, tx.history, processedTxMap, false);
+        };
+
+        // get TX from a given time
+        if (fromTime > 0) {
+          // Use slice, to be able to cache requests result
+          var sliceTime = csSettings.data.walletHistorySliceSecond;
+          fromTime = fromTime - (fromTime % sliceTime);
+          for(var i = fromTime; i - sliceTime < nowInSec; i += sliceTime)  {
+            jobs.push(BMA.tx.history.times({pubkey: pubkey, from: i, to: i+sliceTime-1}, true /*with cache*/)
+              .then(reduceTxFn)
+            );
           }
 
-          // Execute jobs
-          $q.all(jobs)
-            .then(function(res){
-              var current = res[0];
-
-              // sort by time desc
-              tx.history.sort(function(tx1, tx2) {
-                return (tx2.time - tx1.time);
-              });
-              var firstValidatedTxIndex = tx.history.findIndex(function(tx){
-                return (tx.block_number <= current.number - csSettings.data.blockValidityWindow);
-              });
-              // remove validating from history
-              tx.validating = firstValidatedTxIndex > 0 ? tx.history.splice(0, firstValidatedTxIndex) : [];
-
-              tx.fromTime = fromTime !== 'pending' && fromTime || undefined;
-              tx.toTime = tx.history.length ? tx.history[0].time /*=max(tx.time)*/: tx.fromTime;
-
-              resolve(tx);
-            })
-            .catch(reject);
-        });
-      }
-
-      function powBase(amount, base) {
-        return base <= 0 ? amount : amount * Math.pow(10, base);
-      }
+          // Last slide: no cache
+          jobs.push(BMA.tx.history.times({pubkey: pubkey, from: nowInSec - (nowInSec % sliceTime), to: nowInSec+999999999}, false/*no cache*/)
+            .then(reduceTxFn));
+        }
 
-      function addSource(src, sources, sourcesIndexByKey) {
-        var srcKey = src.type+':'+src.identifier+':'+src.noffset;
-        if (angular.isUndefined(sourcesIndexByKey[srcKey])) {
-          sources.push(src);
-          sourcesIndexByKey[srcKey] = sources.length - 1;
+        // get all TX
+        else {
+          jobs.push(BMA.tx.history.all({pubkey: pubkey})
+            .then(reduceTxFn)
+          );
         }
-      }
 
-      function addSources(result, sources) {
-        _(sources).forEach(function(src) {
-          addSource(src, result.sources, result.sourcesIndexByKey);
-        });
-      }
+        // get UD history
+        if (csSettings.data.showUDHistory && fromTime > 0) {
+          /*jobs.push(
+            BMA.ud.history({pubkey: pubkey})
+              .then(function(res){
+                udHistory = !res.history || !res.history.history ? [] :
+                  _.forEach(res.history.history, function(ud){
+                    if (ud.time < fromTime) return res; // skip to old UD
+                    var amount = powBase(ud.amount, ud.base);
+                    udHistory.push({
+                      time: ud.time,
+                      amount: amount,
+                      isUD: true,
+                      block_number: ud.block_number
+                    });
+                  });
+              }));*/
+          // API extension
+          jobs.push(
+            api.data.raisePromise.loadUDs({
+              pubkey: pubkey,
+              fromTime: fromTime
+            })
+              .then(function(res) {
+                if (!res || !res.length) return;
+                _.forEach(res, function(hits) {
+                  tx.history.push(hits);
+                });
+              })
 
-      function loadSourcesAndBalance(pubkey) {
-        return BMA.tx.sources({pubkey: pubkey})
-          .then(function(res){
-            var data = {
-              sources: [],
-              sourcesIndexByKey: [],
-              balance: 0
-            };
-            if (res.sources && res.sources.length) {
-              _.forEach(res.sources, function(src) {
-                src.consumed = false;
-                data.balance += powBase(src.amount, src.base);
-              });
-              addSources(data, res.sources);
-            }
-            return data;
-          })
-          .catch(function(err) {
-            console.warn("[tx] Error while getting sources...", err);
-            throw err;
-          });
+              .catch(function(err) {
+                console.debug('Error while loading UDs history, on extension point.');
+                console.error(err);
+              })
+          );
+        }
       }
 
-      function loadData(pubkey, fromTime) {
-        var now = Date.now();
-
-        return $q.all([
-
-          // Load Sources
-          loadSourcesAndBalance(pubkey),
-
-          // Load Tx
-          loadTx(pubkey, fromTime)
-        ])
+      // Execute jobs
+      $q.all(jobs)
+        .then(function(res){
+          var current = res[0];
 
-          .then(function(res) {
-            // Copy sources and balance
-            var data = res[0];
-            data.tx = res[1];
-
-            var txPendings = [];
-            var txErrors = [];
-            var balanceFromSource = data.balance;
-            var balanceWithPending = data.balance;
-
-            function _processPendingTx(tx) {
-              var consumedSources = [];
-              var valid = true;
-              if (tx.amount > 0) { // do not check sources from received TX
-                valid = false;
-                // TODO get sources from the issuer ?
-              }
-              else {
-                _.find(tx.inputs, function(input) {
-                  var inputKey = input.split(':').slice(2).join(':');
-                  var srcIndex = data.sourcesIndexByKey[inputKey];
-                  if (angular.isDefined(srcIndex)) {
-                    consumedSources.push(data.sources[srcIndex]);
-                  }
-                  else {
-                    valid = false;
-                    return true; // break
-                  }
-                });
-                if (tx.sources) { // add source output
-                  addSources(data, tx.sources);
-                }
-                delete tx.sources;
-                delete tx.inputs;
-              }
-              if (valid) {
-                balanceWithPending += tx.amount; // update balance
-                txPendings.push(tx);
-                _.forEach(consumedSources, function(src) {
-                  src.consumed=true;
-                });
-              }
-              else {
-                txErrors.push(tx);
-              }
-            }
-
-            var txs = data.tx.pendings;
-            var retry = true;
-            while(txs && txs.length) {
-              // process TX pendings
-              _.forEach(txs, _processPendingTx);
-
-              // Retry once (TX could be chained and processed in a wrong order)
-              if (txErrors.length > 0 && txPendings.length > 0 && retry) {
-                txs = txErrors;
-                txErrors = [];
-                retry = false;
+          // sort by time desc
+          tx.history.sort(function(tx1, tx2) {
+            return (tx2.time - tx1.time);
+          });
+          var firstValidatedTxIndex = tx.history.findIndex(function(tx){
+            return (tx.block_number <= current.number - csSettings.data.blockValidityWindow);
+          });
+          // remove validating from history
+          tx.validating = firstValidatedTxIndex > 0 ? tx.history.splice(0, firstValidatedTxIndex) : [];
+
+          tx.fromTime = fromTime !== 'pending' && fromTime || undefined;
+          tx.toTime = tx.history.length ? tx.history[0].time /*=max(tx.time)*/: tx.fromTime;
+
+          resolve(tx);
+        })
+        .catch(reject);
+    });
+  }
+
+  function powBase(amount, base) {
+    return base <= 0 ? amount : amount * Math.pow(10, base);
+  }
+
+  function addSource(src, sources, sourcesIndexByKey) {
+    var srcKey = src.type+':'+src.identifier+':'+src.noffset;
+    if (angular.isUndefined(sourcesIndexByKey[srcKey])) {
+      sources.push(src);
+      sourcesIndexByKey[srcKey] = sources.length - 1;
+    }
+  }
+
+  function addSources(result, sources) {
+    _(sources).forEach(function(src) {
+      addSource(src, result.sources, result.sourcesIndexByKey);
+    });
+  }
+
+  function loadSourcesAndBalance(pubkey) {
+    return BMA.tx.sources({pubkey: pubkey})
+      .then(function(res){
+        var data = {
+          sources: [],
+          sourcesIndexByKey: [],
+          balance: 0
+        };
+        if (res.sources && res.sources.length) {
+          _.forEach(res.sources, function(src) {
+            src.consumed = false;
+            data.balance += powBase(src.amount, src.base);
+          });
+          addSources(data, res.sources);
+        }
+        return data;
+      })
+      .catch(function(err) {
+        console.warn("[tx] Error while getting sources...", err);
+        throw err;
+      });
+  }
+
+  function loadData(pubkey, fromTime) {
+    var now = Date.now();
+
+    return $q.all([
+
+      // Load Sources
+      loadSourcesAndBalance(pubkey),
+
+      // Load Tx
+      loadTx(pubkey, fromTime)
+    ])
+
+      .then(function(res) {
+        // Copy sources and balance
+        var data = res[0];
+        data.tx = res[1];
+
+        var txPendings = [];
+        var txErrors = [];
+        var balanceFromSource = data.balance;
+        var balanceWithPending = data.balance;
+
+        function _processPendingTx(tx) {
+          var consumedSources = [];
+          var valid = true;
+          if (tx.amount > 0) { // do not check sources from received TX
+            valid = false;
+            // TODO get sources from the issuer ?
+          }
+          else {
+            _.find(tx.inputs, function(input) {
+              var inputKey = input.split(':').slice(2).join(':');
+              var srcIndex = data.sourcesIndexByKey[inputKey];
+              if (angular.isDefined(srcIndex)) {
+                consumedSources.push(data.sources[srcIndex]);
               }
               else {
-                txs = null;
+                valid = false;
+                return true; // break
               }
-            }
-
-            data.tx = data.tx || {};
-            data.tx.pendings = txPendings.sort(function(tx1, tx2) {
-              return (tx2.time - tx1.time);
             });
-            data.tx.errors = txErrors.sort(function(tx1, tx2) {
-              return (tx2.time - tx1.time);
+            if (tx.sources) { // add source output
+              addSources(data, tx.sources);
+            }
+            delete tx.sources;
+            delete tx.inputs;
+          }
+          if (valid) {
+            balanceWithPending += tx.amount; // update balance
+            txPendings.push(tx);
+            _.forEach(consumedSources, function(src) {
+              src.consumed=true;
             });
-            // Negative balance not allow (use only source's balance) - fix #769
-            data.balance = (balanceWithPending < 0) ? balanceFromSource : balanceWithPending;
-
-            // Will add uid (+ plugin will add name, avatar, etc. if enable)
-            var allTx = (data.tx.history || []).concat(data.tx.validating||[], data.tx.pendings||[], data.tx.errors||[]);
-            return csWot.extendAll(allTx, 'pubkey')
-              .then(function() {
-                console.debug('[tx] TX and sources loaded in '+ (Date.now()-now) +'ms');
-                return data;
-              });
-          })
-          .catch(function(err) {
-            console.warn("[tx] Error while getting sources and tx...", err);
-            throw err;
-          });
-      }
-
-      function loadSources(pubkey) {
-        console.debug("[tx] Loading sources for " + pubkey.substring(0,8));
-        return loadData(pubkey, 'pending');
-      }
+          }
+          else {
+            txErrors.push(tx);
+          }
+        }
 
-      // Download TX history file
-      function downloadHistoryFile(pubkey, options) {
-
-        options = options || {};
-        options.fromTime = options.fromTime || -1;
-
-        console.debug("[tx] Exporting TX history for pubkey [{0}]".format(pubkey.substr(0,8)));
-
-        return $q.all([
-          $translate(['ACCOUNT.HEADERS.TIME',
-            'COMMON.UID',
-            'COMMON.PUBKEY',
-            'COMMON.UNIVERSAL_DIVIDEND',
-            'ACCOUNT.HEADERS.AMOUNT',
-            'ACCOUNT.HEADERS.COMMENT']),
-          csCurrency.blockchain.current(true/*withCache*/),
-          loadData(pubkey, options.fromTime)
-        ])
-          .then(function(result){
-            var translations = result[0];
-            var currentBlock = result[1];
-            var currentTime = (currentBlock && currentBlock.medianTime) || moment().utc().unix();
-            var currency = currentBlock && currentBlock.currency;
-
-            var data = result[2];
-
-            // no TX
-            if (!data || !data.tx || !data.tx.history) {
-              return UIUtils.toast.show('INFO.EMPTY_TX_HISTORY');
-            }
+        var txs = data.tx.pendings;
+        var retry = true;
+        while(txs && txs.length) {
+          // process TX pendings
+          _.forEach(txs, _processPendingTx);
+
+          // Retry once (TX could be chained and processed in a wrong order)
+          if (txErrors.length > 0 && txPendings.length > 0 && retry) {
+            txs = txErrors;
+            txErrors = [];
+            retry = false;
+          }
+          else {
+            txs = null;
+          }
+        }
 
-            return $translate('ACCOUNT.FILE_NAME', {currency: currency, pubkey: pubkey, currentTime : currentTime})
-              .then(function(filename){
-
-                var formatDecimal = $filter('formatDecimal');
-                var medianDate = $filter('medianDate');
-                var formatSymbol = $filter('currencySymbolNoHtml');
-
-                var headers = [
-                  translations['ACCOUNT.HEADERS.TIME'],
-                  translations['COMMON.UID'],
-                  translations['COMMON.PUBKEY'],
-                  translations['ACCOUNT.HEADERS.AMOUNT'] + ' (' + formatSymbol(currency) + ')',
-                  translations['ACCOUNT.HEADERS.COMMENT']
-                ];
-                var content = data.tx.history.concat(data.tx.validating).reduce(function(res, tx){
-                  return res.concat([
-                    medianDate(tx.time),
-                    tx.uid,
-                    tx.pubkey,
-                    formatDecimal(tx.amount/100),
-                    '"' + (tx.isUD ? translations['COMMON.UNIVERSAL_DIVIDEND'] : tx.comment) + '"'
-                  ].join(';') + '\n');
-                }, [headers.join(';') + '\n']);
-
-                var file = new Blob(content, {type: 'text/plain; charset=utf-8'});
-                FileSaver.saveAs(file, filename);
-              });
+        data.tx = data.tx || {};
+        data.tx.pendings = txPendings.sort(function(tx1, tx2) {
+          return (tx2.time - tx1.time);
+        });
+        data.tx.errors = txErrors.sort(function(tx1, tx2) {
+          return (tx2.time - tx1.time);
+        });
+        // Negative balance not allow (use only source's balance) - fix #769
+        data.balance = (balanceWithPending < 0) ? balanceFromSource : balanceWithPending;
+
+        // Will add uid (+ plugin will add name, avatar, etc. if enable)
+        var allTx = (data.tx.history || []).concat(data.tx.validating||[], data.tx.pendings||[], data.tx.errors||[]);
+        return csWot.extendAll(allTx, 'pubkey')
+          .then(function() {
+            console.debug('[tx] TX and sources loaded in '+ (Date.now()-now) +'ms');
+            return data;
           });
-      }
-
-      // Register extension points
-      api.registerEvent('data', 'loadUDs');
-
-      return {
-        id: id,
-        load: loadData,
-        loadSources: loadSources,
-        downloadHistoryFile: downloadHistoryFile,
-        // api extension
-        api: api
-      };
-    }
-
-    var service = new CsTx('default');
+      })
+      .catch(function(err) {
+        console.warn("[tx] Error while getting sources and tx...", err);
+        throw err;
+      });
+  }
+
+  function loadSources(pubkey) {
+    console.debug("[tx] Loading sources for " + pubkey.substring(0,8));
+    return loadData(pubkey, 'pending');
+  }
+
+  // Download TX history file
+  function downloadHistoryFile(pubkey, options) {
+
+    options = options || {};
+    options.fromTime = options.fromTime || -1;
+
+    console.debug("[tx] Exporting TX history for pubkey [{0}]".format(pubkey.substr(0,8)));
+
+    return $q.all([
+      $translate(['ACCOUNT.HEADERS.TIME',
+        'COMMON.UID',
+        'COMMON.PUBKEY',
+        'COMMON.UNIVERSAL_DIVIDEND',
+        'ACCOUNT.HEADERS.AMOUNT',
+        'ACCOUNT.HEADERS.COMMENT']),
+      csCurrency.blockchain.current(true/*withCache*/),
+      loadData(pubkey, options.fromTime)
+    ])
+      .then(function(result){
+        var translations = result[0];
+        var currentBlock = result[1];
+        var currentTime = (currentBlock && currentBlock.medianTime) || moment().utc().unix();
+        var currency = currentBlock && currentBlock.currency;
+
+        var data = result[2];
+
+        // no TX
+        if (!data || !data.tx || !data.tx.history) {
+          return UIUtils.toast.show('INFO.EMPTY_TX_HISTORY');
+        }
 
-    service.instance = function(id, bma) {
-      return new CsTx(id, bma);
-    };
-    return service;
-  });
+        return $translate('ACCOUNT.FILE_NAME', {currency: currency, pubkey: pubkey, currentTime : currentTime})
+          .then(function(filename){
+
+            var formatDecimal = $filter('formatDecimal');
+            var medianDate = $filter('medianDate');
+            var formatSymbol = $filter('currencySymbolNoHtml');
+
+            var headers = [
+              translations['ACCOUNT.HEADERS.TIME'],
+              translations['COMMON.UID'],
+              translations['COMMON.PUBKEY'],
+              translations['ACCOUNT.HEADERS.AMOUNT'] + ' (' + formatSymbol(currency) + ')',
+              translations['ACCOUNT.HEADERS.COMMENT']
+            ];
+            var content = data.tx.history.concat(data.tx.validating).reduce(function(res, tx){
+              return res.concat([
+                medianDate(tx.time),
+                tx.uid,
+                tx.pubkey,
+                formatDecimal(tx.amount/100),
+                '"' + (tx.isUD ? translations['COMMON.UNIVERSAL_DIVIDEND'] : tx.comment) + '"'
+              ].join(';') + '\n');
+            }, [headers.join(';') + '\n']);
+
+            var file = new Blob(content, {type: 'text/plain; charset=utf-8'});
+            FileSaver.saveAs(file, filename);
+          });
+      });
+  }
+
+  // Register extension points
+  api.registerEvent('data', 'loadUDs');
+
+  return {
+    load: loadData,
+    loadSources: loadSources,
+    downloadHistoryFile: downloadHistoryFile,
+    // api extension
+    api: api
+  };
+});
diff --git a/www/js/services/wallet-services.js b/www/js/services/wallet-services.js
index b1f9b5aa0683396a14aaacf7e1daa150428a4222..ba6f8cf37583550548737b0c86edc59fd8abeb5f 100644
--- a/www/js/services/wallet-services.js
+++ b/www/js/services/wallet-services.js
@@ -11,7 +11,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
   var defaultBMA = BMA;
   var service;
 
-  function csWallet(id, BMA) {
+  function CsWallet(id, BMA) {
 
     BMA = BMA || defaultBMA;
     var
@@ -2450,8 +2450,8 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
     return exports;
   }
 
-  service = csWallet('default', BMA);
-  service.instance = csWallet;
+  service = CsWallet('default', BMA);
+  service.instance = CsWallet;
 
   return service;
 });
diff --git a/www/js/services/wot-services.js b/www/js/services/wot-services.js
index 4ad2f3f9850ed7a233e7b90a2aaa2a13cc036caa..98511b3e13a2c1b35fdcf8e2e1aa415d0f8327a8 100644
--- a/www/js/services/wot-services.js
+++ b/www/js/services/wot-services.js
@@ -5,1212 +5,1204 @@ angular.module('cesium.wot.services', ['ngApi', 'cesium.bma.services', 'cesium.c
 .factory('csWot', function($rootScope, $q, $timeout, BMA, Api, CacheFactory, csConfig, csCurrency, csSettings, csCache) {
   'ngInject';
 
-  function csWot(id) {
-
-    var
-      api = new Api(this, "csWot-" + id),
-      cachePrefix = 'csWot-',
-      identityCache = csCache.get(cachePrefix + 'idty-', csCache.constants.MEDIUM),
-      requirementsCache = csCache.get(cachePrefix + 'requirements-', csCache.constants.MEDIUM),
-
-      // Add id, and remove duplicated id
-      _addUniqueIds = function(idties) {
-        var idtyKeys = {};
-        return idties.reduce(function(res, idty) {
-          idty.id = idty.id || idty.uid + '-' + idty.pubkey;
-          if (!idtyKeys[idty.id]) {
-            idtyKeys[idty.id] = true;
-            return res.concat(idty);
-          }
-          return res;
-        }, []);
-      },
-
-      _sortAndSliceIdentities = function(idties, offset, size) {
-        offset = offset || 0;
-
-        // Add unique ids
-        idties = _addUniqueIds(idties);
-
-        // Sort by block and
-        idties = _.sortBy(idties, function(idty){
-          var score = 1;
-          score += (1000000 * (idty.block));
-          score += (10      * (900 - idty.uid.toLowerCase().charCodeAt(0)));
-          return -score;
-        });
-        if (angular.isDefined(size) && idties.length > size) {
-          idties = idties.slice(offset, offset+size); // limit if more than expected size
-        }
-
 
-        return idties;
-      },
-
-      _sortCertifications = function(certifications) {
-        certifications = _.sortBy(certifications, function(cert){
-          var score = 1;
-          score += (1000000000000 * (cert.expiresIn ? cert.expiresIn : 0));
-          score += (10000000      * (cert.isMember ? 1 : 0));
-          score += (10            * (cert.block ? cert.block : 0));
-          return -score;
-        });
-        return certifications;
-      },
-
-      _resetRequirements = function(data) {
-        data.requirements = {
-          loaded: false,
-          meta: {},
-          hasSelf: false,
-          needSelf: true,
-          needMembership: true,
-          canMembershipOut: false,
-          needRenew: false,
-          pendingMembership: false,
-          isMember: false,
-          wasMember: false,
-          certificationCount: 0,
-          needCertifications: false,
-          needCertificationCount: 0,
-          willNeedCertificationCount: 0,
-          alternatives: undefined
-        };
-        data.blockUid = null;
-        data.isMember = false;
-        data.sigDate = null;
-        data.hasSelf = false;
-      },
-
-      _fillRequirements = function(requirements, currencyParameters) {
-        // Add useful custom fields
-        requirements.hasSelf = !!requirements.meta.timestamp;
-        requirements.needSelf = !requirements.hasSelf || requirements.meta.invalid;
-        requirements.wasMember = angular.isDefined(requirements.wasMember) ? requirements.wasMember : false; // Compat with Duniter 0.9
-        requirements.needMembership = (!requirements.revoked && requirements.membershipExpiresIn <= 0 && requirements.membershipPendingExpiresIn <= 0 && !requirements.wasMember);
-        requirements.needRenew = (!requirements.needMembership && !requirements.revoked &&
-          requirements.membershipExpiresIn <= csSettings.data.timeWarningExpireMembership &&
-          requirements.membershipPendingExpiresIn <= 0) ||
-          (requirements.wasMember && !requirements.revoked && requirements.membershipExpiresIn === 0 &&
-          requirements.membershipPendingExpiresIn === 0);
-        requirements.canMembershipOut = (!requirements.revoked && requirements.membershipExpiresIn > 0);
-        requirements.pendingMembership = (!requirements.revoked && requirements.membershipExpiresIn <= 0 && requirements.membershipPendingExpiresIn > 0);
-        requirements.isMember = (!requirements.revoked && 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.wasMember && !requirements.expired)) && 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;
-        //requirements.outdistanced = requirements.outdistanced; // outdistanced is always present in requirement - see #777
-
-        // 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 ;
+  var
+    api = new Api(this, "csWot"),
+    cachePrefix = 'csWot-',
+    identityCache = csCache.get(cachePrefix + 'idty-', csCache.constants.MEDIUM),
+    requirementsCache = csCache.get(cachePrefix + 'requirements-', csCache.constants.MEDIUM),
+
+    // Add id, and remove duplicated id
+    _addUniqueIds = function(idties) {
+      var idtyKeys = {};
+      return idties.reduce(function(res, idty) {
+        idty.id = idty.id || idty.uid + '-' + idty.pubkey;
+        if (!idtyKeys[idty.id]) {
+          idtyKeys[idty.id] = true;
+          return res.concat(idty);
         }
+        return res;
+      }, []);
+    },
+
+    _sortAndSliceIdentities = function(idties, offset, size) {
+      offset = offset || 0;
+
+      // Add unique ids
+      idties = _addUniqueIds(idties);
+
+      // Sort by block and
+      idties = _.sortBy(idties, function(idty){
+        var score = 1;
+        score += (1000000 * (idty.block));
+        score += (10      * (900 - idty.uid.toLowerCase().charCodeAt(0)));
+        return -score;
+      });
+      if (angular.isDefined(size) && idties.length > size) {
+        idties = idties.slice(offset, offset+size); // limit if more than expected size
+      }
 
-        // 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;
-
-        // Mark as loaded - need by csWallet.isDataLoaded()
-        requirements.loaded = true;
-
-
-        return requirements;
-      },
 
-      _fillIdentitiesMeta = function(identities) {
-        if (!identities) return $q.when(identities);
+      return idties;
+    },
+
+    _sortCertifications = function(certifications) {
+      certifications = _.sortBy(certifications, function(cert){
+        var score = 1;
+        score += (1000000000000 * (cert.expiresIn ? cert.expiresIn : 0));
+        score += (10000000      * (cert.isMember ? 1 : 0));
+        score += (10            * (cert.block ? cert.block : 0));
+        return -score;
+      });
+      return certifications;
+    },
+
+    _resetRequirements = function(data) {
+      data.requirements = {
+        loaded: false,
+        meta: {},
+        hasSelf: false,
+        needSelf: true,
+        needMembership: true,
+        canMembershipOut: false,
+        needRenew: false,
+        pendingMembership: false,
+        isMember: false,
+        wasMember: false,
+        certificationCount: 0,
+        needCertifications: false,
+        needCertificationCount: 0,
+        willNeedCertificationCount: 0,
+        alternatives: undefined
+      };
+      data.blockUid = null;
+      data.isMember = false;
+      data.sigDate = null;
+      data.hasSelf = false;
+    },
+
+    _fillRequirements = function(requirements, currencyParameters) {
+      // Add useful custom fields
+      requirements.hasSelf = !!requirements.meta.timestamp;
+      requirements.needSelf = !requirements.hasSelf || requirements.meta.invalid;
+      requirements.wasMember = angular.isDefined(requirements.wasMember) ? requirements.wasMember : false; // Compat with Duniter 0.9
+      requirements.needMembership = (!requirements.revoked && requirements.membershipExpiresIn <= 0 && requirements.membershipPendingExpiresIn <= 0 && !requirements.wasMember);
+      requirements.needRenew = (!requirements.needMembership && !requirements.revoked &&
+        requirements.membershipExpiresIn <= csSettings.data.timeWarningExpireMembership &&
+        requirements.membershipPendingExpiresIn <= 0) ||
+        (requirements.wasMember && !requirements.revoked && requirements.membershipExpiresIn === 0 &&
+        requirements.membershipPendingExpiresIn === 0);
+      requirements.canMembershipOut = (!requirements.revoked && requirements.membershipExpiresIn > 0);
+      requirements.pendingMembership = (!requirements.revoked && requirements.membershipExpiresIn <= 0 && requirements.membershipPendingExpiresIn > 0);
+      requirements.isMember = (!requirements.revoked && 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.wasMember && !requirements.expired)) && 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;
+      //requirements.outdistanced = requirements.outdistanced; // outdistanced is always present in requirement - see #777
+
+      // 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 ;
+      }
 
-        var blocks = [];
-        _.forEach(identities, function(identity) {
-          var blockUid = identity.meta.timestamp.split('-', 2);
-          identity.meta.number = parseInt(blockUid[0]);
-          identity.meta.hash = blockUid[1];
-          identity.meta.sig = identity.meta.sig || identity.sig;
-          delete identity.sig;
-          blocks.push(identity.meta.number);
-        });
+      // 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;
+
+      // Mark as loaded - need by csWallet.isDataLoaded()
+      requirements.loaded = true;
+
+
+      return requirements;
+    },
+
+    _fillIdentitiesMeta = function(identities) {
+      if (!identities) return $q.when(identities);
+
+      var blocks = [];
+      _.forEach(identities, function(identity) {
+        var blockUid = identity.meta.timestamp.split('-', 2);
+        identity.meta.number = parseInt(blockUid[0]);
+        identity.meta.hash = blockUid[1];
+        identity.meta.sig = identity.meta.sig || identity.sig;
+        delete identity.sig;
+        blocks.push(identity.meta.number);
+      });
+
+      // Get identities blocks, to fill self and revocation time
+      return BMA.blockchain.blocks(_.uniq(blocks))
+        .then(function(blocks) {
+          _.forEach(identities, function(identity) {
+            var block = _.findWhere(blocks, {number: identity.meta.number});
+            identity.meta.time = block && block.medianTime;
+
+            // Check if self has been done on a valid block
+            if (block && identity.meta.number !== 0 && identity.meta.hash !== block.hash) {
+              identity.meta.invalid = true;
+            }
+          });
 
-        // Get identities blocks, to fill self and revocation time
-        return BMA.blockchain.blocks(_.uniq(blocks))
-          .then(function(blocks) {
+          return identities;
+        })
+        .catch(function(err){
+          // Special case for currency init (root block not exists): use now
+          if (err && err.ucode == BMA.errorCodes.BLOCK_NOT_FOUND) {
             _.forEach(identities, function(identity) {
-              var block = _.findWhere(blocks, {number: identity.meta.number});
-              identity.meta.time = block && block.medianTime;
-
-              // Check if self has been done on a valid block
-              if (block && identity.meta.number !== 0 && identity.meta.hash !== block.hash) {
-                identity.meta.invalid = true;
+              if (identity.number === 0) {
+                identity.meta.time = moment().utc().unix();
               }
             });
-
             return identities;
-          })
-          .catch(function(err){
-            // Special case for currency init (root block not exists): use now
-            if (err && err.ucode == BMA.errorCodes.BLOCK_NOT_FOUND) {
-              _.forEach(identities, function(identity) {
-                if (identity.number === 0) {
-                  identity.meta.time = moment().utc().unix();
-                }
-              });
-              return identities;
-            }
-            else {
-              throw err;
-            }
-          });
-      },
-
-      loadRequirements = function(inputData, withCache) {
-        if (!inputData || (!inputData.pubkey && !inputData.uid)) return $q.when(inputData);
-
-        var cacheKey =  inputData.pubkey||inputData.uid;
-        var data = (withCache !== false) ? requirementsCache.get(cacheKey) : null;
-        if (data) {
-          console.debug("[wot] Requirements " + cacheKey + " found in cache");
-          // Update data with cache
-          angular.merge(inputData, data);
-          return $q.when(data);
-        }
-        data = {pubkey: inputData.pubkey, uid: inputData.uid};
+          }
+          else {
+            throw err;
+          }
+        });
+    },
+
+    loadRequirements = function(inputData, withCache) {
+      if (!inputData || (!inputData.pubkey && !inputData.uid)) return $q.when(inputData);
+
+      var cacheKey =  inputData.pubkey||inputData.uid;
+      var data = (withCache !== false) ? requirementsCache.get(cacheKey) : null;
+      if (data) {
+        console.debug("[wot] Requirements " + cacheKey + " found in cache");
+        // Update data with cache
+        angular.merge(inputData, data);
+        return $q.when(data);
+      }
+      data = {pubkey: inputData.pubkey, uid: inputData.uid};
 
-        var now = Date.now();
+      var now = Date.now();
 
-        return $q.all([
-          // Get currency
-          csCurrency.get(),
+      return $q.all([
+        // Get currency
+        csCurrency.get(),
 
-          // Get requirements
-          BMA.wot.requirements({pubkey: data.pubkey||data.uid}, false/*no cache*/)
-            .then(function(res) {
-              return _fillIdentitiesMeta(res && res.identities);
-            })
-        ])
-          .then(function(res){
-            var currency = res[0];
-            var identities = res[1];
-
-            if (!identities || !identities.length) return;
-
-            // Sort to select the best identity
-            if (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
-              identities = _.sortBy(identities, function(idty) {
-                var score = 0;
-                score += (1000000000000* ((data.uid && idty.uid === data.uid) ? 1 : 0));
-                score += (100000000000 * (!idty.meta.invalid ? 1 : 0));
-                score += (10000000000  * ((data.blockUid && idty.meta.timestamp && 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('[wot] Found {0} identities (in requirements). Will selected the best one'.format(identities.length));
-            }
+        // Get requirements
+        BMA.wot.requirements({pubkey: data.pubkey||data.uid}, false/*no cache*/)
+          .then(function(res) {
+            return _fillIdentitiesMeta(res && res.identities);
+          })
+      ])
+        .then(function(res){
+          var currency = res[0];
+          var identities = res[1];
+
+          if (!identities || !identities.length) return;
+
+          // Sort to select the best identity
+          if (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
+            identities = _.sortBy(identities, function(idty) {
+              var score = 0;
+              score += (1000000000000* ((data.uid && idty.uid === data.uid) ? 1 : 0));
+              score += (100000000000 * (!idty.meta.invalid ? 1 : 0));
+              score += (10000000000  * ((data.blockUid && idty.meta.timestamp && 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('[wot] Found {0} identities (in requirements). Will selected the best one'.format(identities.length));
+          }
 
-            // Select the first identity
-            data.requirements = _fillRequirements(identities[0], currency.parameters);
-
-            // Copy some useful properties into data
-            data.pubkey = data.requirements.pubkey;
-            data.uid = data.requirements.uid;
-            data.isMember =  data.requirements.isMember;
-            data.blockUid =  data.requirements.meta &&  data.requirements.meta.timestamp;
-            data.hasSelf =  data.requirements.hasSelf;
-            data.sigDate =  data.requirements.meta && data.requirements.meta.time;
-
-            // Prepare alternatives identities if any
-            if (!data.requirements.isMember && !data.requirements.wasMember && identities.length > 1) {
-              data.requirements.alternatives = identities.splice(1);
-              _.forEach(data.requirements.alternatives, function(requirements) {
-                _fillRequirements(requirements, currency.parameters);
-              });
-            }
+          // Select the first identity
+          data.requirements = _fillRequirements(identities[0], currency.parameters);
+
+          // Copy some useful properties into data
+          data.pubkey = data.requirements.pubkey;
+          data.uid = data.requirements.uid;
+          data.isMember =  data.requirements.isMember;
+          data.blockUid =  data.requirements.meta &&  data.requirements.meta.timestamp;
+          data.hasSelf =  data.requirements.hasSelf;
+          data.sigDate =  data.requirements.meta && data.requirements.meta.time;
+
+          // Prepare alternatives identities if any
+          if (!data.requirements.isMember && !data.requirements.wasMember && identities.length > 1) {
+            data.requirements.alternatives = identities.splice(1);
+            _.forEach(data.requirements.alternatives, function(requirements) {
+              _fillRequirements(requirements, currency.parameters);
+            });
+          }
 
-            /// Save to cache
-            requirementsCache.put(cacheKey, data);
+          /// Save to cache
+          requirementsCache.put(cacheKey, data);
 
-            angular.merge(inputData, data); // Update the input data
+          angular.merge(inputData, data); // Update the input data
 
-            console.debug("[wot] Requirements for '{0}' loaded in {1}ms".format((data.pubkey && data.pubkey.substring(0,8))||data.uid, Date.now() - now));
+          console.debug("[wot] Requirements for '{0}' loaded in {1}ms".format((data.pubkey && data.pubkey.substring(0,8))||data.uid, Date.now() - now));
 
+          return inputData;
+        })
+        .catch(function(err) {
+          _resetRequirements(inputData);
+          // If not a member: continue
+          if (!!err &&
+              (err.ucode == BMA.errorCodes.NO_MATCHING_MEMBER ||
+               err.ucode == BMA.errorCodes.NO_IDTY_MATCHING_PUB_OR_UID)) {
+            inputData.requirements.loaded = true;
             return inputData;
-          })
-          .catch(function(err) {
-            _resetRequirements(inputData);
-            // If not a member: continue
-            if (!!err &&
-                (err.ucode == BMA.errorCodes.NO_MATCHING_MEMBER ||
-                 err.ucode == BMA.errorCodes.NO_IDTY_MATCHING_PUB_OR_UID)) {
-              inputData.requirements.loaded = true;
-              return inputData;
-            }
-            throw err;
-          });
-      },
-
-
-
-      loadIdentityByLookup = function(pubkey, uid) {
-        var data = {
-          pubkey: pubkey,
-          uid: uid,
-          hasSelf: false
-        };
-        return BMA.wot.lookup({ search: pubkey||uid })
-          .then(function(res){
-            var identities = res.results.reduce(function(idties, res) {
-              return idties.concat(res.uids.reduce(function(uids, idty) {
-                var blockUid = idty.meta.timestamp.split('-', 2);
-                var blockNumber = parseInt(blockUid[0]);
-                return uids.concat({
-                  uid: idty.uid,
-                  pubkey: res.pubkey,
-                  meta: {
-                    timestamp: idty.meta.timestamp,
-                    number: blockNumber,
-                    hash: blockUid[1],
-                    sig: idty.self
-                  },
-                  revoked: idty.revoked,
-                  revoked_on: idty.revoked_on
-                });
-              }, []));
-            }, []);
-
-            // Fill identities meta (self)
-            return _fillIdentitiesMeta(identities)
-              .then(function(identities) {
-                return {
-                  identities: identities,
-                  results: res.results
-                };
-              });
-          })
-          .then(function(res){
-            var identities = res.identities;
-
-            // Sort identities if need
-            if (identities.length > 1) {
-              // Select the best identity, by sorting using this order
-              //  - valid block
-              //  - same given uid
-              //  - not revoked
-              //  - max(block_number)
-              res.identities = _.sortBy(identities, function(idty) {
-                var score = 0;
-                score += (100000000000 * ((data.uid && idty.uid === data.uid) ? 1 : 0));
-                score += (10000000000  * (!idty.meta.invalid ? 1 : 0));
-                score += (1000000000  * ((data.blockUid && idty.meta.timestamp && idty.meta.timestamp === data.blockUid) ? 1 : 0));
-                score += (100000000   * (!idty.revoked ? 1 : 0));
-                score += (1            * (idty.meta.number ? idty.meta.number : 0) / 1000);
-                return -score;
+          }
+          throw err;
+        });
+    },
+
+
+
+    loadIdentityByLookup = function(pubkey, uid) {
+      var data = {
+        pubkey: pubkey,
+        uid: uid,
+        hasSelf: false
+      };
+      return BMA.wot.lookup({ search: pubkey||uid })
+        .then(function(res){
+          var identities = res.results.reduce(function(idties, res) {
+            return idties.concat(res.uids.reduce(function(uids, idty) {
+              var blockUid = idty.meta.timestamp.split('-', 2);
+              var blockNumber = parseInt(blockUid[0]);
+              return uids.concat({
+                uid: idty.uid,
+                pubkey: res.pubkey,
+                meta: {
+                  timestamp: idty.meta.timestamp,
+                  number: blockNumber,
+                  hash: blockUid[1],
+                  sig: idty.self
+                },
+                revoked: idty.revoked,
+                revoked_on: idty.revoked_on
               });
-              console.debug('[wot] Found {0} identities (in lookup). Will selected the best one'.format(identities.length));
-            }
+            }, []));
+          }, []);
 
-            // Prepare alternatives identities
-            _.forEach(identities, function(idty) {
-              idty.hasSelf = !!(idty.uid && idty.meta.timestamp && idty.meta.sig);
+          // Fill identities meta (self)
+          return _fillIdentitiesMeta(identities)
+            .then(function(identities) {
+              return {
+                identities: identities,
+                results: res.results
+              };
+            });
+        })
+        .then(function(res){
+          var identities = res.identities;
+
+          // Sort identities if need
+          if (identities.length > 1) {
+            // Select the best identity, by sorting using this order
+            //  - valid block
+            //  - same given uid
+            //  - not revoked
+            //  - max(block_number)
+            res.identities = _.sortBy(identities, function(idty) {
+              var score = 0;
+              score += (100000000000 * ((data.uid && idty.uid === data.uid) ? 1 : 0));
+              score += (10000000000  * (!idty.meta.invalid ? 1 : 0));
+              score += (1000000000  * ((data.blockUid && idty.meta.timestamp && idty.meta.timestamp === data.blockUid) ? 1 : 0));
+              score += (100000000   * (!idty.revoked ? 1 : 0));
+              score += (1            * (idty.meta.number ? idty.meta.number : 0) / 1000);
+              return -score;
             });
+            console.debug('[wot] Found {0} identities (in lookup). Will selected the best one'.format(identities.length));
+          }
 
-            // Select the first identity
-            data.requirements = identities[0];
+          // Prepare alternatives identities
+          _.forEach(identities, function(idty) {
+            idty.hasSelf = !!(idty.uid && idty.meta.timestamp && idty.meta.sig);
+          });
 
-            // Copy some useful properties into data
-            data.pubkey = data.requirements.pubkey;
-            data.uid = data.requirements.uid;
-            data.blockUid = data.requirements.meta && data.requirements.meta.timestamp;
-            data.hasSelf = data.requirements.hasSelf;
-            data.sigDate =  data.requirements.meta && data.requirements.meta.time;
+          // Select the first identity
+          data.requirements = identities[0];
 
-            if (identities.length > 1) {
-              data.requirements.alternatives = identities.splice(1);
-            }
+          // Copy some useful properties into data
+          data.pubkey = data.requirements.pubkey;
+          data.uid = data.requirements.uid;
+          data.blockUid = data.requirements.meta && data.requirements.meta.timestamp;
+          data.hasSelf = data.requirements.hasSelf;
+          data.sigDate =  data.requirements.meta && data.requirements.meta.time;
 
-            // Store additional data (e.g. certs)
-            data.lookup = {};
-
-            // Store received certifications (can be usefull later)
-            var certPubkeys = {};
-            data.lookup.certifications = (res.results || []).reduce(function(certsMap, res) {
-              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],
-                    cert_time:  {
-                      block: (cert.meta && cert.meta.block_number)  ? cert.meta.block_number : 0,
-                      block_hash: (cert.meta && cert.meta.block_hash)  ? cert.meta.block_hash : null
-                    },
-                    isMember: cert.isMember,
-                    wasMember: cert.wasMember,
-                  };
-                  if (!certPubkeys[certFullKey]) {
-                    certPubkeys[certFullKey] = result;
-                  }
-                  else { // if duplicated cert: keep the most recent
-                    if (result.cert_time.block > certPubkeys[certFullKey].cert_time.block) {
-                      certPubkeys[certFullKey] = result;
-                      certs.splice(_.findIndex(certs, {pubkey: cert.pubkey}), 1, result);
-                      return certs;
-                    }
-                    else {
-                      return certs; // skip this cert
-                    }
-                  }
-                  return certs.concat(result);
-                }, []);
-                return certsMap;
-              }, certsMap);
-            }, {});
-
-            // Store given certifications
-            certPubkeys = {};
-            data.lookup.givenCertifications = (res.results || []).reduce(function(certs, res) {
-              return (res.signed || []).reduce(function(certs, cert) {
+          if (identities.length > 1) {
+            data.requirements.alternatives = identities.splice(1);
+          }
+
+          // Store additional data (e.g. certs)
+          data.lookup = {};
+
+          // Store received certifications (can be usefull later)
+          var certPubkeys = {};
+          data.lookup.certifications = (res.results || []).reduce(function(certsMap, res) {
+            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.uid,
+                  uid: cert.uids[0],
                   cert_time:  {
-                    block: (cert.cert_time && cert.cert_time.block)  ? cert.cert_time.block : 0,
-                    block_hash: (cert.cert_time && cert.cert_time.block_hash)  ? cert.cert_time.block_hash : null
+                    block: (cert.meta && cert.meta.block_number)  ? cert.meta.block_number : 0,
+                    block_hash: (cert.meta && cert.meta.block_hash)  ? cert.meta.block_hash : null
                   },
-                  sigDate: cert.meta ? cert.meta.timestamp : null,
                   isMember: cert.isMember,
-                  wasMember: cert.wasMember
+                  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.block > certPubkeys[cert.pubkey].block) {
-                    certPubkeys[cert.pubkey] = result;
-                    // TODO: Replace the existing one ? May be not, to be able to see renewal
-                    // (see issue #806)
-                    //  If yes (need to replace), check this code works:
-                    //certs.splice(_.findIndex(certs, {pubkey: cert.pubkey}), 1, result);
-                    //return certs;
+                  if (result.cert_time.block > certPubkeys[certFullKey].cert_time.block) {
+                    certPubkeys[certFullKey] = result;
+                    certs.splice(_.findIndex(certs, {pubkey: cert.pubkey}), 1, result);
+                    return certs;
                   }
                   else {
                     return certs; // skip this cert
                   }
                 }
                 return certs.concat(result);
-              }, certs);
-            }, []);
-
+              }, []);
+              return certsMap;
+            }, certsMap);
+          }, {});
+
+          // Store given certifications
+          certPubkeys = {};
+          data.lookup.givenCertifications = (res.results || []).reduce(function(certs, res) {
+            return (res.signed || []).reduce(function(certs, cert) {
+              var result = {
+                pubkey: cert.pubkey,
+                uid: cert.uid,
+                cert_time:  {
+                  block: (cert.cert_time && cert.cert_time.block)  ? cert.cert_time.block : 0,
+                  block_hash: (cert.cert_time && cert.cert_time.block_hash)  ? cert.cert_time.block_hash : null
+                },
+                sigDate: cert.meta ? cert.meta.timestamp : null,
+                isMember: cert.isMember,
+                wasMember: cert.wasMember
+              };
+              if (!certPubkeys[cert.pubkey]) {
+                certPubkeys[cert.pubkey] = result;
+              }
+              else { // if duplicated cert: keep the most recent
+                if (result.block > certPubkeys[cert.pubkey].block) {
+                  certPubkeys[cert.pubkey] = result;
+                  // TODO: Replace the existing one ? May be not, to be able to see renewal
+                  // (see issue #806)
+                  //  If yes (need to replace), check this code works:
+                  //certs.splice(_.findIndex(certs, {pubkey: cert.pubkey}), 1, result);
+                  //return certs;
+                }
+                else {
+                  return certs; // skip this cert
+                }
+              }
+              return certs.concat(result);
+            }, certs);
+          }, []);
+
+          return data;
+        })
+        .catch(function(err) {
+          if (!!err && err.ucode == BMA.errorCodes.NO_MATCHING_IDENTITY) { // Identity not found (if no self)
+            _resetRequirements(data);
             return data;
-          })
-          .catch(function(err) {
-            if (!!err && err.ucode == BMA.errorCodes.NO_MATCHING_IDENTITY) { // Identity not found (if no self)
-              _resetRequirements(data);
-              return data;
-            }
-            else {
-              throw err;
-            }
-          });
-      },
+          }
+          else {
+            throw err;
+          }
+        });
+    },
 
-      loadCertifications = function(getFunction, pubkey, lookupCertifications, parameters, medianTime, certifiersOf) {
+    loadCertifications = function(getFunction, pubkey, lookupCertifications, parameters, medianTime, certifiersOf) {
 
-        function _certId(pubkey, block) {
-          return pubkey + '-' + block;
-        }
+      function _certId(pubkey, block) {
+        return pubkey + '-' + block;
+      }
 
-        // TODO : remove this later (when all node will use duniter v0.50+)
-        var lookupHasCertTime = true; // Will be set ti FALSE before Duniter v0.50
-        var lookupCerticationsByCertId = lookupCertifications ? lookupCertifications.reduce(function(res, cert){
-          var certId = _certId(cert.pubkey, cert.cert_time ? cert.cert_time.block : cert.sigDate);
-          if (!cert.cert_time) lookupHasCertTime = false;
-          res[certId] = cert;
-          return res;
-        }, {}) : {};
+      // TODO : remove this later (when all node will use duniter v0.50+)
+      var lookupHasCertTime = true; // Will be set ti FALSE before Duniter v0.50
+      var lookupCerticationsByCertId = lookupCertifications ? lookupCertifications.reduce(function(res, cert){
+        var certId = _certId(cert.pubkey, cert.cert_time ? cert.cert_time.block : cert.sigDate);
+        if (!cert.cert_time) lookupHasCertTime = false;
+        res[certId] = cert;
+        return res;
+      }, {}) : {};
 
-        var isMember = true;
+      var isMember = true;
 
-        return getFunction({ pubkey: pubkey })
-          .then(function(res) {
-            return (res && res.certifications || []).reduce(function (res, cert) {
-              // Rappel :
-              //   cert.sigDate = blockstamp de l'identité
-              //   cert.cert_time.block : block au moment de la certification
-              //   cert.written.number : block où la certification est écrite
-
-              var pending = !cert.written;
-              var certTime = cert.cert_time ? cert.cert_time.medianTime : null;
-              var expiresIn = (!certTime) ? 0 : (pending ?
-                (certTime + parameters.sigWindow - medianTime) :
-                (certTime + parameters.sigValidity - medianTime));
-              expiresIn = (expiresIn < 0) ? 0 : expiresIn;
-              // Remove from lookup certs
-              var certId = _certId(cert.pubkey, lookupHasCertTime && cert.cert_time ? cert.cert_time.block : cert.sigDate);
-              delete lookupCerticationsByCertId[certId];
-
-              // Add to result list
+      return getFunction({ pubkey: pubkey })
+        .then(function(res) {
+          return (res && res.certifications || []).reduce(function (res, cert) {
+            // Rappel :
+            //   cert.sigDate = blockstamp de l'identité
+            //   cert.cert_time.block : block au moment de la certification
+            //   cert.written.number : block où la certification est écrite
+
+            var pending = !cert.written;
+            var certTime = cert.cert_time ? cert.cert_time.medianTime : null;
+            var expiresIn = (!certTime) ? 0 : (pending ?
+              (certTime + parameters.sigWindow - medianTime) :
+              (certTime + parameters.sigValidity - medianTime));
+            expiresIn = (expiresIn < 0) ? 0 : expiresIn;
+            // Remove from lookup certs
+            var certId = _certId(cert.pubkey, lookupHasCertTime && cert.cert_time ? cert.cert_time.block : cert.sigDate);
+            delete lookupCerticationsByCertId[certId];
+
+            // Add to result list
+            return res.concat({
+              pubkey: cert.pubkey,
+              uid: cert.uid,
+              time: certTime,
+              isMember: cert.isMember,
+              wasMember: cert.wasMember,
+              expiresIn: expiresIn,
+              willExpire: (expiresIn && expiresIn <= csSettings.data.timeWarningExpire),
+              pending: pending,
+              block: (cert.written !== null) ? cert.written.number :
+                (cert.cert_time ? cert.cert_time.block : null),
+              valid: (expiresIn > 0)
+            });
+          }, []);
+        })
+        .catch(function(err) {
+          if (!!err && err.ucode == BMA.errorCodes.NO_MATCHING_MEMBER) { // member not found
+            isMember = false;
+            return []; // continue (append pendings cert if exists in lookup)
+          }
+          /*FIXME: workaround for Duniter issue #1309 */
+          else if (!!err && err.ucode == 1002) {
+            console.warn("[wallet-service] Detecting Duniter issue #1309 ! Applying workaround... ");
+            isMember = false;
+            return []; // not found
+          }
+          else {
+            throw err;
+          }
+        })
+
+        // Add pending certs (found in lookup - see loadIdentityByLookup())
+        .then(function(certifications) {
+          var pendingCertifications = _.values(lookupCerticationsByCertId);
+          if (!pendingCertifications.length) return certifications; // No more pending continue
+
+          // Special case for initPhase - issue #
+          if (csCurrency.data.initPhase) {
+            return pendingCertifications.reduce(function(res, cert) {
               return res.concat({
                 pubkey: cert.pubkey,
                 uid: cert.uid,
-                time: certTime,
                 isMember: cert.isMember,
                 wasMember: cert.wasMember,
-                expiresIn: expiresIn,
-                willExpire: (expiresIn && expiresIn <= csSettings.data.timeWarningExpire),
-                pending: pending,
-                block: (cert.written !== null) ? cert.written.number :
-                  (cert.cert_time ? cert.cert_time.block : null),
-                valid: (expiresIn > 0)
+                time: null,
+                expiresIn: parameters.sigWindow,
+                willExpire: false,
+                pending: true,
+                block: 0,
+                valid: true
               });
-            }, []);
-          })
-          .catch(function(err) {
-            if (!!err && err.ucode == BMA.errorCodes.NO_MATCHING_MEMBER) { // member not found
-              isMember = false;
-              return []; // continue (append pendings cert if exists in lookup)
-            }
-            /*FIXME: workaround for Duniter issue #1309 */
-            else if (!!err && err.ucode == 1002) {
-              console.warn("[wallet-service] Detecting Duniter issue #1309 ! Applying workaround... ");
-              isMember = false;
-              return []; // not found
-            }
-            else {
-              throw err;
-            }
-          })
-
-          // Add pending certs (found in lookup - see loadIdentityByLookup())
-          .then(function(certifications) {
-            var pendingCertifications = _.values(lookupCerticationsByCertId);
-            if (!pendingCertifications.length) return certifications; // No more pending continue
+            }, certifications);
+          }
 
-            // Special case for initPhase - issue #
-            if (csCurrency.data.initPhase) {
-              return pendingCertifications.reduce(function(res, cert) {
+          var pendingCertByBlocks = pendingCertifications.reduce(function(res, cert){
+            var block = lookupHasCertTime && cert.cert_time ? cert.cert_time.block :
+              (cert.sigDate ? cert.sigDate.split('-')[0] : null);
+            if (angular.isDefined(block)) {
+              if (!res[block]) {
+                res[block] = [cert];
+              }
+              else {
+                res[block].push(cert);
+              }
+            }
+            return res;
+          }, {});
+
+          // Set time to pending cert, from blocks
+          return BMA.blockchain.blocks(_.keys(pendingCertByBlocks)).then(function(blocks){
+            certifications = blocks.reduce(function(res, block){
+              return res.concat(pendingCertByBlocks[block.number].reduce(function(res, cert) {
+                var certTime = block.medianTime;
+                var expiresIn = Math.max(0, certTime + parameters.sigWindow - medianTime);
+                var validBuid = (!cert.cert_time || !cert.cert_time.block_hash || cert.cert_time.block_hash == block.hash);
+                if (!validBuid) {
+                  console.debug("[wot] Invalid cert {0}: block hash changed".format(cert.pubkey.substring(0,8)));
+                }
+                var valid = (expiresIn > 0) && (!certifiersOf || cert.isMember) && validBuid;
                 return res.concat({
                   pubkey: cert.pubkey,
                   uid: cert.uid,
                   isMember: cert.isMember,
                   wasMember: cert.wasMember,
-                  time: null,
-                  expiresIn: parameters.sigWindow,
-                  willExpire: false,
+                  time: certTime,
+                  expiresIn: expiresIn,
+                  willExpire: (expiresIn && expiresIn <= csSettings.data.timeWarningExpire),
                   pending: true,
-                  block: 0,
-                  valid: true
+                  block: lookupHasCertTime && cert.cert_time ? cert.cert_time.block :
+                  (cert.sigDate ? cert.sigDate.split('-')[0] : null),
+                  valid: valid
                 });
-              }, certifications);
-            }
-
-            var pendingCertByBlocks = pendingCertifications.reduce(function(res, cert){
-              var block = lookupHasCertTime && cert.cert_time ? cert.cert_time.block :
-                (cert.sigDate ? cert.sigDate.split('-')[0] : null);
-              if (angular.isDefined(block)) {
-                if (!res[block]) {
-                  res[block] = [cert];
-                }
-                else {
-                  res[block].push(cert);
-                }
-              }
-              return res;
-            }, {});
-
-            // Set time to pending cert, from blocks
-            return BMA.blockchain.blocks(_.keys(pendingCertByBlocks)).then(function(blocks){
-              certifications = blocks.reduce(function(res, block){
-                return res.concat(pendingCertByBlocks[block.number].reduce(function(res, cert) {
-                  var certTime = block.medianTime;
-                  var expiresIn = Math.max(0, certTime + parameters.sigWindow - medianTime);
-                  var validBuid = (!cert.cert_time || !cert.cert_time.block_hash || cert.cert_time.block_hash == block.hash);
-                  if (!validBuid) {
-                    console.debug("[wot] Invalid cert {0}: block hash changed".format(cert.pubkey.substring(0,8)));
-                  }
-                  var valid = (expiresIn > 0) && (!certifiersOf || cert.isMember) && validBuid;
-                  return res.concat({
-                    pubkey: cert.pubkey,
-                    uid: cert.uid,
-                    isMember: cert.isMember,
-                    wasMember: cert.wasMember,
-                    time: certTime,
-                    expiresIn: expiresIn,
-                    willExpire: (expiresIn && expiresIn <= csSettings.data.timeWarningExpire),
-                    pending: true,
-                    block: lookupHasCertTime && cert.cert_time ? cert.cert_time.block :
-                    (cert.sigDate ? cert.sigDate.split('-')[0] : null),
-                    valid: valid
-                  });
-                }, []));
-              }, certifications);
-              return certifications;
-            });
-          })
+              }, []));
+            }, certifications);
+            return certifications;
+          });
+        })
 
-          // Sort and return result
-          .then(function(certifications) {
+        // Sort and return result
+        .then(function(certifications) {
 
-            // Remove pending cert duplicated with a written & valid cert
-            var writtenCertByPubkey = certifications.reduce(function(res, cert) {
-              if (!cert.pending && cert.valid && cert.expiresIn >= parameters.sigWindow) {
-                res[cert.pubkey] = true;
+          // Remove pending cert duplicated with a written & valid cert
+          var writtenCertByPubkey = certifications.reduce(function(res, cert) {
+            if (!cert.pending && cert.valid && cert.expiresIn >= parameters.sigWindow) {
+              res[cert.pubkey] = true;
+            }
+            return res;
+          }, {});
+
+          // Final sort
+          certifications = _sortCertifications(certifications);
+
+          // Split into valid/pending/error
+          var pendingCertifications = [];
+          var errorCertifications = [];
+          var validCertifications = certifications.reduce(function(res, cert) {
+            if (cert.pending) {
+              if (cert.valid && !writtenCertByPubkey[cert.pubkey]) {
+                pendingCertifications.push(cert);
               }
-              return res;
-            }, {});
-
-            // Final sort
-            certifications = _sortCertifications(certifications);
-
-            // Split into valid/pending/error
-            var pendingCertifications = [];
-            var errorCertifications = [];
-            var validCertifications = certifications.reduce(function(res, cert) {
-              if (cert.pending) {
-                if (cert.valid && !writtenCertByPubkey[cert.pubkey]) {
-                  pendingCertifications.push(cert);
-                }
-                else if (!cert.valid && !writtenCertByPubkey[cert.pubkey]){
-                  errorCertifications.push(cert);
-                }
-                return res;
+              else if (!cert.valid && !writtenCertByPubkey[cert.pubkey]){
+                errorCertifications.push(cert);
               }
-              return res.concat(cert);
-            }, []);
-
-            return {
-              valid: validCertifications,
-              pending: pendingCertifications,
-              error: errorCertifications
-            };
-          })
-          ;
-      },
-
-      // Add events on given account
-      addEvents = function(data) {
+              return res;
+            }
+            return res.concat(cert);
+          }, []);
 
-        if (data.requirements.revoked) {
-          delete data.requirements.meta.invalid;
-          if (data.requirements.revoked_on) {
-            addEvent(data, {type: 'error', message: 'ERROR.IDENTITY_REVOKED_WITH_TIME', messageParams: {revocationTime: data.requirements.revoked_on}});
-            console.debug("[wot] Identity [{0}] has been revoked on {1}".format(data.uid, data.requirements.revoked_on));
-          }
-          else {
-            addEvent(data, {type: 'error', message: 'ERROR.IDENTITY_REVOKED'});
-            console.debug("[wot] Identity [{0}] has been revoked".format(data.uid));
-          }
-        }
-        else if (data.requirements.pendingRevocation) {
-          delete data.requirements.meta.invalid;
-          addEvent(data, {type:'error', message: 'ERROR.IDENTITY_PENDING_REVOCATION'});
-          console.debug("[wot] Identity [{0}] has pending revocation".format(data.uid));
-        }
-        else if (data.requirements.meta && data.requirements.meta.invalid) {
-          if (!data.isMember) {
-            addEvent(data, {type: 'error', message: 'ERROR.IDENTITY_INVALID_BLOCK_HASH'});
-            console.debug("[wot] Invalid membership for uid {0}: block hash changed".format(data.uid));
-          }
-        }
-        else if (data.requirements.expired) {
-          addEvent(data, {type: 'error', message: 'ERROR.IDENTITY_EXPIRED'});
-          console.debug("[wot] Identity {0} expired (in sandbox)".format(data.uid));
-        }
-        else if (data.requirements.willNeedCertificationCount > 0) {
-          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));
+          return {
+            valid: validCertifications,
+            pending: pendingCertifications,
+            error: errorCertifications
+          };
+        })
+        ;
+    },
+
+    // Add events on given account
+    addEvents = function(data) {
+
+      if (data.requirements.revoked) {
+        delete data.requirements.meta.invalid;
+        if (data.requirements.revoked_on) {
+          addEvent(data, {type: 'error', message: 'ERROR.IDENTITY_REVOKED_WITH_TIME', messageParams: {revocationTime: data.requirements.revoked_on}});
+          console.debug("[wot] Identity [{0}] has been revoked on {1}".format(data.uid, data.requirements.revoked_on));
         }
-        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));
+        else {
+          addEvent(data, {type: 'error', message: 'ERROR.IDENTITY_REVOKED'});
+          console.debug("[wot] Identity [{0}] has been revoked".format(data.uid));
         }
-        if (!data.isMember && data.requirements.alternatives) {
-          addEvent(data, {type: 'info', message: 'INFO.HAS_ALTERNATIVE_IDENTITIES'});
+      }
+      else if (data.requirements.pendingRevocation) {
+        delete data.requirements.meta.invalid;
+        addEvent(data, {type:'error', message: 'ERROR.IDENTITY_PENDING_REVOCATION'});
+        console.debug("[wot] Identity [{0}] has pending revocation".format(data.uid));
+      }
+      else if (data.requirements.meta && data.requirements.meta.invalid) {
+        if (!data.isMember) {
+          addEvent(data, {type: 'error', message: 'ERROR.IDENTITY_INVALID_BLOCK_HASH'});
+          console.debug("[wot] Invalid membership for uid {0}: block hash changed".format(data.uid));
         }
-      },
+      }
+      else if (data.requirements.expired) {
+        addEvent(data, {type: 'error', message: 'ERROR.IDENTITY_EXPIRED'});
+        console.debug("[wot] Identity {0} expired (in sandbox)".format(data.uid));
+      }
+      else if (data.requirements.willNeedCertificationCount > 0) {
+        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));
+      }
+      if (!data.isMember && data.requirements.alternatives) {
+        addEvent(data, {type: 'info', message: 'INFO.HAS_ALTERNATIVE_IDENTITIES'});
+      }
+    },
 
-      loadData = function(pubkey, uid, options) {
+    loadData = function(pubkey, uid, options) {
 
-        options = options || {};
-        var data;
+      options = options || {};
+      var data;
 
-        if (!pubkey && uid && !options.force) {
-          return BMA.wot.member.getByUid(uid)
-            .then(function(member) {
-              if (member) return loadData(member.pubkey, member.uid, options); // recursive call, with a pubkey
-              //throw {message: 'NOT_A_MEMBER'};
-              var options = angular.copy(options || {});
-              options.force = true;
-              return loadData(pubkey, uid, options); // Loop with force=true
-            });
-        }
+      if (!pubkey && uid && !options.force) {
+        return BMA.wot.member.getByUid(uid)
+          .then(function(member) {
+            if (member) return loadData(member.pubkey, member.uid, options); // recursive call, with a pubkey
+            //throw {message: 'NOT_A_MEMBER'};
+            var options = angular.copy(options || {});
+            options.force = true;
+            return loadData(pubkey, uid, options); // Loop with force=true
+          });
+      }
 
-        // Check cached data
-        if (pubkey) {
-          data = (options.cache !== false) ? identityCache.get(pubkey) : null;
-          if (data && (!uid || data.uid === uid) && (!options.blockUid || data.blockUid === options.blockUid)) {
-            console.debug("[wot] Identity " + pubkey.substring(0, 8) + " found in cache");
-            return $q.when(data);
-          }
-          console.debug("[wot] Loading identity " + pubkey.substring(0, 8) + "...");
-          data = {
-            pubkey: pubkey,
-            uid: uid
-          };
-        }
-        else {
-          console.debug("[wot] Loading identity from uid " + uid);
-          data = {
-            uid: uid
-          };
-        }
-        if (options.blockUid) {
-          data.blockUid = options.blockUid;
+      // Check cached data
+      if (pubkey) {
+        data = (options.cache !== false) ? identityCache.get(pubkey) : null;
+        if (data && (!uid || data.uid === uid) && (!options.blockUid || data.blockUid === options.blockUid)) {
+          console.debug("[wot] Identity " + pubkey.substring(0, 8) + " found in cache");
+          return $q.when(data);
         }
+        console.debug("[wot] Loading identity " + pubkey.substring(0, 8) + "...");
+        data = {
+          pubkey: pubkey,
+          uid: uid
+        };
+      }
+      else {
+        console.debug("[wot] Loading identity from uid " + uid);
+        data = {
+          uid: uid
+        };
+      }
+      if (options.blockUid) {
+        data.blockUid = options.blockUid;
+      }
 
-        var now = Date.now();
-        var parameters;
-        var medianTime;
+      var now = Date.now();
+      var parameters;
+      var medianTime;
 
-        return $q.all([
+      return $q.all([
 
-            // Get parameters
-            csCurrency.parameters()
-              .then(function(res) {
-                parameters = res;
+          // Get parameters
+          csCurrency.parameters()
+            .then(function(res) {
+              parameters = res;
+            }),
+
+          // Get current time
+          csCurrency.blockchain.current(true)
+            .then(function(current) {
+              medianTime = current.medianTime;
+            })
+            .catch(function(err){
+              // Special case for currency init (root block not exists): use now
+              if (err && err.ucode == BMA.errorCodes.NO_CURRENT_BLOCK) {
+                medianTime = moment.utc().unix();
+              }
+              else {
+                throw err;
+              }
+            }),
+
+          // Get requirements
+          loadRequirements(data, options.cache !== false),
+
+          // Get identity using lookup
+          loadIdentityByLookup(pubkey, uid)
+
+        ])
+        .then(function(res) {
+          var dataByLookup = res[3];
+
+          // If no requirements found: copy from lookup data
+          if (!data.requirements.uid) {
+            console.debug("[wot] No requirements found: using data from lookup");
+            angular.merge(data, dataByLookup);
+            delete data.lookup; // not need
+            return;
+          }
+
+          var idtyFullKey = data.requirements.uid + '-' + data.requirements.meta.timestamp;
+
+          return $q.all([
+            // Get received certifications
+            loadCertifications(BMA.wot.certifiersOf, data.pubkey, dataByLookup.lookup ? dataByLookup.lookup.certifications[idtyFullKey] : null, parameters, medianTime, true /*certifiersOf*/)
+              .then(function (res) {
+                data.received_cert = res.valid;
+                data.received_cert_pending = res.pending;
+                data.received_cert_error = res.error;
               }),
 
-            // Get current time
-            csCurrency.blockchain.current(true)
-              .then(function(current) {
-                medianTime = current.medianTime;
+            // Get given certifications
+            loadCertifications(BMA.wot.certifiedBy, data.pubkey, dataByLookup.lookup ? dataByLookup.lookup.givenCertifications : null, parameters, medianTime, false/*certifiersOf*/)
+              .then(function (res) {
+                data.given_cert = res.valid;
+                data.given_cert_pending = res.pending;
+                data.given_cert_error = res.error;
               })
-              .catch(function(err){
-                // Special case for currency init (root block not exists): use now
-                if (err && err.ucode == BMA.errorCodes.NO_CURRENT_BLOCK) {
-                  medianTime = moment.utc().unix();
-                }
-                else {
-                  throw err;
-                }
-              }),
+          ]);
+        })
+        .then(function() {
 
-            // Get requirements
-            loadRequirements(data, options.cache !== false),
+          // Add compute some additional requirements (that required all data like certifications)
+          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;
 
-            // Get identity using lookup
-            loadIdentityByLookup(pubkey, uid)
+          // Add account events
+          addEvents(data);
 
-          ])
-          .then(function(res) {
-            var dataByLookup = res[3];
-
-            // If no requirements found: copy from lookup data
-            if (!data.requirements.uid) {
-              console.debug("[wot] No requirements found: using data from lookup");
-              angular.merge(data, dataByLookup);
-              delete data.lookup; // not need
-              return;
-            }
+          // API extension
+          return api.data.raisePromise.load(data)
+            .catch(function(err) {
+              console.debug('Error while loading identity data, on extension point.');
+              console.error(err);
+            });
+        })
+        .then(function() {
+          if (!data.pubkey) return undefined; // not found
+          identityCache.put(data.pubkey, data); // add to cache
+          console.debug('[wot] Identity '+ data.pubkey.substring(0, 8) +' loaded in '+ (Date.now()-now) +'ms');
+          return data;
+        });
+    },
 
-            var idtyFullKey = data.requirements.uid + '-' + data.requirements.meta.timestamp;
-
-            return $q.all([
-              // Get received certifications
-              loadCertifications(BMA.wot.certifiersOf, data.pubkey, dataByLookup.lookup ? dataByLookup.lookup.certifications[idtyFullKey] : null, parameters, medianTime, true /*certifiersOf*/)
-                .then(function (res) {
-                  data.received_cert = res.valid;
-                  data.received_cert_pending = res.pending;
-                  data.received_cert_error = res.error;
-                }),
-
-              // Get given certifications
-              loadCertifications(BMA.wot.certifiedBy, data.pubkey, dataByLookup.lookup ? dataByLookup.lookup.givenCertifications : null, parameters, medianTime, false/*certifiersOf*/)
-                .then(function (res) {
-                  data.given_cert = res.valid;
-                  data.given_cert_pending = res.pending;
-                  data.given_cert_error = res.error;
-                })
-            ]);
-          })
-          .then(function() {
+    search = function(text, options) {
+      if (!text || text.trim() !== text) {
+        return $q.when(undefined);
+      }
 
-            // Add compute some additional requirements (that required all data like certifications)
-            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;
+      // Remove first special characters (to avoid request error)
+      var safeText = text.replace(/(^|\s)#\w+/g, ''); // remove tags
+      safeText = safeText.replace(/[^a-zA-Z0-9_-\s]+/g, '');
+      safeText = safeText.replace(/\s+/g, ' ').trim();
 
-            // Add account events
-            addEvents(data);
+      options = options || {};
+      options.addUniqueId = angular.isDefined(options.addUniqueId) ? options.addUniqueId : true;
+      options.allowExtension = angular.isDefined(options.allowExtension) ? options.allowExtension : true;
+      options.excludeRevoked = angular.isDefined(options.excludeRevoked) ? options.excludeRevoked : false;
 
-            // API extension
-            return api.data.raisePromise.load(data)
-              .catch(function(err) {
-                console.debug('Error while loading identity data, on extension point.');
-                console.error(err);
-              });
+      var promise;
+      if (!safeText) {
+        promise = $q.when([]);
+      }
+      else {
+        promise = $q.all(
+          safeText.split(' ').reduce(function(res, text) {
+            console.debug('[wot] Will search on: \'' + text + '\'');
+            return res.concat(BMA.wot.lookup({ search: text }));
+          }, [])
+        ).then(function(res){
+            return res.reduce(function(idties, res) {
+              return idties.concat(res.results.reduce(function(idties, res) {
+                return idties.concat(res.uids.reduce(function(uids, idty) {
+                  var blocUid = idty.meta.timestamp.split('-', 2);
+                  var revoked = !idty.revoked && idty.revocation_sig;
+                  if (!options.excludeRevoked || !revoked) {
+                    return uids.concat({
+                      uid: idty.uid,
+                      pubkey: res.pubkey,
+                      number: blocUid[0],
+                      hash: blocUid[1],
+                      revoked: revoked
+                    });
+                  }
+                  return uids;
+                }, []));
+              }, []));
+            }, []);
           })
-          .then(function() {
-            if (!data.pubkey) return undefined; // not found
-            identityCache.put(data.pubkey, data); // add to cache
-            console.debug('[wot] Identity '+ data.pubkey.substring(0, 8) +' loaded in '+ (Date.now()-now) +'ms');
-            return data;
+          .catch(function(err) {
+            if (err && err.ucode == BMA.errorCodes.NO_MATCHING_IDENTITY) {
+              return [];
+            }
+            else {
+              throw err;
+            }
           });
-      },
-
-      search = function(text, options) {
-        if (!text || text.trim() !== text) {
-          return $q.when(undefined);
-        }
-
-        // Remove first special characters (to avoid request error)
-        var safeText = text.replace(/(^|\s)#\w+/g, ''); // remove tags
-        safeText = safeText.replace(/[^a-zA-Z0-9_-\s]+/g, '');
-        safeText = safeText.replace(/\s+/g, ' ').trim();
+      }
 
-        options = options || {};
-        options.addUniqueId = angular.isDefined(options.addUniqueId) ? options.addUniqueId : true;
-        options.allowExtension = angular.isDefined(options.allowExtension) ? options.allowExtension : true;
-        options.excludeRevoked = angular.isDefined(options.excludeRevoked) ? options.excludeRevoked : false;
+      return promise
+        .then(function(idties) {
+          if (!options.allowExtension) {
+            // Add unique id (if enable)
+            return options.addUniqueId ? _addUniqueIds(idties) : idties;
+          }
+          var lookupResultCount = idties.length;
+          // call extension point
+          return api.data.raisePromise.search(text, idties, 'pubkey')
+            .then(function() {
 
-        var promise;
-        if (!safeText) {
-          promise = $q.when([]);
-        }
-        else {
-          promise = $q.all(
-            safeText.split(' ').reduce(function(res, text) {
-              console.debug('[wot] Will search on: \'' + text + '\'');
-              return res.concat(BMA.wot.lookup({ search: text }));
-            }, [])
-          ).then(function(res){
-              return res.reduce(function(idties, res) {
-                return idties.concat(res.results.reduce(function(idties, res) {
-                  return idties.concat(res.uids.reduce(function(uids, idty) {
-                    var blocUid = idty.meta.timestamp.split('-', 2);
-                    var revoked = !idty.revoked && idty.revocation_sig;
-                    if (!options.excludeRevoked || !revoked) {
-                      return uids.concat({
-                        uid: idty.uid,
-                        pubkey: res.pubkey,
-                        number: blocUid[0],
-                        hash: blocUid[1],
-                        revoked: revoked
+              // Make sure to add uid to new results - fix #488
+              if (idties.length > lookupResultCount) {
+                var idtiesWithoutUid = _.filter(idties, function(idty) {
+                  return !idty.uid && idty.pubkey;
+                });
+                if (idtiesWithoutUid.length) {
+                  return BMA.wot.member.uids()
+                    .then(function(uids) {
+                      _.forEach(idties, function(idty) {
+                        if (!idty.uid && idty.pubkey) {
+                          idty.uid = uids[idty.pubkey];
+                        }
                       });
-                    }
-                    return uids;
-                  }, []));
-                }, []));
-              }, []);
-            })
-            .catch(function(err) {
-              if (err && err.ucode == BMA.errorCodes.NO_MATCHING_IDENTITY) {
-                return [];
-              }
-              else {
-                throw err;
+                    });
+                }
               }
-            });
-        }
-
-        return promise
-          .then(function(idties) {
-            if (!options.allowExtension) {
+            })
+            .then(function() {
               // Add unique id (if enable)
               return options.addUniqueId ? _addUniqueIds(idties) : idties;
-            }
-            var lookupResultCount = idties.length;
-            // call extension point
-            return api.data.raisePromise.search(text, idties, 'pubkey')
-              .then(function() {
-
-                // Make sure to add uid to new results - fix #488
-                if (idties.length > lookupResultCount) {
-                  var idtiesWithoutUid = _.filter(idties, function(idty) {
-                    return !idty.uid && idty.pubkey;
+            });
+        });
+    },
+
+    getNewcomers = function(offset, size) {
+      offset = offset || 0;
+      size = size || 20;
+      var total;
+      return $q.all([
+          csCurrency.blockchain.current(true)
+            .then(function(block) {
+              total = block.membersCount || 0;
+            }),
+          BMA.blockchain.stats.newcomers()
+        ])
+        .then(function(res) {
+          res = res[1];
+          if (!res || !res.result || !res.result.blocks || !res.result.blocks.length) return null; // no result
+          var blocks = _.sortBy(res.result.blocks, function (n) {
+            return -n;
+          });
+          return getNewcomersRecursive(blocks, 0, 5, offset+size);
+        })
+        .then(function(idties){
+          if (!idties || !idties.length) {
+            return null;
+          }
+          idties = _sortAndSliceIdentities(idties, offset, size);
+
+          // Extension point
+          return extendAll(idties, 'pubkey', true/*skipAddUid*/);
+        })
+        .then(function(idties) {
+          return {
+            hits: idties,
+            total: total
+          };
+        });
+    },
+
+
+    getNewcomersRecursive = function(blocks, offset, size, maxResultSize) {
+      return $q(function(resolve, reject) {
+        var result = [];
+        var jobs = [];
+        _.each(blocks.slice(offset, offset+size), function(number) {
+          jobs.push(
+            BMA.blockchain.block({block: number})
+              .then(function(block){
+                if (!block || !block.joiners) return;
+                _.each(block.joiners, function(joiner){
+                  var parts = joiner.split(':');
+                  var idtyKey = parts[parts.length-1]/*uid*/ + '-' + parts[0]/*pubkey*/;
+                  result.push({
+                    id: idtyKey,
+                    uid: parts[parts.length-1],
+                    pubkey:parts[0],
+                    memberDate: block.medianTime,
+                    block: block.number
                   });
-                  if (idtiesWithoutUid.length) {
-                    return BMA.wot.member.uids()
-                      .then(function(uids) {
-                        _.forEach(idties, function(idty) {
-                          if (!idty.uid && idty.pubkey) {
-                            idty.uid = uids[idty.pubkey];
-                          }
-                        });
-                      });
-                  }
-                }
+                });
               })
-              .then(function() {
-                // Add unique id (if enable)
-                return options.addUniqueId ? _addUniqueIds(idties) : idties;
-              });
-          });
-      },
-
-      getNewcomers = function(offset, size) {
-        offset = offset || 0;
-        size = size || 20;
-        var total;
-        return $q.all([
-            csCurrency.blockchain.current(true)
-              .then(function(block) {
-                total = block.membersCount || 0;
-              }),
-            BMA.blockchain.stats.newcomers()
-          ])
-          .then(function(res) {
-            res = res[1];
-            if (!res || !res.result || !res.result.blocks || !res.result.blocks.length) return null; // no result
-            var blocks = _.sortBy(res.result.blocks, function (n) {
-              return -n;
-            });
-            return getNewcomersRecursive(blocks, 0, 5, offset+size);
-          })
-          .then(function(idties){
-            if (!idties || !idties.length) {
-              return null;
-            }
-            idties = _sortAndSliceIdentities(idties, offset, size);
+          );
+        });
 
-            // Extension point
-            return extendAll(idties, 'pubkey', true/*skipAddUid*/);
-          })
-          .then(function(idties) {
-            return {
-              hits: idties,
-              total: total
-            };
-          });
-      },
-
-
-      getNewcomersRecursive = function(blocks, offset, size, maxResultSize) {
-        return $q(function(resolve, reject) {
-          var result = [];
-          var jobs = [];
-          _.each(blocks.slice(offset, offset+size), function(number) {
-            jobs.push(
-              BMA.blockchain.block({block: number})
-                .then(function(block){
-                  if (!block || !block.joiners) return;
-                  _.each(block.joiners, function(joiner){
-                    var parts = joiner.split(':');
-                    var idtyKey = parts[parts.length-1]/*uid*/ + '-' + parts[0]/*pubkey*/;
-                    result.push({
-                      id: idtyKey,
-                      uid: parts[parts.length-1],
-                      pubkey:parts[0],
-                      memberDate: block.medianTime,
-                      block: block.number
-                    });
+        $q.all(jobs)
+          .then(function() {
+            if (result.length < maxResultSize && offset < blocks.length - 1) {
+              $timeout(function() {
+                getNewcomersRecursive(blocks, offset+size, size, maxResultSize - result.length)
+                  .then(function(res) {
+                    resolve(result.concat(res));
+                  })
+                  .catch(function(err) {
+                    reject(err);
                   });
-                })
-            );
+              }, 1000);
+            }
+            else {
+              resolve(result);
+            }
+          })
+          .catch(function(err){
+            if (err && err.ucode === BMA.errorCodes.HTTP_LIMITATION) {
+              resolve(result);
+            }
+            else {
+              reject(err);
+            }
           });
-
-          $q.all(jobs)
-            .then(function() {
-              if (result.length < maxResultSize && offset < blocks.length - 1) {
-                $timeout(function() {
-                  getNewcomersRecursive(blocks, offset+size, size, maxResultSize - result.length)
-                    .then(function(res) {
-                      resolve(result.concat(res));
-                    })
-                    .catch(function(err) {
-                      reject(err);
-                    });
-                }, 1000);
-              }
-              else {
-                resolve(result);
+      });
+    },
+
+    getPending = function(offset, size) {
+      offset = offset || 0;
+      size = size || 20;
+      var now = Date.now();
+      return $q.all([
+        BMA.wot.member.uids(),
+        BMA.wot.member.pending()
+          .then(function(res) {
+            return (res.memberships && res.memberships.length) ? res.memberships : undefined;
+          })
+        ])
+        .then(function(res) {
+          var uids = res[0];
+          var memberships = res[1];
+          if (!memberships) return;
+
+          var idtiesByBlock = {};
+          var idtiesByPubkey = {};
+          _.forEach(memberships, function(ms){
+            if (ms.membership == 'IN' && !uids[ms.pubkey]) {
+              var idty = {
+                uid: ms.uid,
+                pubkey: ms.pubkey,
+                block: ms.blockNumber,
+                blockHash: ms.blockHash
+              };
+              var otherIdtySamePubkey = idtiesByPubkey[ms.pubkey];
+              if (otherIdtySamePubkey && idty.block > otherIdtySamePubkey.block) {
+                return; // skip
               }
-            })
-            .catch(function(err){
-              if (err && err.ucode === BMA.errorCodes.HTTP_LIMITATION) {
-                resolve(result);
+              idtiesByPubkey[idty.pubkey] = idty;
+              if (!idtiesByBlock[idty.block]) {
+                idtiesByBlock[idty.block] = [idty];
               }
               else {
-                reject(err);
+                idtiesByBlock[idty.block].push(idty);
               }
-            });
-        });
-      },
-
-      getPending = function(offset, size) {
-        offset = offset || 0;
-        size = size || 20;
-        var now = Date.now();
-        return $q.all([
-          BMA.wot.member.uids(),
-          BMA.wot.member.pending()
-            .then(function(res) {
-              return (res.memberships && res.memberships.length) ? res.memberships : undefined;
-            })
-          ])
-          .then(function(res) {
-            var uids = res[0];
-            var memberships = res[1];
-            if (!memberships) return;
-
-            var idtiesByBlock = {};
-            var idtiesByPubkey = {};
-            _.forEach(memberships, function(ms){
-              if (ms.membership == 'IN' && !uids[ms.pubkey]) {
-                var idty = {
-                  uid: ms.uid,
-                  pubkey: ms.pubkey,
-                  block: ms.blockNumber,
-                  blockHash: ms.blockHash
-                };
-                var otherIdtySamePubkey = idtiesByPubkey[ms.pubkey];
-                if (otherIdtySamePubkey && idty.block > otherIdtySamePubkey.block) {
-                  return; // skip
-                }
-                idtiesByPubkey[idty.pubkey] = idty;
-                if (!idtiesByBlock[idty.block]) {
-                  idtiesByBlock[idty.block] = [idty];
-                }
-                else {
-                  idtiesByBlock[idty.block].push(idty);
-                }
 
-                // Remove previous idty from map
-                if (otherIdtySamePubkey) {
-                  idtiesByBlock[otherIdtySamePubkey.block] = idtiesByBlock[otherIdtySamePubkey.block].reduce(function(res, aidty){
-                    if (aidty.pubkey == otherIdtySamePubkey.pubkey) return res; // if match idty to remove, to NOT add
-                    return (res||[]).concat(aidty);
-                  }, null);
-                  if (idtiesByBlock[otherIdtySamePubkey.block] === null) {
-                    delete idtiesByBlock[otherIdtySamePubkey.block];
-                  }
+              // Remove previous idty from map
+              if (otherIdtySamePubkey) {
+                idtiesByBlock[otherIdtySamePubkey.block] = idtiesByBlock[otherIdtySamePubkey.block].reduce(function(res, aidty){
+                  if (aidty.pubkey == otherIdtySamePubkey.pubkey) return res; // if match idty to remove, to NOT add
+                  return (res||[]).concat(aidty);
+                }, null);
+                if (idtiesByBlock[otherIdtySamePubkey.block] === null) {
+                  delete idtiesByBlock[otherIdtySamePubkey.block];
                 }
               }
-            });
-
-            var idties = _.values(idtiesByPubkey);
-            var total = idties.length; // get total BEFORE slice
-
-            idties = _sortAndSliceIdentities(idties, offset, size);
-            var blocks = idties.reduce(function(res, aidty) {
-              return res.concat(aidty.block);
-            }, []);
+            }
+          });
 
-            return  $q.all([
-              // Get time from blocks
-              BMA.blockchain.blocks(_.uniq(blocks))
-              .then(function(blocks) {
-
-                _.forEach(blocks, function(block){
-                  _.forEach(idtiesByBlock[block.number], function(idty) {
-                    idty.sigDate = block.medianTime;
-                    if (block.number !== 0 && idty.blockHash !== block.hash) {
-                      addEvent(idty, {type:'error', message: 'ERROR.WOT_PENDING_INVALID_BLOCK_HASH'});
-                      console.debug("Invalid membership for uid={0}: block hash changed".format(idty.uid));
-                    }
-                  });
+          var idties = _.values(idtiesByPubkey);
+          var total = idties.length; // get total BEFORE slice
+
+          idties = _sortAndSliceIdentities(idties, offset, size);
+          var blocks = idties.reduce(function(res, aidty) {
+            return res.concat(aidty.block);
+          }, []);
+
+          return  $q.all([
+            // Get time from blocks
+            BMA.blockchain.blocks(_.uniq(blocks))
+            .then(function(blocks) {
+
+              _.forEach(blocks, function(block){
+                _.forEach(idtiesByBlock[block.number], function(idty) {
+                  idty.sigDate = block.medianTime;
+                  if (block.number !== 0 && idty.blockHash !== block.hash) {
+                    addEvent(idty, {type:'error', message: 'ERROR.WOT_PENDING_INVALID_BLOCK_HASH'});
+                    console.debug("Invalid membership for uid={0}: block hash changed".format(idty.uid));
+                  }
                 });
-              }),
-
-              // Extension point
-              extendAll(idties, 'pubkey', true/*skipAddUid*/)
-            ])
-            .then(function() {
-              console.debug("[ES] [wot] Loaded {0}/{1} pending identities in {2} ms".format(idties && idties.length || 0, total, Date.now() - now));
-              return {
-                hits: idties,
-                total: total
-              };
-            });
-          });
-      },
+              });
+            }),
 
-      getAll = function() {
-        var letters = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','u','v','w','x','y','z'];
-        return getAllRecursive(letters, 0, BMA.constants.LIMIT_REQUEST_COUNT)
-          .then(function(idties) {
-            return extendAll(idties, 'pubkey', true/*skipAddUid*/);
-          })
-          .then(_addUniqueIds)
+            // Extension point
+            extendAll(idties, 'pubkey', true/*skipAddUid*/)
+          ])
           .then(function() {
+            console.debug("[ES] [wot] Loaded {0}/{1} pending identities in {2} ms".format(idties && idties.length || 0, total, Date.now() - now));
             return {
               hits: idties,
-              total: idties.length
+              total: total
             };
           });
-      },
-
-      getAllRecursive = function(letters, offset, size) {
-        return $q(function(resolve, reject) {
-          var result = [];
-          var pubkeys = {};
-          var jobs = [];
-          _.each(letters.slice(offset, offset+size), function(letter) {
-            jobs.push(
-              search(letter, {
-                addUniqueId: false, // will be done in parent method
-                allowExtension: false // extension point will be called in parent method
-              })
-            .then(function(idties){
-                if (!idties || !idties.length) return;
-                result = idties.reduce(function(res, idty) {
-                  if (!pubkeys[idty.pubkey]) {
-                    pubkeys[idty.pubkey] = true;
-                    return res.concat(idty);
-                  }
-                  return res;
-                }, result);
-              })
-            );
-          });
+        });
+    },
+
+    getAll = function() {
+      var letters = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','u','v','w','x','y','z'];
+      return getAllRecursive(letters, 0, BMA.constants.LIMIT_REQUEST_COUNT)
+        .then(function(idties) {
+          return extendAll(idties, 'pubkey', true/*skipAddUid*/);
+        })
+        .then(_addUniqueIds)
+        .then(function() {
+          return {
+            hits: idties,
+            total: idties.length
+          };
+        });
+    },
 
-          $q.all(jobs)
-            .then(function() {
-              if (offset < letters.length - 1) {
-                $timeout(function() {
-                  getAllRecursive(letters, offset+size, size)
-                    .then(function(idties) {
-                      if (!idties || !idties.length) {
-                        resolve(result);
-                        return;
-                      }
-                      resolve(idties.reduce(function(res, idty) {
-                        if (!pubkeys[idty.pubkey]) {
-                          pubkeys[idty.pubkey] = true;
-                          return res.concat(idty);
-                        }
-                        return res;
-                      }, result));
-                    })
-                    .catch(function(err) {
-                      reject(err);
-                    });
-                }, BMA.constants.LIMIT_REQUEST_DELAY);
-              }
-              else {
-                resolve(result);
-              }
+    getAllRecursive = function(letters, offset, size) {
+      return $q(function(resolve, reject) {
+        var result = [];
+        var pubkeys = {};
+        var jobs = [];
+        _.each(letters.slice(offset, offset+size), function(letter) {
+          jobs.push(
+            search(letter, {
+              addUniqueId: false, // will be done in parent method
+              allowExtension: false // extension point will be called in parent method
             })
-            .catch(function(err){
-              if (err && err.ucode === BMA.errorCodes.HTTP_LIMITATION) {
-                resolve(result);
-              }
-              else {
-                reject(err);
-              }
-            });
+          .then(function(idties){
+              if (!idties || !idties.length) return;
+              result = idties.reduce(function(res, idty) {
+                if (!pubkeys[idty.pubkey]) {
+                  pubkeys[idty.pubkey] = true;
+                  return res.concat(idty);
+                }
+                return res;
+              }, result);
+            })
+          );
         });
-      },
 
-      extend = function(idty, pubkeyAttributeName, skipAddUid) {
-        return extendAll([idty], pubkeyAttributeName, skipAddUid)
-          .then(function(res) {
-            return res[0];
+        $q.all(jobs)
+          .then(function() {
+            if (offset < letters.length - 1) {
+              $timeout(function() {
+                getAllRecursive(letters, offset+size, size)
+                  .then(function(idties) {
+                    if (!idties || !idties.length) {
+                      resolve(result);
+                      return;
+                    }
+                    resolve(idties.reduce(function(res, idty) {
+                      if (!pubkeys[idty.pubkey]) {
+                        pubkeys[idty.pubkey] = true;
+                        return res.concat(idty);
+                      }
+                      return res;
+                    }, result));
+                  })
+                  .catch(function(err) {
+                    reject(err);
+                  });
+              }, BMA.constants.LIMIT_REQUEST_DELAY);
+            }
+            else {
+              resolve(result);
+            }
+          })
+          .catch(function(err){
+            if (err && err.ucode === BMA.errorCodes.HTTP_LIMITATION) {
+              resolve(result);
+            }
+            else {
+              reject(err);
+            }
           });
-      },
-
-      extendAll = function(idties, pubkeyAttributeName, skipAddUid) {
-
-        pubkeyAttributeName = pubkeyAttributeName || 'pubkey';
-
-        var jobs = [];
-        if (!skipAddUid) jobs.push(BMA.wot.member.uids());
-
-        jobs.push(api.data.raisePromise.search(null, idties, pubkeyAttributeName)
-          .catch(function(err) {
-            console.debug('Error while search identities, on extension point.');
-            console.error(err);
-          }));
+      });
+    },
 
-        return $q.all(jobs)
+    extend = function(idty, pubkeyAttributeName, skipAddUid) {
+      return extendAll([idty], pubkeyAttributeName, skipAddUid)
         .then(function(res) {
-          if (!skipAddUid) {
-            var uidsByPubkey = res[0];
-            // Set uid (on every data)
-            _.forEach(idties, function(data) {
-              if (!data.uid && data[pubkeyAttributeName]) {
-                data.uid = uidsByPubkey[data[pubkeyAttributeName]];
-                // Remove name if redundant with uid
-                if (data.uid && data.uid == data.name) {
-                  delete data.name;
-                }
+          return res[0];
+        });
+    },
+
+    extendAll = function(idties, pubkeyAttributeName, skipAddUid) {
+
+      pubkeyAttributeName = pubkeyAttributeName || 'pubkey';
+
+      var jobs = [];
+      if (!skipAddUid) jobs.push(BMA.wot.member.uids());
+
+      jobs.push(api.data.raisePromise.search(null, idties, pubkeyAttributeName)
+        .catch(function(err) {
+          console.debug('Error while search identities, on extension point.');
+          console.error(err);
+        }));
+
+      return $q.all(jobs)
+      .then(function(res) {
+        if (!skipAddUid) {
+          var uidsByPubkey = res[0];
+          // Set uid (on every data)
+          _.forEach(idties, function(data) {
+            if (!data.uid && data[pubkeyAttributeName]) {
+              data.uid = uidsByPubkey[data[pubkeyAttributeName]];
+              // Remove name if redundant with uid
+              if (data.uid && data.uid == data.name) {
+                delete data.name;
               }
-            });
-          }
+            }
+          });
+        }
 
-          return idties;
-        });
-      },
-
-      addEvent = function(data, event) {
-        event = event || {};
-        event.type = event.type || 'info';
-        event.message = event.message || '';
-        event.messageParams = event.messageParams || {};
-        data.events = data.events || [];
-        data.events.push(event);
-      },
-
-      cleanCache = function() {
-        console.debug("[wot] Cleaning cache...");
-        csCache.clear(cachePrefix);
-      }
-    ;
-
-    // Register extension points
-    api.registerEvent('data', 'load');
-    api.registerEvent('data', 'search');
-
-    // Listen if node changed
-    BMA.api.node.on.stop($rootScope, cleanCache, this);
-
-    return {
-      id: id,
-      load: loadData,
-      loadRequirements: loadRequirements,
-      search: search,
-      newcomers: getNewcomers,
-      pending: getPending,
-      all: getAll,
-      extend: extend,
-      extendAll: extendAll,
-      // api extension
-      api: api
-    };
-  }
-
-  var service = csWot('default', BMA);
-
-  service.instance = csWot;
-  return service;
+        return idties;
+      });
+    },
+
+    addEvent = function(data, event) {
+      event = event || {};
+      event.type = event.type || 'info';
+      event.message = event.message || '';
+      event.messageParams = event.messageParams || {};
+      data.events = data.events || [];
+      data.events.push(event);
+    },
+
+    cleanCache = function() {
+      console.debug("[wot] Cleaning cache...");
+      csCache.clear(cachePrefix);
+    }
+  ;
+
+  // Register extension points
+  api.registerEvent('data', 'load');
+  api.registerEvent('data', 'search');
+
+  // Listen if node changed
+  BMA.api.node.on.stop($rootScope, cleanCache, this);
+
+  return {
+    load: loadData,
+    loadRequirements: loadRequirements,
+    search: search,
+    newcomers: getNewcomers,
+    pending: getPending,
+    all: getAll,
+    extend: extend,
+    extendAll: extendAll,
+    // api extension
+    api: api
+  };
 });
diff --git a/www/plugins/es/js/services/network-services.js b/www/plugins/es/js/services/network-services.js
index de4da6d2d06158e05b0b00a6894f34e1ab0232c6..6b653b1b6fb4fc128ddf807b470242edad086f92 100644
--- a/www/plugins/es/js/services/network-services.js
+++ b/www/plugins/es/js/services/network-services.js
@@ -220,13 +220,13 @@ angular.module('cesium.es.network.services', ['ngApi', 'cesium.es.http.services'
                       hasUpdates = true;
                     }
                     else {
-                      console.debug("[network] {0} endpoint [{1}] unchanged".format(
+                      console.debug("[ES] [network] {0} endpoint [{1}] unchanged".format(
                         refreshedPeer.ep && refreshedPeer.ep.api || '',
                         refreshedPeer.server));
                     }
                   }
                   else if (refreshedPeer && (refreshedPeer.online === data.filter.online || data.filter.online === 'all')) {
-                    console.debug("[network] {0} endpoint [{1}] is {2}".format(
+                    console.debug("[ES] [network] {0} endpoint [{1}] is {2}".format(
                       refreshedPeer.ep && refreshedPeer.ep.api || '',
                       refreshedPeer.server,
                       refreshedPeer.online ? 'UP' : 'DOWN'
@@ -328,10 +328,10 @@ angular.module('cesium.es.network.services', ['ngApi', 'cesium.es.http.services'
             }
             if (!peer.secondTry) {
               var ep = peer.ep || peer.getEP();
-              if (ep.dns && peer.server.indexOf(ep.dns) == -1) {
+              if (ep.dns && peer.server.indexOf(ep.dns) === -1) {
                 // try again, using DNS instead of IPv4 / IPV6
                 peer.secondTry = true;
-                peer.api = esHttp.lightInstance(ep.dns, ep.port, ep.useSsl);
+                peer.api = esHttp.lightInstance(ep.dns, peer.getPort(), peer.isSsl(), data.timeout);
                 return refreshPeer(peer); // recursive call
               }
             }
@@ -574,14 +574,14 @@ angular.module('cesium.es.network.services', ['ngApi', 'cesium.es.http.services'
             data.sort = options.sort ? angular.merge(data.sort, options.sort) : data.sort;
             data.expertMode = angular.isDefined(options.expertMode) ? options.expertMode : data.expertMode;
             data.timeout = angular.isDefined(options.timeout) ? options.timeout : csConfig.timeout;
-            console.info('[network] Starting network from [{0}]'.format(data.pod.server));
+            console.info('[ES] [network] Starting network from [{0}]'.format(data.pod.server));
             var now = Date.now();
 
             addListeners();
 
             return loadPeers()
               .then(function(peers){
-                console.debug('[network] Started in '+(Date.now() - now)+'ms');
+                console.debug('[ES] [network] Started in '+(Date.now() - now)+'ms');
                 return peers;
               });
           });
@@ -589,7 +589,7 @@ angular.module('cesium.es.network.services', ['ngApi', 'cesium.es.http.services'
 
       close = function() {
         if (data.pod) {
-          console.info('[network-service] Stopping...');
+          console.info('[ES] [network-service] Stopping...');
           removeListeners();
           resetData();
         }