diff --git a/lib/DataFinder.ts b/lib/DataFinder.ts
index 488d50c56199cdda8b0a1c5b1ab9c2a452fedd81..e2070f66c0957054d4f0a86b3074af2cd7d6e768 100644
--- a/lib/DataFinder.ts
+++ b/lib/DataFinder.ts
@@ -133,14 +133,9 @@ export class DataFinder {
   }
 
   @MonitorExecutionTime()
-  getUidOfPub(pub: string): Promise<{ uid: string }[]> {
+  getUidOfPub(pub: string): Promise<FullIindexEntry> {
     return this.getFromCacheOrDB('getUidOfPub', pub, async () => {
-      const entry = await this.iindex.getFullFromPubkey(pub)
-      if (!entry.uid) {
-        // Not found
-        return []
-      }
-      return [entry]
+      return this.iindex.getFromPubkey(pub)
     })
   }
 
diff --git a/modules/will-members.ts b/modules/will-members.ts
index 1c2664c566595ea5ccec866980e79330a09d2f4b..b1c9abcbf0f5b47b4f77a0ca4d3459c3ec99c4ad 100644
--- a/modules/will-members.ts
+++ b/modules/will-members.ts
@@ -5,6 +5,19 @@ import {showExecutionTimes} from "../lib/MonitorExecutionTime";
 import {DataFinder} from "../lib/DataFinder";
 import {Server} from "duniter/server";
 import {WotBuilder} from "duniter/neon/lib";
+import {
+  DetailedDistance,
+  PendingCert,
+  WillMemberIdentity,
+  WillMemberIdentityWithPendingCerts
+} from "./willMembers/interfaces";
+import {triParDateDeDisponibilite} from "./willMembers/triParDateDeDisponibilite";
+import {WotbIdCache} from "./willMembers/wotbIdCache";
+import {getIdentityListOrdered} from "./willMembers/getIdentityListOrdered";
+import {computeMeansAndCounts} from "./willMembers/computeMeansAndCounts";
+import {getMembersQualityExt} from "./willMembers/getMembersQualityExt";
+import {getSorting} from "./willMembers/getSorting";
+import {SentryChecker} from "./willMembers/issuerIsSentry";
 
 // Préserver les résultats en cache
 let lockWillMembers = false
@@ -13,39 +26,23 @@ let identitiesList: WillMemberIdentity[] = []
 let idtysPendingCertifsList: PendingCert[][] = []
 let nbMaxCertifs = 0
 let countMembersWithSigQtyValidCert = 0
-let sentries = []
-let sentriesIndex = []
-let wotbIdIndex = []
-let meanSentriesReachedByIdtyPerCert: number[] = []
-let meanMembersReachedByIdtyPerCert: number[] = []
-let countIdtiesPerReceiveCert: number[] = []
-let membersQualityExt: { [k: string]: string } = {}
 
 export async function willMembers(duniterServer: Server, days = 65, order = 'desc', sort_by = 'registrationPackage', showIdtyWithZeroCert = 'no', sortSig = 'Availability') {
 
   const dataFinder = await DataFinder.getInstanceReindexedIfNecessary()
-
+  const wotbIdCache = new WotbIdCache(dataFinder)
   // get blockchain timestamp
   let resultQueryCurrentBlock: any = await dataFinder.getCurrentBlockOrNull();
   const currentBlockchainTimestamp = resultQueryCurrentBlock.medianTime;
   const currentMembersCount = resultQueryCurrentBlock.membersCount;
   const currentBlockNumber = resultQueryCurrentBlock.number;
-
   // Initaliser les constantes
   const conf = duniterServer.conf;
   const dSen = Math.ceil(Math.pow(currentMembersCount, 1 / conf.stepMax));
-
-  // Initaliser les variables
-  let errors = "";
-  let idtysListOrdered: WillMemberIdentityWithPendingCerts[]  = []
-
   // Calculer le timestamp limite à prendre en compte
   let limitTimestamp = currentBlockchainTimestamp + (days*86400);
-
   // Alimenter wotb avec la toile de confiance
   const wotbInstance = duniterServer.dal.wotb;
-
-
   // Vérifier si le cache doit être Réinitialiser
   let reinitCache = (Math.floor(Date.now() / 1000) > (willMembersLastUptime + MonitConstants.MIN_WILLMEMBERS_UPDATE_FREQ));
 
@@ -56,397 +53,171 @@ export async function willMembers(duniterServer: Server, days = 65, order = 'des
     reinitCache = false;
   }
 
-  if (reinitCache)
-  {
+  if (reinitCache) {
     // Réinitialiser le cache
     dataFinder.invalidateCache()
     identitiesList = [];
     idtysPendingCertifsList = [];
     nbMaxCertifs = 0;
     countMembersWithSigQtyValidCert = 0;
-    sentries = [];
-    sentriesIndex = [];
-    wotbIdIndex = [];
-    membersQualityExt = {};
     willMembersLastUptime = Math.floor(Date.now() / 1000);
 
     // Récupérer la liste des membres référents
-    sentries = wotbInstance.getSentries(dSen);
+    const sentryChecker = new SentryChecker(wotbInstance.getSentries(dSen))
 
     // Récupérer la liste des identités en piscine
-    const resultQueryIdtys: DBIdentity[] = await dataFinder.findPendingMembers()
+    const pendingMembers: DBIdentity[] = await dataFinder.findPendingMembers()
 
     // Récupérer pour chaque identité, l'ensemble des certifications qu'elle à reçue.
-    for (let i=0;i<resultQueryIdtys.length;i++)
-    {
+    for (const pendingIdty of pendingMembers) {
       // Extraire le numéro de bloc d'émission de l'identité
-      let idtyBlockStamp = resultQueryIdtys[i].buid.split("-");
+      let idtyBlockStamp = pendingIdty.buid.split("-");
       let idtyBlockNumber = idtyBlockStamp[0];
 
       // récupérer le medianTime et le hash du bloc d'émission de l'identité
       let idtyEmittedBlock = await dataFinder.getBlock(parseInt(idtyBlockNumber));
 
       // Récupérer l'identifiant wotex de l'identité (en cas d'identité multiple)
-      let idties = await dataFinder.getWotexInfos(resultQueryIdtys[i].uid);
+      let idties = await dataFinder.getWotexInfos(pendingIdty.uid);
       let wotexId = '';
-      if (idties.length > 1)
-      {
+      if (idties.length > 1) {
         let pos = 0;
-        for (const idty of idties)
-        {
-          if (idty.hash == resultQueryIdtys[i].hash) { wotexId = '['+pos+']'; }
+        for (const idty of idties) {
+          if (idty.hash == pendingIdty.hash) { wotexId = '['+pos+']'; }
           pos++;
         }
       }
 
       // vérifier la validité du blockstamp de l'identité
       let validIdtyBlockStamp = false;
-      if (typeof(idtyEmittedBlock) == 'undefined' || idtyEmittedBlock.hash == idtyBlockStamp[1])
-      { validIdtyBlockStamp = true; }
+      if (typeof(idtyEmittedBlock) == 'undefined' || idtyEmittedBlock.hash == idtyBlockStamp[1]) {
+        validIdtyBlockStamp = true;
+      }
 
       // vérifier si l'identité a été révoquée ou non
       let idtyRevoked = false;
-      if (resultQueryIdtys[i].revocation_sig != null)
-      {
+      if (pendingIdty.revocation_sig != null) {
         idtyRevoked = true;
       }
 
       // Stocker les informations de l'identité
-      identitiesList.push({
+      const identity = {
         BlockNumber: parseInt(idtyBlockNumber),
         creationTimestamp: (typeof(idtyEmittedBlock) == 'undefined' ) ? currentBlockchainTimestamp:idtyEmittedBlock.medianTime,
-        pubkey: resultQueryIdtys[i].pubkey,
-        uid: resultQueryIdtys[i].uid,
-        hash: resultQueryIdtys[i].hash,
+        pubkey: pendingIdty.pubkey,
+        uid: pendingIdty.uid,
+        hash: pendingIdty.hash,
         wotexId: wotexId,
-        expires_on: resultQueryIdtys[i].expires_on || 0,
+        expires_on: pendingIdty.expires_on || 0,
         nbCert: 0,
         nbValidPendingCert: 0,
         registrationAvailability: 0,
         validBlockStamp: validIdtyBlockStamp,
         idtyRevoked: idtyRevoked
-      });
-      idtysPendingCertifsList.push([])
+      }
+      identitiesList.push(identity);
+      const pendingCertifications: PendingCert[] = []
 
       // récupérer l'ensemble des certifications en attente destinées à l'identité courante
-      let tmpQueryPendingCertifsList = await dataFinder.findPendingCertsToTarget(resultQueryIdtys[i].pubkey, resultQueryIdtys[i].hash);
+      let pendingCerts = await dataFinder.findPendingCertsToTarget(pendingIdty.pubkey, pendingIdty.hash);
 
       // Récupérer les uid des émetteurs des certifications reçus par l'utilisateur
       // Et stocker les uid et dates d'expiration dans un tableau
-      for (let j=0;j<tmpQueryPendingCertifsList.length;j++)
-      {
+      for (const pendingCert of pendingCerts) {
         // Récupérer le medianTime et le hash du bloc d'émission de la certification
-        let emittedBlock = await dataFinder.getBlock(tmpQueryPendingCertifsList[j].block_number)
+        let emittedBlock = await dataFinder.getBlock(pendingCert.block_number)
 
         // Vérifier que l'émetteur de la certification correspond à une identité inscrite en blockchain
-        let tmpQueryGetUidIssuerPendingCert = await dataFinder.getUidOfPub(tmpQueryPendingCertifsList[j].from)
-        if (emittedBlock && tmpQueryGetUidIssuerPendingCert.length > 0)
-        {
+        let member = await dataFinder.getUidOfPub(pendingCert.from)
+        if (emittedBlock && member) {
           // Récupérer la pubkey de l'émetteur
-          let issuerPubkey = tmpQueryPendingCertifsList[j].from;
+          let issuerPubkey = pendingCert.from;
 
           // Récupérer le wotb_id
-          let wotb_id = 0;
-          if (typeof(wotbIdIndex[issuerPubkey]) == 'undefined')
-          {
-            wotb_id = await dataFinder.getWotbIdByIssuerPubkey(issuerPubkey)
-            wotbIdIndex[issuerPubkey] = wotb_id;
-          }
-          else { wotb_id = wotbIdIndex[issuerPubkey]; }
+          let wotb_id = await wotbIdCache.getWotbId(issuerPubkey)
 
           // Vérifier si l'émetteur de la certification est référent
-          let issuerIsSentry = false;
-          if (typeof(sentriesIndex[issuerPubkey]) == 'undefined')
-          {
-            sentriesIndex[issuerPubkey] = false;
-            for (let s=0;s<sentries.length;s++)
-            {
-              if (sentries[s] == wotb_id)
-              {
-                issuerIsSentry=true;
-                sentriesIndex[issuerPubkey] = true;
-                sentries.splice(s, 1);
-              }
-            }
-          }
-          else { issuerIsSentry = sentriesIndex[issuerPubkey]; }
+          let issuerIsSentry = sentryChecker.isIssuerSentry(issuerPubkey, wotb_id);
 
           // Vérifier si le blockstamp est correct
-          var validBlockStamp = false;
-          if (emittedBlock.hash == tmpQueryPendingCertifsList[j].block_hash)
-          { validBlockStamp = true; }
-
+          const validBlockStamp = emittedBlock.hash == pendingCert.block_hash;
           // récupérer le timestamp d'enchainement de la dernière certification écrite par l'émetteur
           let tmpQueryLastIssuerCert = await dataFinder.getChainableOnByIssuerPubkey(issuerPubkey)
           let certTimestampWritable = 0;
-          if ( typeof(tmpQueryLastIssuerCert[0]) != 'undefined' && typeof(tmpQueryLastIssuerCert[0].chainable_on) != 'undefined' )
-          { certTimestampWritable = tmpQueryLastIssuerCert[0].chainable_on; }
-          //identitiesList[i].registrationAvailability = (certTimestampWritable > identitiesList[i].registrationAvailability) ? certTimestampWritable : identitiesList[i].registrationAvailability;
+          if ( typeof(tmpQueryLastIssuerCert[0]) != 'undefined' && typeof(tmpQueryLastIssuerCert[0].chainable_on) != 'undefined' ) {
+            certTimestampWritable = tmpQueryLastIssuerCert[0].chainable_on;
+          }
+          //identity.registrationAvailability = (certTimestampWritable > identity.registrationAvailability) ? certTimestampWritable : identity.registrationAvailability;
 
           // Vérifier que l'identité courant n'a pas déjà reçu d'autre(s) certification(s) de la part du même membre ET dans le même état de validité du blockstamp
-          let doubloonPendingCertif = false;
-          for (const pendingCert of idtysPendingCertifsList[i])
-          {
-            if (pendingCert.from == tmpQueryGetUidIssuerPendingCert[0].uid && pendingCert.validBlockStamp == validBlockStamp)
-            {
-              doubloonPendingCertif = true;
-            }
-          }
-          if (!doubloonPendingCertif)
-          {
+          let doubloonPendingCertif = pendingCertifications.filter(c => c.from == member.uid && c.validBlockStamp == validBlockStamp).length > 0;
+          if (!doubloonPendingCertif) {
             // Stoker la liste des certifications en piscine qui n'ont pas encore expirées
-            if (tmpQueryPendingCertifsList[j].expires_on > currentBlockchainTimestamp)
-            {
-              idtysPendingCertifsList[i].push({
-                from: tmpQueryGetUidIssuerPendingCert[0].uid,
+            if (pendingCert.expires_on > currentBlockchainTimestamp) {
+              pendingCertifications.push({
+                from: member.uid,
                 pubkey: issuerPubkey,
                 wotb_id: wotb_id,
                 issuerIsSentry: issuerIsSentry,
-                blockNumber: tmpQueryPendingCertifsList[j].block_number,
+                blockNumber: pendingCert.block_number,
                 creationTimestamp: emittedBlock.medianTime,
-                timestampExpire: tmpQueryPendingCertifsList[j].expires_on,
+                timestampExpire: pendingCert.expires_on,
                 timestampWritable: certTimestampWritable,
                 validBlockStamp: validBlockStamp
               });
-              identitiesList[i].nbCert++;
-              if (validBlockStamp) { identitiesList[i].nbValidPendingCert++; }
+              identity.nbCert++;
+              if (validBlockStamp) { identity.nbValidPendingCert++; }
             }
           }
         }
       }
+      idtysPendingCertifsList.push(pendingCertifications)
 
       // Calculer le nombre maximal de certifications reçues par l'identité courante
-      if ( identitiesList[i].nbCert > nbMaxCertifs) { nbMaxCertifs = identitiesList[i].nbCert; }
+      if ( identity.nbCert > nbMaxCertifs) {
+        nbMaxCertifs = identity.nbCert;
+      }
 
       // calculate countMembersWithSigQtyValidCert
-      if ( identitiesList[i].nbValidPendingCert >= conf.sigQty) { countMembersWithSigQtyValidCert++; }
+      if ( identity.nbValidPendingCert >= conf.sigQty) {
+        countMembersWithSigQtyValidCert++;
+      }
     }  // END IDENTITIES LOOP
-
-    // Réinitialiser sumSentriesReachedByIdtyPerCert, sumMembersReachedByIdtyPerCert et countIdtiesPerReceiveCert
-    for (let i=0;i<=nbMaxCertifs;i++)
-    {
-      meanSentriesReachedByIdtyPerCert[i] = 0;
-      meanMembersReachedByIdtyPerCert[i] = 0;
-      countIdtiesPerReceiveCert[i] = 0;
-    }
   } // END if (reinitCache)
 
   // Si demandé, retrier les, certifications par date de disponibilité
-  if (sortSig == "Availability")
-  {
-    const idtysPendingCertifsListSort: PendingCert[][] = [ [] ];
-    for (var i=0;i<idtysPendingCertifsList.length;i++)
-    {
-      idtysPendingCertifsListSort[i] = Array();
-      let min;
-      let idMin =0;
-      let tmpExcluded = Array();
-      for (let j=0;j<idtysPendingCertifsList[i].length;j++) { tmpExcluded[j] = false; }
-      for (let j=0;j<idtysPendingCertifsList[i].length;j++)
-      {
-        min = currentBlockchainTimestamp+conf.sigValidity; // begin to min = max
-
-        // search idMin (id of certif with min timestampWritable)
-        for (let k=0;k<idtysPendingCertifsList[i].length;k++)
-        {
-          if (idtysPendingCertifsList[i][k].timestampWritable < min && !tmpExcluded[k])
-          {
-            min = idtysPendingCertifsList[i][k].timestampWritable;
-            idMin = k;
-          }
-        }
-
-        // Push min value on sort table
-        idtysPendingCertifsListSort[i].push({
-          from: idtysPendingCertifsList[i][idMin].from,
-          wotb_id: idtysPendingCertifsList[i][idMin].wotb_id,
-          issuerIsSentry: idtysPendingCertifsList[i][idMin].issuerIsSentry,
-          blockNumber: idtysPendingCertifsList[i][idMin].blockNumber,
-          creationTimestamp: idtysPendingCertifsList[i][idMin].creationTimestamp,
-          timestampExpire: idtysPendingCertifsList[i][idMin].timestampExpire,
-          timestampWritable: idtysPendingCertifsList[i][idMin].timestampWritable,
-          validBlockStamp: idtysPendingCertifsList[i][idMin].validBlockStamp
-        });
-
-        // Calculer la date de disponibilité du dossier d'inscription de l'identité correspondante
-        // := date de disponibilité maximale parmi les sigQty certifications aux dates de disponibilités les plus faibles
-        if (j<conf.sigQty)
-        {
-          let timestampWritable = idtysPendingCertifsList[i][idMin].timestampWritable;
-          identitiesList[i].registrationAvailability = (timestampWritable > identitiesList[i].registrationAvailability) ? timestampWritable : identitiesList[i].registrationAvailability;
-        }
-
-        // Exclure la valeur min avant de poursuivre le tri
-        tmpExcluded[idMin] = true;
-      }
-
-    }
-    idtysPendingCertifsList = idtysPendingCertifsListSort;
+  if (sortSig == "Availability") {
+    idtysPendingCertifsList = triParDateDeDisponibilite(idtysPendingCertifsList, conf, currentBlockchainTimestamp, identitiesList)
   }
 
   // Récupérer la valeur du critère de tri pour chaque identité
-  var tabSort = [];
-  if (sort_by == "creationIdty")
-  {
-    for (const idty of identitiesList)
-    {
-      tabSort.push(idty.expires_on);
-    }
-  }
-  else if (sort_by == "sigCount" || sort_by == "registrationPackage")
-  {
-    for (const idty of identitiesList)
-    {
-      // Calculate registrationAvailabilityDelay
-      let registrationAvailabilityDelay = (idty.registrationAvailability > currentBlockchainTimestamp) ? (idty.registrationAvailability-currentBlockchainTimestamp):0;
-
-      // Trier les identités par date de disponibilité de leur dossier d'inscription (le signe moins est nécessaire car plus un dossier est disponible tôt
-      //  plus la valeur de registrationAvailabilityDelay sera petite, hors le nombre obtenu est classé de façon décroissante)
-      // Attribuer un malus de 2*sigValidity secondes par certification valide (plafonner à sigQty dans le cas de 'registrationPackage')
-      if (sort_by == "registrationPackage" && idty.nbValidPendingCert > conf.sigQty)
-      {
-        tabSort.push(-registrationAvailabilityDelay + (2*conf.sigValidity*conf.sigQty));
-      }
-      else
-      {
-        tabSort.push(-registrationAvailabilityDelay + (2*conf.sigValidity*idty.nbValidPendingCert));
-      }
-    }
-  }
-  else { errors += "<p>ERREUR : param <i>sort_by</i> invalid !</p>"; }
-
-  // Trier les identités par ordre decroissant du critère sort_by
-  for (var i=0;i<identitiesList.length;i++)
-  {
-    let max = -1;
-    let idMax =0;
-    for (var j=0;j<identitiesList.length;j++)
-    {
-      if (tabSort[j] > max)
-      {
-        max = tabSort[j];
-        idMax = j;
-      }
-    }
+  let tabSort = getSorting(identitiesList, sort_by, currentBlockchainTimestamp, conf)
 
-    // Push max value on sort table, only if respect days limit
-    if (limitTimestamp > identitiesList[idMax].expires_on)
-    {
-      // Vérifier que cette identité n'a pas déjà été prise en compte (empecher les doublons)
-      let doubloon = false;
-      for (const idty of idtysListOrdered)
-      {
-        if (identitiesList[idMax].uid == idty.uid && identitiesList[idMax].BlockNumber == idty.BlockNumber)
-        {
-          doubloon = true;
-        }
-      }
-
-      // Push max value on sort table (and test distance rule)
-      if (!doubloon)
-      {
-        // Tester la présence de l'adhésion
-        let membership: DBMembership|null = null
-        const pendingMembershipsOfIdty: DBMembership[] = await duniterServer.dal.msDAL.getPendingINOfTarget(identitiesList[idMax].hash as string);
-        for (const ms of pendingMembershipsOfIdty)
-        {
-          if (!membership && ms.expires_on > currentBlockchainTimestamp)
-          {
-            membership = ms
-          }
-        }
-
-        // Créer une wot temporaire
-        let tmpWot = WotBuilder.fromWot(wotbInstance);
-
-        // Mesurer la qualité externe de chaque emetteur de chaque certification
-        for (const cert of idtysPendingCertifsList[idMax]) {
-          if (typeof (membersQualityExt[cert.from]) == 'undefined') {
-            const detailedDistanceQualityExt: DetailedDistance = tmpWot.detailedDistance(cert.wotb_id, dSen, conf.stepMax - 1, conf.xpercent);
-            membersQualityExt[cert.from] = ((detailedDistanceQualityExt.nbSuccess / detailedDistanceQualityExt.nbSentries) / conf.xpercent).toFixed(2);
-          }
-        }
-
-        // Ajouter un noeud a la wot temporaire et lui donner toute les certifications valides reçues par l'indentité idMax
-        let pendingIdtyWID = tmpWot.addNode();
-        for (const cert of idtysPendingCertifsList[idMax])
-        {
-          if (cert.validBlockStamp)
-          {
-            tmpWot.addLink(cert.wotb_id, pendingIdtyWID);
-          }
-        }
-        // Récupérer les données de distance du dossier d'adhésion de l'indentité idMax
-        let detailedDistance = tmpWot.detailedDistance(pendingIdtyWID, dSen, conf.stepMax, conf.xpercent);
-
-        // Nettoyer la wot temporaire
-        tmpWot.clear();
-
-        // Calculer percentSentriesReached et percentMembersReached
-        let percentSentriesReached = parseFloat(((detailedDistance.nbSuccess/detailedDistance.nbSentries)*100).toFixed(2));
-        let percentMembersReached = parseFloat(((detailedDistance.nbReached/currentMembersCount)*100).toFixed(2));
-
-        // Pousser l'identité dans le tableau idtysListOrdered
-        idtysListOrdered.push({
-          uid: identitiesList[idMax].uid,
-          wotexId: identitiesList[idMax].wotexId,
-          creationTimestamp: identitiesList[idMax].creationTimestamp,
-          pubkey: identitiesList[idMax].pubkey,
-          BlockNumber: identitiesList[idMax].BlockNumber,
-          expires_on: identitiesList[idMax].expires_on,
-          nbCert: identitiesList[idMax].nbCert,
-          registrationAvailability: identitiesList[idMax].registrationAvailability,
-          nbValidPendingCert: identitiesList[idMax].nbValidPendingCert,
-          detailedDistance,
-          percentSentriesReached,
-          percentMembersReached,
-          membership,
-          pendingCertifications: idtysPendingCertifsList[idMax],
-          validBlockStamp: identitiesList[idMax].validBlockStamp,
-          idtyRevoked: identitiesList[idMax].idtyRevoked
-        });
+  // Trier les identités
+  let idtysListOrdered: WillMemberIdentityWithPendingCerts[] = await getIdentityListOrdered(
+    identitiesList,
+    idtysPendingCertifsList,
+    currentBlockchainTimestamp,
+    currentMembersCount,
+    limitTimestamp,
+    wotbInstance,
+    duniterServer,
+    conf,
+    dSen,
+    tabSort,
+    order)
 
-        // Si le cache a été réinitialiser, recalculer les sommes meanSentriesReachedByIdtyPerCert et meanMembersReachedByIdtyPerCert
-        if (reinitCache && identitiesList[idMax].nbValidPendingCert > 0)
-        {
-          let nbReceiveCert = identitiesList[idMax].nbValidPendingCert;
-          meanSentriesReachedByIdtyPerCert[nbReceiveCert-1] += percentSentriesReached;
-          meanMembersReachedByIdtyPerCert[nbReceiveCert-1] += percentMembersReached;
-          countIdtiesPerReceiveCert[nbReceiveCert-1] += 1;
-        }
-      } // END if (!doubloon)
-    }  // END days limit rule
+  console.log('Calcul des qualités...')
 
-    // Exclure la valeur max avant de poursuivre le tri
-    tabSort[idMax] = -1;
-  }  // End sort identities loop
+  let membersQualityExt = getMembersQualityExt(wotbInstance, idtysListOrdered, conf, dSen)
 
-  // Si ordre croissant demandé, inverser le tableau
-  if (order == 'asc')
-  {
-    const idtysListOrdered2: WillMemberIdentityWithPendingCerts[] = []
-    let tmpIdtysListOrderedLength = idtysListOrdered.length;
-    for (let i=0;i<tmpIdtysListOrderedLength;i++)
-    {
-      idtysListOrdered2[i] = idtysListOrdered[tmpIdtysListOrderedLength-i-1];
-    }
-    idtysListOrdered = idtysListOrdered2;
-  }
+  console.log('Calcul des moyennes...')
+  const {
+    meanSentriesReachedByIdtyPerCert,
+    meanMembersReachedByIdtyPerCert,
+  } = computeMeansAndCounts(idtysListOrdered, nbMaxCertifs)
 
   if (reinitCache) {
-    // Calculate meanSentriesReachedByIdtyPerCert and meanMembersReachedByIdtyPerCert
-    for (let i = 0; i <= nbMaxCertifs; i++) {
-      if (countIdtiesPerReceiveCert[i] > 0) {
-        meanSentriesReachedByIdtyPerCert[i] = parseFloat((meanSentriesReachedByIdtyPerCert[i] / countIdtiesPerReceiveCert[i]).toFixed(2));
-        meanMembersReachedByIdtyPerCert[i] = parseFloat((meanMembersReachedByIdtyPerCert[i] / countIdtiesPerReceiveCert[i]).toFixed(2));
-      }
-      else {
-        meanSentriesReachedByIdtyPerCert[i] = 0.0;
-        meanMembersReachedByIdtyPerCert[i] = 0.0;
-      }
-    }
-
-    // Dévérouiller le cache willMembers
     lockWillMembers = false;
   }
 
@@ -472,48 +243,3 @@ export async function willMembers(duniterServer: Server, days = 65, order = 'des
     membersQualityExt,
   }
 }
-
-interface PendingCert {
-  from: string
-  pubkey?: string
-  wotb_id: number
-  issuerIsSentry: boolean
-  blockNumber: number
-  creationTimestamp: number
-  timestampExpire: number
-  timestampWritable: number
-  validBlockStamp: boolean
-}
-
-interface DetailedDistance {
-  nbSentries: number;
-  nbSuccess: number;
-  nbSuccessAtBorder: number;
-  nbReached: number;
-  nbReachedAtBorder: number;
-  isOutdistanced: number;
-}
-
-interface WillMemberIdentity {
-  BlockNumber: number
-  creationTimestamp: number
-  pubkey: string
-  uid: string
-  hash?: string
-  wotexId: string
-  expires_on: number
-  nbCert: number
-  nbValidPendingCert: number
-  registrationAvailability: number
-  detailedDistance?: DetailedDistance
-  pendingCertifications?: PendingCert[]
-  validBlockStamp: boolean
-  idtyRevoked: boolean
-  percentSentriesReached?: number
-  percentMembersReached?: number
-  membership?: DBMembership|null
-}
-
-interface WillMemberIdentityWithPendingCerts extends WillMemberIdentity {
-  pendingCertifications: PendingCert[]
-}
diff --git a/modules/willMembers/computeMeansAndCounts.ts b/modules/willMembers/computeMeansAndCounts.ts
new file mode 100644
index 0000000000000000000000000000000000000000..62abe0b5ad31220f2bd769cd4aa2f818ad5059d0
--- /dev/null
+++ b/modules/willMembers/computeMeansAndCounts.ts
@@ -0,0 +1,40 @@
+import {WillMemberIdentityWithPendingCerts} from "./interfaces";
+
+export function computeMeansAndCounts(idtysListOrdered: WillMemberIdentityWithPendingCerts[], nbMaxCertifs: number) {
+  const meanSentriesReachedByIdtyPerCert: number[] = []
+  const meanMembersReachedByIdtyPerCert: number[] = []
+  const countIdtiesPerReceiveCert: number[] = []
+  // Réinitialiser sumSentriesReachedByIdtyPerCert, sumMembersReachedByIdtyPerCert et countIdtiesPerReceiveCert
+  for (let i=0; i<=nbMaxCertifs; i++) {
+    meanSentriesReachedByIdtyPerCert[i] = 0;
+    meanMembersReachedByIdtyPerCert[i] = 0;
+    countIdtiesPerReceiveCert[i] = 0;
+  }
+
+  idtysListOrdered.forEach(pendingIdty => {
+    // Si le cache a été réinitialiser, recalculer les sommes meanSentriesReachedByIdtyPerCert et meanMembersReachedByIdtyPerCert
+    if (pendingIdty.nbValidPendingCert > 0) {
+      let nbReceiveCert = pendingIdty.nbValidPendingCert;
+      meanSentriesReachedByIdtyPerCert[nbReceiveCert-1] += pendingIdty.percentSentriesReached;
+      meanMembersReachedByIdtyPerCert[nbReceiveCert-1] += pendingIdty.percentMembersReached;
+      countIdtiesPerReceiveCert[nbReceiveCert-1] += 1;
+    }
+  })
+
+  // Calculate meanSentriesReachedByIdtyPerCert and meanMembersReachedByIdtyPerCert
+  for (let i = 0; i <= nbMaxCertifs; i++) {
+    if (countIdtiesPerReceiveCert[i] > 0) {
+      meanSentriesReachedByIdtyPerCert[i] = parseFloat((meanSentriesReachedByIdtyPerCert[i] / countIdtiesPerReceiveCert[i]).toFixed(2));
+      meanMembersReachedByIdtyPerCert[i] = parseFloat((meanMembersReachedByIdtyPerCert[i] / countIdtiesPerReceiveCert[i]).toFixed(2));
+    }
+    else {
+      meanSentriesReachedByIdtyPerCert[i] = 0.0;
+      meanMembersReachedByIdtyPerCert[i] = 0.0;
+    }
+  }
+
+  return {
+    meanSentriesReachedByIdtyPerCert,
+    meanMembersReachedByIdtyPerCert
+  }
+}
\ No newline at end of file
diff --git a/modules/willMembers/getIdentityListOrdered.ts b/modules/willMembers/getIdentityListOrdered.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8c38a08a104c2b9b1065533801be786fec50eaf5
--- /dev/null
+++ b/modules/willMembers/getIdentityListOrdered.ts
@@ -0,0 +1,121 @@
+import {DBMembership} from "duniter/app/lib/dal/sqliteDAL/MembershipDAL";
+import {Wot, WotBuilder} from "duniter/neon/lib";
+import {DetailedDistance, PendingCert, WillMemberIdentity, WillMemberIdentityWithPendingCerts} from "./interfaces";
+import {Server} from "duniter/server";
+import {ConfDTO} from "duniter/app/lib/dto/ConfDTO";
+
+export async function getIdentityListOrdered(identitiesList: WillMemberIdentity[],
+                                       idtysPendingCertifsList: PendingCert[][],
+                                       currentBlockchainTimestamp: number,
+                                       currentMembersCount: number,
+                                       limitTimestamp: number,
+                                       wotbInstance: Wot,
+                                       duniterServer: Server,
+                                       conf: ConfDTO,
+                                       dSen: number,
+                                       tabSort: number[],
+                                       order: string
+): Promise<WillMemberIdentityWithPendingCerts[]> {
+
+  let idtysListOrdered: WillMemberIdentityWithPendingCerts[] = []
+  for (let i=0; i<identitiesList.length; i++) {
+    let max = -1;
+    let idMax =0;
+    for (let j=0; j<identitiesList.length; j++) {
+      if (tabSort[j] > max) {
+        max = tabSort[j];
+        idMax = j;
+      }
+    }
+    const pendingIdty = identitiesList[idMax]
+    const certsToPending = idtysPendingCertifsList[idMax]
+
+    // Push max value on sort table, only if respect days limit
+    if (limitTimestamp <= pendingIdty.expires_on) {
+      // Exclure la valeur max avant de poursuivre le tri
+      tabSort[idMax] = -1;
+      console.log(`Traitement de l'identité ${i+1}/${identitiesList.length} (${pendingIdty.uid}) : expirée`)
+      continue;
+    }
+
+    // Vérifier que cette identité n'a pas déjà été prise en compte (empecher les doublons)
+    let doubloon = idtysListOrdered.filter(idty => pendingIdty.uid == idty.uid && pendingIdty.BlockNumber == idty.BlockNumber).length;
+    if (doubloon) {
+      // Exclure la valeur max avant de poursuivre le tri
+      tabSort[idMax] = -1;
+      console.log(`Traitement de l'identité ${i+1}/${identitiesList.length} (${pendingIdty.uid}) : doublon`)
+      continue;
+    }
+    console.log(`Traitement de l'identité ${i+1}/${identitiesList.length} (${pendingIdty.uid})...`)
+
+    // Push max value on sort table (and test distance rule)
+
+    // Tester la présence de l'adhésion
+    const pendingMembershipsOfIdty: DBMembership[] = await duniterServer.dal.msDAL.getPendingINOfTarget(pendingIdty.hash as string);
+    let membership: DBMembership|null = pendingMembershipsOfIdty.filter(ms => ms.expires_on > currentBlockchainTimestamp)[0]
+
+    // Créer une wot temporaire
+    let tmpWot = WotBuilder.fromWot(wotbInstance);
+
+    // Ajouter un noeud a la wot temporaire et lui donner toute les certifications valides reçues par l'indentité en attente
+    let pendingIdtyWID = tmpWot.addNode();
+    for (const cert of certsToPending) {
+      if (cert.validBlockStamp) {
+        tmpWot.addLink(cert.wotb_id, pendingIdtyWID);
+      }
+    }
+    // Récupérer les données de distance du dossier d'adhésion de l'indentité idMax
+    let detailedDistance = tmpWot.detailedDistance(pendingIdtyWID, dSen, conf.stepMax, conf.xpercent);
+
+    // Nettoyer la wot temporaire
+    tmpWot.clear();
+
+    // Calculer percentSentriesReached et percentMembersReached
+    let percentSentriesReached = parseFloat(((detailedDistance.nbSuccess/detailedDistance.nbSentries)*100).toFixed(2));
+    let percentMembersReached = parseFloat(((detailedDistance.nbReached/currentMembersCount)*100).toFixed(2));
+    // const percentSentriesReached = 0
+    // const percentMembersReached = 0
+    // const detailedDistance: DetailedDistance = {
+    //   isOutdistanced: 0,
+    //   nbReached: 0,
+    //   nbReachedAtBorder: 0,
+    //   nbSentries: 0,
+    //   nbSuccessAtBorder: 0,
+    //   nbSuccess: 0
+    // }
+
+    // Pousser l'identité dans le tableau idtysListOrdered
+    idtysListOrdered.push({
+      uid: pendingIdty.uid,
+      wotexId: pendingIdty.wotexId,
+      creationTimestamp: pendingIdty.creationTimestamp,
+      pubkey: pendingIdty.pubkey,
+      BlockNumber: pendingIdty.BlockNumber,
+      expires_on: pendingIdty.expires_on,
+      nbCert: pendingIdty.nbCert,
+      registrationAvailability: pendingIdty.registrationAvailability,
+      nbValidPendingCert: pendingIdty.nbValidPendingCert,
+      detailedDistance,
+      percentSentriesReached,
+      percentMembersReached,
+      membership,
+      pendingCertifications: certsToPending,
+      validBlockStamp: pendingIdty.validBlockStamp,
+      idtyRevoked: pendingIdty.idtyRevoked
+    });
+    // Exclure la valeur max avant de poursuivre le tri
+    tabSort[idMax] = -1;
+  }
+
+  // Si ordre croissant demandé, inverser le tableau
+  if (order == 'asc') {
+    const idtysListOrdered2: WillMemberIdentityWithPendingCerts[] = []
+    let tmpIdtysListOrderedLength = idtysListOrdered.length;
+    for (let i=0;i<tmpIdtysListOrderedLength;i++) {
+      idtysListOrdered2[i] = idtysListOrdered[tmpIdtysListOrderedLength-i-1];
+    }
+    idtysListOrdered = idtysListOrdered2;
+  }
+
+  return idtysListOrdered
+}
\ No newline at end of file
diff --git a/modules/willMembers/getMembersQualityExt.ts b/modules/willMembers/getMembersQualityExt.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4970d8e70b27076584dd05a381f714b1a901e279
--- /dev/null
+++ b/modules/willMembers/getMembersQualityExt.ts
@@ -0,0 +1,30 @@
+import {Wot, WotBuilder} from "duniter/neon/lib";
+import {DetailedDistance, WillMemberIdentityWithPendingCerts} from "./interfaces";
+import {ConfDTO} from "duniter/app/lib/dto/ConfDTO";
+
+export function getMembersQualityExt(wotbInstance: Wot,
+                                     idtysListOrdered: WillMemberIdentityWithPendingCerts[],
+                                     conf: ConfDTO,
+                                     dSen: number
+): { [k: string]: string } {
+  let membersQualityExt: { [k: string]: string } = {}
+  const nbIdentites = idtysListOrdered.length
+  let i = 0
+  idtysListOrdered.forEach(pendingIdty => {
+    console.log(`Qualité de l'identité ${i+1}/${nbIdentites}`)
+    // Créer une wot temporaire
+    // let tmpWot = WotBuilder.fromWot(wotbInstance);
+    // Mesurer la qualité externe de chaque emetteur de chaque certification
+    for (const cert of pendingIdty.pendingCertifications) {
+      if (typeof (membersQualityExt[cert.from]) == 'undefined') {
+        // const detailedDistanceQualityExt: DetailedDistance = tmpWot.detailedDistance(cert.wotb_id, dSen, conf.stepMax - 1, conf.xpercent);
+        // membersQualityExt[cert.from] = ((detailedDistanceQualityExt.nbSuccess / detailedDistanceQualityExt.nbSentries) / conf.xpercent).toFixed(2);
+        membersQualityExt[cert.from] = "9.99"
+      }
+    }
+    // Vider la mémoire
+    // tmpWot.clear()
+    i++
+  })
+  return membersQualityExt
+}
\ No newline at end of file
diff --git a/modules/willMembers/getSorting.ts b/modules/willMembers/getSorting.ts
new file mode 100644
index 0000000000000000000000000000000000000000..efe1d0604c85dd950d36cdb2223b5b12103b2f14
--- /dev/null
+++ b/modules/willMembers/getSorting.ts
@@ -0,0 +1,26 @@
+import {WillMemberIdentity} from "./interfaces";
+import {ConfDTO} from "duniter/app/lib/dto/ConfDTO";
+
+export function getSorting(identitiesList: WillMemberIdentity[], sort_by: string, currentBlockchainTimestamp: any, conf: ConfDTO): number[] {
+  let tabSort: number[] = []
+  if (sort_by == "creationIdty") {
+    tabSort = identitiesList.map(i => i.expires_on)
+  }
+  else if (sort_by == "sigCount" || sort_by == "registrationPackage") {
+    for (const idty of identitiesList) {
+      // Calculate registrationAvailabilityDelay
+      let registrationAvailabilityDelay = (idty.registrationAvailability > currentBlockchainTimestamp) ? (idty.registrationAvailability-currentBlockchainTimestamp):0;
+
+      // Trier les identités par date de disponibilité de leur dossier d'inscription (le signe moins est nécessaire car plus un dossier est disponible tôt
+      //  plus la valeur de registrationAvailabilityDelay sera petite, hors le nombre obtenu est classé de façon décroissante)
+      // Attribuer un malus de 2*sigValidity secondes par certification valide (plafonner à sigQty dans le cas de 'registrationPackage')
+      if (sort_by == "registrationPackage" && idty.nbValidPendingCert > conf.sigQty) {
+        tabSort.push(-registrationAvailabilityDelay + (2*conf.sigValidity*conf.sigQty));
+      }
+      else {
+        tabSort.push(-registrationAvailabilityDelay + (2*conf.sigValidity*idty.nbValidPendingCert));
+      }
+    }
+  }
+  return tabSort
+}
\ No newline at end of file
diff --git a/modules/willMembers/interfaces.ts b/modules/willMembers/interfaces.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c409ea0306575f16335b0fa86e385bee482ab2d9
--- /dev/null
+++ b/modules/willMembers/interfaces.ts
@@ -0,0 +1,48 @@
+import {DBMembership} from "duniter/app/lib/dal/sqliteDAL/MembershipDAL";
+
+export interface PendingCert {
+  from: string
+  pubkey?: string
+  wotb_id: number
+  issuerIsSentry: boolean
+  blockNumber: number
+  creationTimestamp: number
+  timestampExpire: number
+  timestampWritable: number
+  validBlockStamp: boolean
+}
+
+export interface DetailedDistance {
+  nbSentries: number;
+  nbSuccess: number;
+  nbSuccessAtBorder: number;
+  nbReached: number;
+  nbReachedAtBorder: number;
+  isOutdistanced: number;
+}
+
+export interface WillMemberIdentity {
+  BlockNumber: number
+  creationTimestamp: number
+  pubkey: string
+  uid: string
+  hash?: string
+  wotexId: string
+  expires_on: number
+  nbCert: number
+  nbValidPendingCert: number
+  registrationAvailability: number
+  detailedDistance?: DetailedDistance
+  pendingCertifications?: PendingCert[]
+  validBlockStamp: boolean
+  idtyRevoked: boolean
+  percentSentriesReached?: number
+  percentMembersReached?: number
+  membership?: DBMembership|null
+}
+
+export interface WillMemberIdentityWithPendingCerts extends WillMemberIdentity {
+  pendingCertifications: PendingCert[]
+  percentSentriesReached: number
+  percentMembersReached: number
+}
\ No newline at end of file
diff --git a/modules/willMembers/issuerIsSentry.ts b/modules/willMembers/issuerIsSentry.ts
new file mode 100644
index 0000000000000000000000000000000000000000..556549d847a22876a63f26b342d44fe5d3dd6e6e
--- /dev/null
+++ b/modules/willMembers/issuerIsSentry.ts
@@ -0,0 +1,25 @@
+export class SentryChecker {
+
+  private sentriesIndex: { [k: string]: boolean } = {}
+
+
+  constructor(private sentries: number[]) {
+  }
+
+  isIssuerSentry(issuerPubkey: string, wotb_id: number): boolean {
+    if (typeof(this.sentriesIndex[issuerPubkey]) == 'undefined') {
+      this.sentriesIndex[issuerPubkey] = false;
+      for (let s=0;s<this.sentries.length;s++) {
+        if (this.sentries[s] == wotb_id) {
+          this.sentriesIndex[issuerPubkey] = true;
+          this.sentries.splice(s, 1);
+          return true
+        }
+      }
+      return false
+    }
+    else {
+      return this.sentriesIndex[issuerPubkey];
+    }
+  }
+}
\ No newline at end of file
diff --git a/modules/willMembers/triParDateDeDisponibilite.ts b/modules/willMembers/triParDateDeDisponibilite.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0c5b0ac055e7ca528f1468f2aa08722a22307c5d
--- /dev/null
+++ b/modules/willMembers/triParDateDeDisponibilite.ts
@@ -0,0 +1,57 @@
+import {PendingCert, WillMemberIdentity} from "./interfaces";
+import {ConfDTO} from "duniter/app/lib/dto/ConfDTO";
+
+export function triParDateDeDisponibilite(idtysPendingCertifsList: PendingCert[][],
+                                          conf: ConfDTO,
+                                          currentBlockchainTimestamp: number,
+                                          identitiesList: WillMemberIdentity[]) {
+
+  const idtysPendingCertifsListSort: PendingCert[][] = [ [] ];
+  for (var i=0;i<idtysPendingCertifsList.length;i++)
+  {
+    idtysPendingCertifsListSort[i] = Array();
+    let min;
+    let idMin =0;
+    let tmpExcluded = Array();
+    for (let j=0;j<idtysPendingCertifsList[i].length;j++) { tmpExcluded[j] = false; }
+    for (let j=0;j<idtysPendingCertifsList[i].length;j++)
+    {
+      min = currentBlockchainTimestamp+conf.sigValidity; // begin to min = max
+
+      // search idMin (id of certif with min timestampWritable)
+      for (let k=0;k<idtysPendingCertifsList[i].length;k++)
+      {
+        if (idtysPendingCertifsList[i][k].timestampWritable < min && !tmpExcluded[k])
+        {
+          min = idtysPendingCertifsList[i][k].timestampWritable;
+          idMin = k;
+        }
+      }
+
+      // Push min value on sort table
+      idtysPendingCertifsListSort[i].push({
+        from: idtysPendingCertifsList[i][idMin].from,
+        wotb_id: idtysPendingCertifsList[i][idMin].wotb_id,
+        issuerIsSentry: idtysPendingCertifsList[i][idMin].issuerIsSentry,
+        blockNumber: idtysPendingCertifsList[i][idMin].blockNumber,
+        creationTimestamp: idtysPendingCertifsList[i][idMin].creationTimestamp,
+        timestampExpire: idtysPendingCertifsList[i][idMin].timestampExpire,
+        timestampWritable: idtysPendingCertifsList[i][idMin].timestampWritable,
+        validBlockStamp: idtysPendingCertifsList[i][idMin].validBlockStamp
+      });
+
+      // Calculer la date de disponibilité du dossier d'inscription de l'identité correspondante
+      // := date de disponibilité maximale parmi les sigQty certifications aux dates de disponibilités les plus faibles
+      if (j<conf.sigQty)
+      {
+        let timestampWritable = idtysPendingCertifsList[i][idMin].timestampWritable;
+        identitiesList[i].registrationAvailability = (timestampWritable > identitiesList[i].registrationAvailability) ? timestampWritable : identitiesList[i].registrationAvailability;
+      }
+
+      // Exclure la valeur min avant de poursuivre le tri
+      tmpExcluded[idMin] = true;
+    }
+
+  }
+  return idtysPendingCertifsListSort;
+}
\ No newline at end of file
diff --git a/modules/willMembers/wotbIdCache.ts b/modules/willMembers/wotbIdCache.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2b53d15e80c62d2f3d70827eca12402bc500b8c6
--- /dev/null
+++ b/modules/willMembers/wotbIdCache.ts
@@ -0,0 +1,19 @@
+import {DataFinder} from "../../lib/DataFinder";
+
+export class WotbIdCache {
+
+  private wotbIdIndex: { [k: string]: number | undefined } = {}
+  private dataFinder: DataFinder
+
+
+  constructor(dataFinder: DataFinder) {
+    this.dataFinder = dataFinder;
+  }
+
+  async getWotbId(pubkey: string): Promise<number> {
+    if (this.wotbIdIndex[pubkey] === undefined) {
+      this.wotbIdIndex[pubkey] = await this.dataFinder.getWotbIdByIssuerPubkey(pubkey);
+    }
+    return this.wotbIdIndex[pubkey] as number
+  }
+}
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index e9bac2bbbd082210154d173662e46a50920eb6d5..8d055e8029d247c5bf3442fc36628abc91d7c4e6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -31,7 +31,7 @@
         "typescript": "^3.3.3"
       },
       "peerDependencies": {
-        "duniter": "1.7.x"
+        "duniter": "1.8.6"
       }
     },
     "node_modules/@types/mocha": {
diff --git a/package.json b/package.json
index 1e27b11118ddef1f7e1e1f657efaae4cb6c603b3..d12814d77df8706c1318a3906c3f88e06d336fe6 100755
--- a/package.json
+++ b/package.json
@@ -30,6 +30,6 @@
     "ts-node": "^3.3.0"
   },
   "peerDependencies": {
-    "duniter": "1.7.x"
+    "duniter": "1.8.6"
   }
 }
diff --git a/routes/members2.ts b/routes/members2.ts
index 2176f24ff034d24d45fb8eff2fbb8baddc6a9540..102a1a594e07345036322042c5c85783b5b50a92 100755
--- a/routes/members2.ts
+++ b/routes/members2.ts
@@ -353,7 +353,7 @@ module.exports = async (req: any, res: any, next: any) => {
 						let tmpQueryGetUidProtagonistPendingCert = await dataFinder.getUidOfPub(tmpPub)
 						
 						// Vérifier que l'émetteur de la certification correspond à une identié connue
-						if ( tmpQueryGetUidProtagonistPendingCert.length > 0 )
+						if ( tmpQueryGetUidProtagonistPendingCert )
 						{
 							// Vérifier la validité du blockStamp de la certification en piscine
 							let validBlockStamp = false;
@@ -364,7 +364,7 @@ module.exports = async (req: any, res: any, next: any) => {
 							let doubloonPendingCertif = false;
 							for (const pendingCert of membersPendingCertifsList[m])
 							{
-								if (pendingCert.protagonist == tmpQueryGetUidProtagonistPendingCert[0].uid && pendingCert.validBlockStamp == validBlockStamp)
+								if (pendingCert.protagonist == tmpQueryGetUidProtagonistPendingCert.uid && pendingCert.validBlockStamp == validBlockStamp)
 								{
 									doubloonPendingCertif = true;
 								}
@@ -378,8 +378,8 @@ module.exports = async (req: any, res: any, next: any) => {
 								if (tmpQueryPendingCertifsList[i].expires_on > currentBlockchainTimestamp)
 								{
 									membersPendingCertifsList[m].push({
-											protagonist: tmpQueryGetUidProtagonistPendingCert[0].uid,
-											protagonistIsSentry: sentriesIndex[tmpQueryGetUidProtagonistPendingCert[0].uid],
+											protagonist: tmpQueryGetUidProtagonistPendingCert.uid,
+											protagonistIsSentry: sentriesIndex[tmpQueryGetUidProtagonistPendingCert.uid],
 											blockNumber: tmpQueryPendingCertifsList[i].block_number,
 											timestampExpire: tmpQueryPendingCertifsList[i].expires_on,
 											timestampWritable: (typeof(tmpQueryLastIssuerCert[0]) == 'undefined') ? 0:tmpQueryLastIssuerCert[0].chainable_on,
diff --git a/routes/willMembers2.ts b/routes/willMembers2.ts
index 513cb6cde5ea5c1bef087a858c5cae47717e8e61..14ddb0761938e95c35636c96b96c52ae9a91047e 100755
--- a/routes/willMembers2.ts
+++ b/routes/willMembers2.ts
@@ -90,6 +90,7 @@ module.exports = async (req: any, res: any, next: any) => {
   }
   catch (e)
   {
+    console.error(e.stack);
     // En cas d'exception, afficher le message
     res.status(500).send(`<pre>${e.stack || e.message}</pre>`);
   }