diff --git a/.gitignore b/.gitignore
index dbb80f0d968a967cf2f524cc0a930cfc27527112..d8b4d96841d50077f479ed283bf65f6fbd18cc2b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -88,3 +88,25 @@ test/dal/loki.d.ts
 test/dal/loki.js*
 test/dal/blockchain-archive.d.ts
 test/dal/blockchain-archive.js*
+test/dal/basic-dal-tests.d.ts
+test/dal/basic-dal-tests.js*
+
+# In test folders
+test/integration/wot/*.d.ts
+test/integration/wot/*.js*
+test/integration/transactions/*.d.ts
+test/integration/transactions/*.js*
+test/integration/network/*.d.ts
+test/integration/network/*.js*
+test/integration/misc/*.d.ts
+test/integration/misc/*.js*
+test/integration/identity/*.d.ts
+test/integration/identity/*.js*
+test/integration/certification/*.d.ts
+test/integration/certification/*.js*
+test/integration/branches/*.d.ts
+test/integration/branches/*.js*
+test/integration/blocks/*.d.ts
+test/integration/blocks/*.js*
+test/fast/index/*.d.ts
+test/fast/index/*.js*
\ No newline at end of file
diff --git a/app/lib/blockchain/DuniterBlockchain.ts b/app/lib/blockchain/DuniterBlockchain.ts
index 843ab75e08ea49280f00b582804450955ea6bc92..ea76b84517aa7314909d3615b24dc4e0203de852 100644
--- a/app/lib/blockchain/DuniterBlockchain.ts
+++ b/app/lib/blockchain/DuniterBlockchain.ts
@@ -27,8 +27,7 @@ import {FileDAL} from "../dal/fileDAL"
 import {DataErrors} from "../common-libs/errors"
 import {NewLogger} from "../logger"
 import {DBTx} from "../db/DBTx"
-
-const _ = require('underscore')
+import {Underscore} from "../common-libs/underscore"
 
 export class DuniterBlockchain {
 
@@ -334,10 +333,10 @@ export class DuniterBlockchain {
   }
 
   static async updateWallets(sindex:SindexEntry[], aDal:any, reverse = false) {
-    const differentConditions = _.uniq(sindex.map((entry) => entry.conditions))
+    const differentConditions = Underscore.uniq(sindex.map((entry) => entry.conditions))
     for (const conditions of differentConditions) {
-      const creates = _.filter(sindex, (entry:SindexEntry) => entry.conditions === conditions && entry.op === CommonConstants.IDX_CREATE)
-      const updates = _.filter(sindex, (entry:SindexEntry) => entry.conditions === conditions && entry.op === CommonConstants.IDX_UPDATE)
+      const creates = Underscore.filter(sindex, (entry:SindexEntry) => entry.conditions === conditions && entry.op === CommonConstants.IDX_CREATE)
+      const updates = Underscore.filter(sindex, (entry:SindexEntry) => entry.conditions === conditions && entry.op === CommonConstants.IDX_UPDATE)
       const positives = creates.reduce((sum:number, src:SindexEntry) => sum + src.amount * Math.pow(10, src.base), 0)
       const negatives = updates.reduce((sum:number, src:SindexEntry) => sum + src.amount * Math.pow(10, src.base), 0)
       const wallet = await aDal.getWallet(conditions)
@@ -476,7 +475,7 @@ export class DuniterBlockchain {
   }
 
   static async computeToBeRevoked(mindex:MindexEntry[], dal:FileDAL) {
-    const revocations = _.filter(mindex, (entry:MindexEntry) => entry.revoked_on);
+    const revocations = Underscore.filter(mindex, (entry:MindexEntry) => !!(entry.revoked_on))
     for (const revoked of revocations) {
       await dal.setRevoked(revoked.pub)
     }
diff --git a/app/lib/common-libs/crypto/map.ts b/app/lib/common-libs/crypto/map.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a178fde884f70191fa00e56a5e4d2e91ba2f9eaa
--- /dev/null
+++ b/app/lib/common-libs/crypto/map.ts
@@ -0,0 +1,4 @@
+
+export interface Map<T> {
+  [k:string]: T
+}
diff --git a/app/lib/common-libs/underscore.ts b/app/lib/common-libs/underscore.ts
index 4bb08092d66a51db4d01a4733a97214086fdeae8..2592220474e242b23f4e9af5b59609f132c6e8eb 100644
--- a/app/lib/common-libs/underscore.ts
+++ b/app/lib/common-libs/underscore.ts
@@ -1,28 +1,87 @@
-const _ = require("underscore")
+import {Map} from "./crypto/map"
+
+const _underscore_ = require("underscore")
+
+export interface UnderscoreClass<T> {
+  filter(filterFunc: (t: T) => boolean): UnderscoreClass<T>
+  where(props: { [k in keyof T]?: T[k] }): UnderscoreClass<T>
+  sortBy(sortFunc:(element:T) => number): UnderscoreClass<T>
+  pluck<K extends keyof T>(k:K): UnderscoreClass<T>
+  uniq<K extends keyof T>(isSorted?:boolean, iteratee?:(t:T) => K): UnderscoreClass<T>
+  value(): T[]
+}
 
 export const Underscore = {
 
   filter: <T>(elements:T[], filterFunc: (t:T) => boolean): T[] => {
-    return _.filter(elements, filterFunc)
+    return _underscore_.filter(elements, filterFunc)
   },
 
   where: <T>(elements:T[], props: { [k in keyof T]?: T[k] }): T[] => {
-    return _.where(elements, props)
+    return _underscore_.where(elements, props)
+  },
+
+  findWhere: <T>(elements:T[], props: { [k in keyof T]?: T[k] }): T|null => {
+    return _underscore_.findWhere(elements, props)
   },
 
   keys: <T>(map:T): (keyof T)[] => {
-    return _.keys(map)
+    return _underscore_.keys(map)
   },
 
   values: <T>(map:{ [k:string]: T }): T[] => {
-    return _.values(map)
+    return _underscore_.values(map)
   },
 
   pluck: <T, K extends keyof T>(elements:T[], k:K): T[K][] => {
-    return _.pluck(elements, k)
+    return _underscore_.pluck(elements, k)
+  },
+
+  pick: <T, K extends keyof T>(elements:T, ...k:K[]): T[K][] => {
+    return _underscore_.pick(elements, ...k)
+  },
+
+  omit: <T, K extends keyof T>(element:T, ...k:K[]): T[K][] => {
+    return _underscore_.omit(element, ...k)
+  },
+
+  uniq: <T, K>(elements:T[], isSorted:boolean = false, iteratee?:(t:T) => K): T[] => {
+    return _underscore_.uniq(elements, isSorted, iteratee)
+  },
+
+  clone: <T>(t:T): T => {
+    return _underscore_.clone(t)
+  },
+
+  mapObject: <T, K extends keyof T, L extends keyof (T[K])>(t:T, cb:(k:K) => (T[K])[L]): Map<T[K][L]> => {
+    return _underscore_.mapObject(t, cb)
+  },
+
+  mapObjectByProp: <T, K extends keyof T, L extends keyof (T[K])>(t:T, prop:L): Map<T[K][L]> => {
+    return _underscore_.mapObject(t, (o:T[K]) => o[prop])
+  },
+
+  sortBy: <T, K extends keyof T>(elements:T[], sortFunc:((element:T) => number|string)|K): T[] => {
+    return _underscore_.sortBy(elements, sortFunc)
+  },
+
+  difference: <T>(array1:T[], array2:T[]): T[] => {
+    return _underscore_.difference(array1, array2)
   },
 
-  uniq: <T>(elements:T[]): T[] => {
-    return _.uniq(elements)
-  }
+  shuffle: <T>(elements:T[]): T[] => {
+    return _underscore_.shuffle(elements)
+  },
+
+  extend: <T, U>(t1:T, t2:U): T|U => {
+    return _underscore_.extend(t1, t2)
+  },
+
+  range: (count:number, end?:number): number[] => {
+    return _underscore_.range(count, end)
+  },
+
+  chain: <T>(element:T[]): UnderscoreClass<T> => {
+    return _underscore_.chain(element)
+  },
 }
diff --git a/app/lib/computation/BlockchainContext.ts b/app/lib/computation/BlockchainContext.ts
index b33f4a7ace0b891835300802f7a6d81fbf8b3735..cc5bb67ad73bc6d346c4d9e4a2f0064ac275c731 100644
--- a/app/lib/computation/BlockchainContext.ts
+++ b/app/lib/computation/BlockchainContext.ts
@@ -11,15 +11,14 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
 import {BlockDTO} from "../dto/BlockDTO"
 import {DuniterBlockchain} from "../blockchain/DuniterBlockchain"
 import {QuickSynchronizer} from "./QuickSync"
 import {DBHead} from "../db/DBHead"
 import {FileDAL} from "../dal/fileDAL"
 import {DBBlock} from "../db/DBBlock"
+import {Underscore} from "../common-libs/underscore"
 
-const _               = require('underscore');
 const indexer         = require('../indexer').Indexer
 const constants       = require('../constants');
 
@@ -28,7 +27,6 @@ export class BlockchainContext {
   private conf:any
   private dal:FileDAL
   private logger:any
-  private blockchain:DuniterBlockchain
   private quickSynchronizer:QuickSynchronizer
 
   /**
@@ -84,7 +82,7 @@ export class BlockchainContext {
     for (const k of keys) {
       copy[k] = this.vHEAD[k];
     }
-    _.extend(copy, props);
+    Underscore.extend(copy, props);
     return copy;
   }
 
diff --git a/app/lib/computation/QuickSync.ts b/app/lib/computation/QuickSync.ts
index b825912f7b4113adbb6c0dfa427e31d7371cacd6..049b057f993a842bf1f4c6f6d3151bc532d6a1d0 100644
--- a/app/lib/computation/QuickSync.ts
+++ b/app/lib/computation/QuickSync.ts
@@ -19,8 +19,8 @@ import {CurrencyConfDTO} from "../dto/ConfDTO";
 import {FileDAL} from "../dal/fileDAL"
 import {DBBlock} from "../db/DBBlock"
 import {DBTx} from "../db/DBTx"
+import {Underscore} from "../common-libs/underscore"
 
-const _ = require('underscore')
 const constants = require('../constants')
 
 let sync_bindex: any [] = [];
@@ -171,7 +171,7 @@ export class QuickSynchronizer {
           const nextExpiringChanged = currentNextExpiring !== sync_nextExpiring
 
           // Fills in correctly the SINDEX
-          await Promise.all(_.where(sync_sindex.concat(local_sindex), { op: 'UPDATE' }).map(async (entry: any) => {
+          await Promise.all(Underscore.where(sync_sindex.concat(local_sindex), { op: 'UPDATE' }).map(async (entry: any) => {
             if (!entry.conditions) {
               const src = (await this.dal.sindexDAL.getSource(entry.identifier, entry.pos)) as FullSindexEntry
               entry.conditions = src.conditions;
@@ -246,8 +246,8 @@ export class QuickSynchronizer {
         await this.dal.cindexDAL.insertBatch(sync_cindex);
 
         // Save the intermediary table of wallets
-        const conditions = _.keys(sync_memoryWallets)
-        const nonEmptyKeys = _.filter(conditions, (k: any) => sync_memoryWallets[k] && sync_memoryWallets[k].balance > 0)
+        const conditions = Underscore.keys(sync_memoryWallets)
+        const nonEmptyKeys = Underscore.filter(conditions, (k: any) => sync_memoryWallets[k] && sync_memoryWallets[k].balance > 0)
         const walletsToRecord = nonEmptyKeys.map((k: any) => sync_memoryWallets[k])
         await this.dal.walletDAL.insertBatch(walletsToRecord)
         for (const cond of conditions) {
diff --git a/app/lib/dal/fileDAL.ts b/app/lib/dal/fileDAL.ts
index b15ce341911162e65b385314e8b222a01307f308..99756afbe9c4544024e3eba5f020f3edf503269e 100644
--- a/app/lib/dal/fileDAL.ts
+++ b/app/lib/dal/fileDAL.ts
@@ -30,7 +30,6 @@ import {
   IndexEntry,
   SindexEntry
 } from "../indexer"
-import {DBPeer} from "./sqliteDAL/PeerDAL"
 import {TransactionDTO} from "../dto/TransactionDTO"
 import {CertDAL, DBCert} from "./sqliteDAL/CertDAL"
 import {DBBlock} from "../db/DBBlock"
@@ -72,9 +71,10 @@ import {Tristamp} from "../common/Tristamp"
 import {CFSBlockchainArchive} from "./indexDAL/CFSBlockchainArchive"
 import {CFSCore} from "./fileDALs/CFSCore"
 import {BlockchainArchiveDAO} from "./indexDAL/abstract/BlockchainArchiveDAO"
+import {Underscore} from "../common-libs/underscore"
+import {DBPeer} from "../db/DBPeer"
 
 const readline = require('readline')
-const _       = require('underscore');
 const indexer = require('../indexer').Indexer
 const logger = require('../logger').NewLogger('filedal');
 const constants = require('../constants');
@@ -187,7 +187,7 @@ export class FileDAL {
     for (const indexDAL of dals) {
       indexDAL.triggerInit()
     }
-    const dalNames = _.keys(this.newDals);
+    const dalNames = Underscore.keys(this.newDals);
     for (const dalName of dalNames) {
       const dal = this.newDals[dalName];
       await dal.init();
@@ -321,10 +321,10 @@ export class FileDAL {
     // Cert period rule
     const medianTime = vHEAD_1 ? vHEAD_1.medianTime : 0;
     const linksFrom:FullCindexEntry[] = await this.cindexDAL.reducablesFrom(from)
-    const unchainables = _.filter(linksFrom, (link:CindexEntry) => link.chainable_on > medianTime);
+    const unchainables = Underscore.filter(linksFrom, (link:CindexEntry) => link.chainable_on > medianTime);
     if (unchainables.length > 0) return true;
     // Max stock rule
-    let activeLinks = _.filter(linksFrom, (link:CindexEntry) => !link.expired_on);
+    let activeLinks = Underscore.filter(linksFrom, (link:CindexEntry) => !link.expired_on);
     return activeLinks.length >= sigStock;
   }
 
@@ -620,7 +620,7 @@ export class FileDAL {
 
   async findPeersWhoseHashIsIn(hashes:string[]) {
     const peers = await this.peerDAL.listAll();
-    return _.chain(peers).filter((p:DBPeer) => hashes.indexOf(p.hash) !== -1).value();
+    return Underscore.chain(peers).filter((p:DBPeer) => hashes.indexOf(p.hash) !== -1).value()
   }
 
   getTxByHash(hash:string) {
@@ -637,7 +637,7 @@ export class FileDAL {
 
   async getNonWritten(pubkey:string) {
     const pending = await this.idtyDAL.getPendingIdentities();
-    return _.chain(pending).where({pubkey: pubkey}).value();
+    return Underscore.chain(pending).where({pubkey: pubkey}).value()
   }
 
   async getRevocatingMembers() {
@@ -660,18 +660,18 @@ export class FileDAL {
     return this.mindexDAL.getRevokedPubkeys()
   }
 
-  async searchJustIdentities(search:string) {
+  async searchJustIdentities(search:string): Promise<DBIdentity[]> {
     const pendings = await this.idtyDAL.searchThoseMatching(search);
     const writtens = await this.iindexDAL.searchThoseMatching(search);
-    const nonPendings = _.filter(writtens, (w:IindexEntry) => {
-      return _.where(pendings, { pubkey: w.pub }).length == 0;
+    const nonPendings = Underscore.filter(writtens, (w:IindexEntry) => {
+      return Underscore.where(pendings, { pubkey: w.pub }).length == 0;
     });
     const found = pendings.concat(nonPendings.map((i:any) => {
       // Use the correct field
       i.pubkey = i.pub
       return i
     }));
-    return await Promise.all(found.map(async (f:any) => {
+    return await Promise.all<DBIdentity>(found.map(async (f:any) => {
       const ms = await this.mindexDAL.getReducedMS(f.pub);
       if (ms) {
         f.revoked_on = ms.revoked_on ? ms.revoked_on : null;
@@ -689,7 +689,7 @@ export class FileDAL {
     await Promise.all(links.map(async (entry:any) => {
       matching.push(await this.cindexEntry2DBCert(entry))
     }))
-    matching  = _.sortBy(matching, (c:DBCert) => -c.block);
+    matching  = Underscore.sortBy(matching, (c:DBCert) => -c.block);
     matching.reverse();
     return matching;
   }
@@ -701,7 +701,7 @@ export class FileDAL {
     await Promise.all(links.map(async (entry:CindexEntry) => {
       matching.push(await this.cindexEntry2DBCert(entry))
     }))
-    matching  = _.sortBy(matching, (c:DBCert) => -c.block);
+    matching  = Underscore.sortBy(matching, (c:DBCert) => -c.block);
     matching.reverse();
     return matching;
   }
@@ -741,12 +741,12 @@ export class FileDAL {
 
   async certsFindNew() {
     const certs = await this.certDAL.getNotLinked();
-    return _.chain(certs).where({linked: false}).sortBy((c:DBCert) => -c.block).value();
+    return Underscore.chain(certs).where({linked: false}).sortBy((c:DBCert) => -c.block).value()
   }
 
   async certsNotLinkedToTarget(hash:string) {
     const certs = await this.certDAL.getNotLinkedToTarget(hash);
-    return _.chain(certs).sortBy((c:any) => -c.block).value();
+    return Underscore.chain(certs).sortBy((c:any) => -c.block).value();
   }
 
   async getMostRecentMembershipNumberForIssuer(issuer:string) {
@@ -761,7 +761,7 @@ export class FileDAL {
 
   async lastJoinOfIdentity(target:string) {
     let pending = await this.msDAL.getPendingINOfTarget(target);
-    return _(pending).sortBy((ms:any) => -ms.number)[0];
+    return Underscore.sortBy(pending, (ms:any) => -ms.number)[0];
   }
 
   async findNewcomers(blockMedianTime = 0): Promise<DBMembership[]> {
@@ -773,24 +773,22 @@ export class FileDAL {
       }
       return null
     }))
-    return _.chain(mss)
-      .filter((ms:DBMembership) => ms)
+    return Underscore.chain(Underscore.filter(mss, ms => !!ms) as DBMembership[])
       .sortBy((ms:DBMembership) => -ms.blockNumber)
       .value()
   }
 
   async findLeavers(blockMedianTime = 0): Promise<DBMembership[]> {
     const pending = await this.msDAL.getPendingOUT();
-    const mss = await Promise.all(pending.map(async (p:any) => {
+    const mss = await Promise.all<DBMembership|null>(pending.map(async p => {
       const reduced = await this.mindexDAL.getReducedMS(p.issuer)
       if (!reduced || !reduced.chainable_on || blockMedianTime >= reduced.chainable_on || blockMedianTime < constants.TIME_TO_TURN_ON_BRG_107) {
         return p
       }
       return null
     }))
-    return _.chain(mss)
-      .filter((ms:DBMembership) => ms)
-      .sortBy((ms:DBMembership) => -ms.blockNumber)
+    return Underscore.chain(Underscore.filter(mss, ms => !!ms) as DBMembership[])
+      .sortBy(ms => -ms.blockNumber)
       .value();
   }
 
@@ -884,14 +882,14 @@ export class FileDAL {
 
   async listAllPeersWithStatusNewUP() {
     const peers = await this.peerDAL.listAll();
-    return _.chain(peers)
+    return Underscore.chain(peers)
         .filter((p:DBPeer) => ['UP']
             .indexOf(p.status) !== -1).value();
   }
 
   async listAllPeersWithStatusNewUPWithtout(pub:string) {
     const peers = await this.peerDAL.listAll();
-    return _.chain(peers).filter((p:DBPeer) => p.status == 'UP').filter((p:DBPeer) => p.pubkey !== pub).value();
+    return Underscore.chain(peers).filter((p:DBPeer) => p.status == 'UP').filter((p:DBPeer) => p.pubkey !== pub).value();
   }
 
   async findPeers(pubkey:string): Promise<DBPeer[]> {
@@ -903,9 +901,9 @@ export class FileDAL {
     }
   }
 
-  async getRandomlyUPsWithout(pubkeys:string[]) {
+  async getRandomlyUPsWithout(pubkeys:string[]): Promise<DBPeer[]> {
     const peers = await this.listAllPeersWithStatusNewUP();
-    return peers.filter((peer:DBPeer) => pubkeys.indexOf(peer.pubkey) == -1);
+    return peers.filter(peer => pubkeys.indexOf(peer.pubkey) == -1)
   }
 
   async setPeerUP(pubkey:string) {
@@ -1098,7 +1096,7 @@ export class FileDAL {
   async getUDHistory(pubkey:string) {
     const sources = await this.sindexDAL.getUDSources(pubkey)
     return {
-      history: sources.map((src:SindexEntry) => _.extend({
+      history: sources.map((src:SindexEntry) => Underscore.extend({
         block_number: src.pos,
         time: src.written_time
       }, src))
@@ -1114,7 +1112,7 @@ export class FileDAL {
     const firstBlock = Math.max(0, start);
     const lastBlock = Math.max(0, Math.min(current.number, end));
     const blocks = await this.blockDAL.getBlocks(firstBlock, lastBlock);
-    return _.chain(blocks).pluck('issuer').uniq().value();
+    return Underscore.uniq(blocks.map(b => b.issuer))
   }
 
   /**
@@ -1152,11 +1150,11 @@ export class FileDAL {
   async loadConf(overrideConf:ConfDTO, defaultConf = false) {
     let conf = ConfDTO.complete(overrideConf || {});
     if (!defaultConf) {
-      const savedConf = await this.confDAL.loadConf();
-      const savedProxyConf = _(savedConf.proxyConf).extend({});
-      conf = _(savedConf).extend(overrideConf || {});
+      const savedConf = await this.confDAL.loadConf()
+      const savedProxyConf = Underscore.extend(savedConf.proxyConf, {})
+      conf = Underscore.extend(savedConf, overrideConf || {})
       if (overrideConf.proxiesConf !== undefined) {} else {
-        conf.proxyConf = _(savedProxyConf).extend({});
+        conf.proxyConf = Underscore.extend(savedProxyConf, {})
       }
     }
     if (this.loadConfHook) {
@@ -1206,11 +1204,11 @@ export class FileDAL {
   }
 
   async cleanCaches() {
-    await _.values(this.newDals).map((dal:Initiable) => dal.cleanCache && dal.cleanCache())
+    await Underscore.values(this.newDals).map((dal:Initiable) => dal.cleanCache && dal.cleanCache())
   }
 
   async close() {
-    await _.values(this.newDals).map((dal:Initiable) => dal.cleanCache && dal.cleanCache())
+    await Underscore.values(this.newDals).map((dal:Initiable) => dal.cleanCache && dal.cleanCache())
     return this.sqliteDriver.closeConnection();
   }
 
diff --git a/app/lib/dal/fileDALs/CFSCore.ts b/app/lib/dal/fileDALs/CFSCore.ts
index 28971e6c545fc7e8fc39f9513c8fe53ec2f69a41..019155abe5149360d5199937a4de0f9a48732919 100644
--- a/app/lib/dal/fileDALs/CFSCore.ts
+++ b/app/lib/dal/fileDALs/CFSCore.ts
@@ -14,8 +14,8 @@
 "use strict";
 
 import {FileSystem} from "../../system/directory"
+import {Underscore} from "../../common-libs/underscore"
 
-const _ = require('underscore');
 const path = require('path');
 
 const DEEP_WRITE = true;
@@ -92,9 +92,9 @@ export class CFSCore {
       const deletedOfThisPath = deletedFiles.filter((f:string) => f.match(new RegExp('^' + this.toRemoveDirName(dirPath))));
       const locallyDeletedFiles = deletedOfThisPath.map((f:string) => f.replace(this.toRemoveDirName(dirPath), '')
         .replace(/^__/, ''));
-      files = _.difference(files, locallyDeletedFiles);
+      files = Underscore.difference(files, locallyDeletedFiles)
     }
-    return _.uniq(files);
+    return Underscore.uniq(files)
   };
 
   /**
diff --git a/app/lib/dal/fileDALs/ConfDAL.ts b/app/lib/dal/fileDALs/ConfDAL.ts
index 5ecef21a9a5cf29ab976ec4cbe9b86064ebccf3d..f42197b7ef4a9200bf0909f268cee68df822a465 100644
--- a/app/lib/dal/fileDALs/ConfDAL.ts
+++ b/app/lib/dal/fileDALs/ConfDAL.ts
@@ -15,8 +15,7 @@ import {AbstractCFS} from "./AbstractCFS"
 import {ConfDTO} from "../../dto/ConfDTO"
 import {CommonConstants} from "../../common-libs/constants";
 import {FileSystem} from "../../system/directory"
-
-const _ = require('underscore');
+import {Underscore} from "../../common-libs/underscore"
 
 export class ConfDAL extends AbstractCFS {
 
@@ -62,7 +61,7 @@ export class ConfDAL extends AbstractCFS {
   async loadConf() {
     const data = await this.coreFS.readJSON('conf.json');
     if (data) {
-      return _(ConfDTO.defaultConf()).extend(data);
+      return Underscore.extend(ConfDTO.defaultConf(), data)
     } else {
       // Silent error
       this.logger.warn('No configuration loaded');
diff --git a/app/lib/dal/fileDALs/StatDAL.ts b/app/lib/dal/fileDALs/StatDAL.ts
index 6e3501469203c64de026655bae958163439f813a..96f03e5444b18cc43e31047097606a056e105b79 100644
--- a/app/lib/dal/fileDALs/StatDAL.ts
+++ b/app/lib/dal/fileDALs/StatDAL.ts
@@ -13,8 +13,7 @@
 
 import {AbstractCFS} from "./AbstractCFS";
 import {FileSystem} from "../../system/directory"
-
-const _ = require('underscore');
+import {Underscore} from "../../common-libs/underscore"
 
 export class StatDAL extends AbstractCFS {
 
@@ -40,7 +39,7 @@ export class StatDAL extends AbstractCFS {
 
   async pushStats(statsToPush:any) {
     const stats = (await this.loadStats()) || {};
-    _.keys(statsToPush).forEach(function(statName:string){
+    Underscore.keys(statsToPush).forEach(function(statName:string){
       if (!stats[statName]) {
         stats[statName] = { blocks: [] };
       }
diff --git a/app/lib/dal/indexDAL/abstract/PeerDAO.ts b/app/lib/dal/indexDAL/abstract/PeerDAO.ts
index 9e3423b43b5bf43a925626193b99904223e5b99c..6cedd6230aa5a530e51501f9571720a2a0f1a80c 100644
--- a/app/lib/dal/indexDAL/abstract/PeerDAO.ts
+++ b/app/lib/dal/indexDAL/abstract/PeerDAO.ts
@@ -1,5 +1,5 @@
 import {Initiable} from "../../sqliteDAL/Initiable"
-import {DBPeer} from "../../sqliteDAL/PeerDAL"
+import {DBPeer} from "../../../db/DBPeer"
 
 export interface PeerDAO extends Initiable {
 
diff --git a/app/lib/dal/indexDAL/loki/LokiPeer.ts b/app/lib/dal/indexDAL/loki/LokiPeer.ts
index 2614d0ac737ba5295893ec92fbe1b0d86525981b..7aef11957088093557789c6e59e6e0cc1778a6bd 100644
--- a/app/lib/dal/indexDAL/loki/LokiPeer.ts
+++ b/app/lib/dal/indexDAL/loki/LokiPeer.ts
@@ -1,6 +1,6 @@
 import {LokiCollectionManager} from "./LokiCollectionManager"
 import {PeerDAO} from "../abstract/PeerDAO"
-import {DBPeer} from "../../sqliteDAL/PeerDAL"
+import {DBPeer} from "../../../db/DBPeer"
 
 export class LokiPeer extends LokiCollectionManager<DBPeer> implements PeerDAO {
 
diff --git a/app/lib/dal/indexDAL/loki/LokiSIndex.ts b/app/lib/dal/indexDAL/loki/LokiSIndex.ts
index d7d6bb288cc8432baf0433d3aadfa1927a287947..575d529a418fd59fcc1579c3bacc30f6d204fe02 100644
--- a/app/lib/dal/indexDAL/loki/LokiSIndex.ts
+++ b/app/lib/dal/indexDAL/loki/LokiSIndex.ts
@@ -1,8 +1,7 @@
 import {LokiIndex} from "./LokiIndex"
 import {FullSindexEntry, Indexer, SindexEntry} from "../../../indexer"
 import {SIndexDAO} from "../abstract/SIndexDAO"
-
-const _ = require('underscore')
+import {Underscore} from "../../../common-libs/underscore"
 
 export class LokiSIndex extends LokiIndex<SindexEntry> implements SIndexDAO {
 
@@ -33,7 +32,7 @@ export class LokiSIndex extends LokiIndex<SindexEntry> implements SIndexDAO {
         src.type = src.tx ? 'T' : 'D'
         return src
       })
-    return _.sortBy(sources, (row:SindexEntry) => row.type == 'D' ? 0 : 1);
+    return Underscore.sortBy(sources, (row:SindexEntry) => row.type == 'D' ? 0 : 1)
   }
 
   async getAvailableForPubkey(pubkey: string): Promise<{ amount: number; base: number }[]> {
diff --git a/app/lib/dal/indexDAL/loki/LokiTransactions.ts b/app/lib/dal/indexDAL/loki/LokiTransactions.ts
index ea8a09ecf5adaa557434eed79304a1a3b5b72a6a..97265aaecf2d34ba568d150794a1c044bd7b1305 100644
--- a/app/lib/dal/indexDAL/loki/LokiTransactions.ts
+++ b/app/lib/dal/indexDAL/loki/LokiTransactions.ts
@@ -3,8 +3,8 @@ import {TxsDAO} from "../abstract/TxsDAO"
 import {SandBox} from "../../sqliteDAL/SandBox"
 import {TransactionDTO} from "../../../dto/TransactionDTO"
 import {DBTx} from "../../../db/DBTx"
+import {Underscore} from "../../../common-libs/underscore"
 
-const _ = require('underscore')
 const moment = require('moment')
 const constants = require('../../../constants')
 
@@ -106,7 +106,7 @@ export class LokiTransactions extends LokiIndex<DBTx> implements TxsDAO {
       written: true
     })
     // Which does not contains the key as issuer
-    return _.filter(rows, (row: DBTx) => row.issuers.indexOf(pubkey) === -1);
+    return Underscore.filter(rows, (row: DBTx) => row.issuers.indexOf(pubkey) === -1);
   }
 
   async getPendingWithIssuer(pubkey: string): Promise<DBTx[]> {
diff --git a/app/lib/dal/sqliteDAL/AbstractSQLite.ts b/app/lib/dal/sqliteDAL/AbstractSQLite.ts
index 4a240425613410f3d2a77829f14f931d79be9f34..7e3c42b70b1724c60e0ff3a6aa7f92031ddf5a8f 100644
--- a/app/lib/dal/sqliteDAL/AbstractSQLite.ts
+++ b/app/lib/dal/sqliteDAL/AbstractSQLite.ts
@@ -14,12 +14,12 @@
 import {SQLiteDriver} from "../drivers/SQLiteDriver"
 import {Initiable} from "./Initiable"
 import {getDurationInMicroSeconds, getMicrosecondsTime} from "../../../ProcessCpuProfiler"
+import {Underscore} from "../../common-libs/underscore"
 
 /**
  * Created by cgeek on 22/08/15.
  */
 
-const _ = require('underscore');
 const colors = require('colors');
 const logger = require('../../logger').NewLogger('sqlite');
 
@@ -84,7 +84,7 @@ export abstract class AbstractSQLite<T> extends Initiable {
   sqlFind(obj:any, sortObj:any = {}): Promise<T[]> {
     const conditions = this.toConditionsArray(obj).join(' and ');
     const values = this.toParams(obj);
-    const sortKeys: string[] = _.keys(sortObj);
+    const sortKeys: string[] = Underscore.keys(sortObj)
     const sort = sortKeys.length ? ' ORDER BY ' + sortKeys.map((k) => "`" + k + "` " + (sortObj[k] ? 'DESC' : 'ASC')).join(',') : '';
     return this.query('SELECT * FROM ' + this.table + ' WHERE ' + conditions + sort, values);
   }
@@ -95,12 +95,12 @@ export abstract class AbstractSQLite<T> extends Initiable {
   }
 
   sqlFindLikeAny(obj:any): Promise<T[]> {
-    const keys:string[] = _.keys(obj);
+    const keys:string[] = Underscore.keys(obj)
     return this.query('SELECT * FROM ' + this.table + ' WHERE ' + keys.map((k) => 'UPPER(`' + k + '`) like ?').join(' or '), keys.map((k) => obj[k].toUpperCase()))
   }
 
   async sqlRemoveWhere(obj:any): Promise<void> {
-    const keys:string[] = _.keys(obj);
+    const keys:string[] = Underscore.keys(obj)
     await this.query('DELETE FROM ' + this.table + ' WHERE ' + keys.map((k) => '`' + k + '` = ?').join(' and '), keys.map((k) => obj[k]))
   }
 
@@ -209,7 +209,7 @@ export abstract class AbstractSQLite<T> extends Initiable {
   }
 
   private toConditionsArray(obj:any): string[] {
-    return _.keys(obj).map((k:string) => {
+    return Underscore.keys(obj).map((k:string) => {
       if (obj[k].$lte !== undefined) {
         return '`' + k + '` <= ?';
       } else if (obj[k].$gte !== undefined) {
@@ -230,7 +230,7 @@ export abstract class AbstractSQLite<T> extends Initiable {
 
   private toParams(obj:any, fields:string[] | null = null): any[] {
     let params:any[] = [];
-    (fields || _.keys(obj)).forEach((f:string) => {
+    (fields || Underscore.keys(obj)).forEach((f:string) => {
       if (obj[f].$null === undefined) {
         let pValue;
         if      (obj[f].$lte  !== undefined)      { pValue = obj[f].$lte;  }
diff --git a/app/lib/dal/sqliteDAL/MembershipDAL.ts b/app/lib/dal/sqliteDAL/MembershipDAL.ts
index 65cb2af3529d60d36ee314d40e0cdb444c4539a6..ddadff48d9138f1bc567666eb79405fa918584b2 100644
--- a/app/lib/dal/sqliteDAL/MembershipDAL.ts
+++ b/app/lib/dal/sqliteDAL/MembershipDAL.ts
@@ -15,8 +15,8 @@ import {SQLiteDriver} from "../drivers/SQLiteDriver";
 import {AbstractSQLite} from "./AbstractSQLite";
 import {SandBox} from './SandBox';
 import {DBDocument} from './DocumentDAL';
+import {Underscore} from "../../common-libs/underscore"
 
-const _ = require('underscore');
 const constants = require('../../constants');
 
 export interface DBMembership extends DBDocument {
@@ -128,7 +128,7 @@ export class MembershipDAL extends AbstractSQLite<DBMembership> {
   savePendingMembership(ms:DBMembership) {
     ms.membership = ms.membership.toUpperCase();
     ms.written = false;
-    return this.saveEntity(_.pick(ms, 'membership', 'issuer', 'number', 'blockNumber', 'blockHash', 'userid', 'certts', 'block', 'fpr', 'idtyHash', 'expires_on', 'written', 'written_number', 'signature'))
+    return this.saveEntity(Underscore.pick(ms, 'membership', 'issuer', 'number', 'blockNumber', 'blockHash', 'userid', 'certts', 'block', 'fpr', 'idtyHash', 'expires_on', 'written', 'written_number', 'signature'))
   }
 
   async deleteMS(ms:DBMembership) {
diff --git a/app/lib/dal/sqliteDAL/MetaDAL.ts b/app/lib/dal/sqliteDAL/MetaDAL.ts
index 023259da4cd28cfb28da618488320e8f8d05b279..53b7b49086d1d7f1a21ff53d8448f7985ca1be03 100644
--- a/app/lib/dal/sqliteDAL/MetaDAL.ts
+++ b/app/lib/dal/sqliteDAL/MetaDAL.ts
@@ -17,7 +17,6 @@ import {ConfDTO} from "../../dto/ConfDTO"
 import {TransactionDTO} from "../../dto/TransactionDTO"
 import {IdentityDAL} from "./IdentityDAL"
 
-const _ = require('underscore')
 const logger = require('../../logger').NewLogger('metaDAL');
 
 export interface DBMeta {
diff --git a/app/lib/dal/sqliteDAL/PeerDAL.ts b/app/lib/dal/sqliteDAL/PeerDAL.ts
deleted file mode 100644
index e5662fa8a7ddf683b6000c944052df7c155490d5..0000000000000000000000000000000000000000
--- a/app/lib/dal/sqliteDAL/PeerDAL.ts
+++ /dev/null
@@ -1,124 +0,0 @@
-// Source file from duniter: Crypto-currency software to manage libre currency such as Äž1
-// Copyright (C) 2018  Cedric Moreau <cem.moreau@gmail.com>
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU Affero General Public License for more details.
-
-import {SQLiteDriver} from "../drivers/SQLiteDriver"
-import {AbstractSQLite} from "./AbstractSQLite"
-
-export class DBPeer {
-
-  version: number
-  currency: string
-  status: string
-  statusTS: number
-  hash: string
-  first_down: number | null
-  last_try: number | null
-  pubkey: string
-  block: string
-  signature: string 
-  endpoints: string[]
-  raw: string
-
-  json() {
-    return {
-      version: this.version,
-      currency: this.currency,
-      endpoints: this.endpoints,
-      status: this.status,
-      block: this.block,
-      signature: this.signature,
-      raw: this.raw,
-      pubkey: this.pubkey
-    }
-  }
-}
-
-export class PeerDAL extends AbstractSQLite<DBPeer> {
-
-  constructor(driver:SQLiteDriver) {
-    super(
-      driver,
-      'peer',
-      // PK fields
-      ['pubkey'],
-      // Fields
-      [
-        'version',
-        'currency',
-        'status',
-        'statusTS',
-        'hash',
-        'first_down',
-        'last_try',
-        'pubkey',
-        'block',
-        'signature',
-        'endpoints',
-        'raw'
-      ],
-      // Arrays
-      ['endpoints'],
-      // Booleans
-      [],
-      // BigIntegers
-      [],
-      // Transient
-      []
-    )
-  }
-
-  async init() {
-    await this.exec('BEGIN;' +
-      'CREATE TABLE IF NOT EXISTS ' + this.table + ' (' +
-      'version INTEGER NOT NULL,' +
-      'currency VARCHAR(50) NOT NULL,' +
-      'status VARCHAR(10),' +
-      'statusTS INTEGER NOT NULL,' +
-      'hash CHAR(64),' +
-      'first_down INTEGER,' +
-      'last_try INTEGER,' +
-      'pubkey VARCHAR(50) NOT NULL,' +
-      'block VARCHAR(60) NOT NULL,' +
-      'signature VARCHAR(100),' +
-      'endpoints TEXT NOT NULL,' +
-      'raw TEXT,' +
-      'PRIMARY KEY (pubkey)' +
-      ');' +
-      'CREATE INDEX IF NOT EXISTS idx_link_source ON peer (pubkey);' +
-      'COMMIT;')
-  }
-
-  listAll() {
-    return this.sqlListAll()
-  }
-
-  getPeer(pubkey:string) {
-    return this.sqlFindOne({ pubkey: pubkey })
-  }
-
-  getPeersWithEndpointsLike(str:string) {
-    return this.query('SELECT * FROM peer WHERE endpoints LIKE ?', ['%' + str + '%'])
-  }
-
-  savePeer(peer:DBPeer) {
-    return this.saveEntity(peer)
-  }
-
-  removePeerByPubkey(pubkey:string) {
-    return this.exec('DELETE FROM peer WHERE pubkey LIKE \'' + pubkey + '\'')
-  }
-
-  async removeAll() {
-    await this.sqlDeleteAll()
-  }
-}
diff --git a/app/lib/db/DBPeer.ts b/app/lib/db/DBPeer.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c71fb86e76500e80ecad0184c121606bd762e09e
--- /dev/null
+++ b/app/lib/db/DBPeer.ts
@@ -0,0 +1,47 @@
+import {PeerDTO} from "../dto/PeerDTO"
+
+export class DBPeer {
+
+  version: number
+  currency: string
+  status: string
+  statusTS: number
+  hash: string
+  first_down: number | null
+  last_try: number | null
+  pubkey: string
+  block: string
+  signature: string
+  endpoints: string[]
+  raw: string
+
+  static json(peer:DBPeer): JSONDBPeer {
+    return {
+      version: peer.version,
+      currency: peer.currency,
+      status: peer.status,
+      first_down: peer.first_down,
+      last_try: peer.last_try,
+      pubkey: peer.pubkey,
+      block: peer.block,
+      signature: peer.signature,
+      endpoints: peer.endpoints
+    }
+  }
+
+  static fromPeerDTO(peer:PeerDTO): DBPeer {
+    return peer.toDBPeer()
+  }
+}
+
+export class JSONDBPeer {
+  version: number
+  currency: string
+  status: string
+  first_down: number | null
+  last_try: number | null
+  pubkey: string
+  block: string
+  signature: string
+  endpoints: string[]
+}
diff --git a/app/lib/dto/ConfDTO.ts b/app/lib/dto/ConfDTO.ts
index eb9ccef3391badfa479b1ed7dc1fdb013be73f3f..0cfd61f6af14a59f6d1d22ed9b9e0638bedf69be 100644
--- a/app/lib/dto/ConfDTO.ts
+++ b/app/lib/dto/ConfDTO.ts
@@ -13,7 +13,7 @@
 
 import {CommonConstants} from "../common-libs/constants"
 import { ProxiesConf } from '../proxy';
-const _ = require('underscore');
+import {Underscore} from "../common-libs/underscore"
 const constants = require('../constants');
 
 export interface Keypair {
@@ -215,6 +215,6 @@ export class ConfDTO implements CurrencyConfDTO, KeypairConfDTO, NetworkConfDTO,
   }
 
   static complete(conf:any) {
-    return _(ConfDTO.defaultConf()).extend(conf);
+    return Underscore.extend(ConfDTO.defaultConf(), conf)
   }
 }
\ No newline at end of file
diff --git a/app/lib/dto/PeerDTO.ts b/app/lib/dto/PeerDTO.ts
index 119c8a90c7c3938ed7b658d81af88edd418223c7..9fb10b08f28752e8cbd4c3c5ae6675ae193400f7 100644
--- a/app/lib/dto/PeerDTO.ts
+++ b/app/lib/dto/PeerDTO.ts
@@ -11,11 +11,10 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-import {DBPeer} from "../dal/sqliteDAL/PeerDAL"
 import {hashf} from "../common"
 import {CommonConstants} from "../common-libs/constants"
 import {Cloneable} from "./Cloneable"
-import { WS2PConstants } from '../../modules/ws2p/lib/constants';
+import {DBPeer} from "../db/DBPeer"
 
 export interface WS2PEndpoint {
   version:number
diff --git a/app/lib/indexer.ts b/app/lib/indexer.ts
index 705e632dc366f9689351786d94b4dce913f265dd..c93ac3851b812e6decd1a61e1815ed051311f074 100644
--- a/app/lib/indexer.ts
+++ b/app/lib/indexer.ts
@@ -210,7 +210,13 @@ export interface BlockchainBlocksDAL {
 
 export class Indexer {
 
-  static localIndex(block:BlockDTO, conf:CurrencyConfDTO): IndexEntry[] {
+  static localIndex(block:BlockDTO, conf:{
+    sigValidity:number,
+    msValidity:number,
+    msPeriod:number,
+    sigPeriod:number,
+    sigStock:number
+  }): IndexEntry[] {
 
     /********************
      * GENERAL BEHAVIOR
@@ -1628,7 +1634,9 @@ export class Indexer {
       const members = await dal.iindexDAL.getMembersPubkeys()
       for (const MEMBER of members) {
         dividends.push({
+          index: constants.S_INDEX,
           op: 'CREATE',
+          tx: null,
           identifier: MEMBER.pub,
           pos: HEAD.number,
           written_on: [HEAD.number, HEAD.hash].join('-'),
@@ -1833,27 +1841,27 @@ export class Indexer {
   }
 
   static iindexCreate(index: IndexEntry[]): IindexEntry[] {
-    return _(index).filter({ index: constants.I_INDEX, op: constants.IDX_CREATE })
+    return Underscore.where(index, { index: constants.I_INDEX, op: constants.IDX_CREATE }) as IindexEntry[]
   }
 
   static mindexCreate(index: IndexEntry[]): MindexEntry[] {
-    return _(index).filter({ index: constants.M_INDEX, op: constants.IDX_CREATE })
+    return Underscore.where(index, { index: constants.M_INDEX, op: constants.IDX_CREATE }) as MindexEntry[]
   }
 
   static iindex(index: IndexEntry[]): IindexEntry[] {
-    return _(index).filter({ index: constants.I_INDEX })
+    return Underscore.where(index, { index: constants.I_INDEX }) as IindexEntry[]
   }
 
   static mindex(index: IndexEntry[]): MindexEntry[] {
-    return _(index).filter({ index: constants.M_INDEX })
+    return Underscore.where(index, { index: constants.M_INDEX }) as MindexEntry[]
   }
 
   static cindex(index: IndexEntry[]): CindexEntry[] {
-    return _(index).filter({ index: constants.C_INDEX })
+    return Underscore.where(index, { index: constants.C_INDEX }) as CindexEntry[]
   }
 
   static sindex(index: IndexEntry[]): SindexEntry[] {
-    return _(index).filter({ index: constants.S_INDEX })
+    return Underscore.where(index, { index: constants.S_INDEX }) as SindexEntry[]
   }
 
   static DUP_HELPERS = {
diff --git a/app/lib/rules/global_rules.ts b/app/lib/rules/global_rules.ts
index dbd0b858a05c2699b29edd8ac3cc83466e97234e..417b91c35da81ecf4609417c6a31a69e89f2bb3f 100644
--- a/app/lib/rules/global_rules.ts
+++ b/app/lib/rules/global_rules.ts
@@ -25,8 +25,6 @@ import {Indexer} from "../indexer"
 import {DBTx} from "../db/DBTx"
 import {Tristamp} from "../common/Tristamp"
 
-const _ = require('underscore')
-
 const constants      = CommonConstants
 
 // Empty logger by default
diff --git a/app/lib/rules/local_rules.ts b/app/lib/rules/local_rules.ts
index d0d819cf7d148053c42b19af436ce777b5580619..2522a45fb361d3373dc240a74bf6079fa66996f3 100644
--- a/app/lib/rules/local_rules.ts
+++ b/app/lib/rules/local_rules.ts
@@ -11,7 +11,6 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
 import {BlockDTO} from "../dto/BlockDTO"
 import {ConfDTO} from "../dto/ConfDTO"
 import {CindexEntry, IndexEntry, Indexer, MindexEntry, SindexEntry} from "../indexer"
@@ -22,8 +21,7 @@ import {hashf} from "../common"
 import {CommonConstants} from "../common-libs/constants"
 import {IdentityDTO} from "../dto/IdentityDTO"
 import {MembershipDTO} from "../dto/MembershipDTO"
-
-const _          = require('underscore');
+import {Underscore} from "../common-libs/underscore"
 
 const constants       = CommonConstants
 const maxAcceleration = require('./helpers').maxAcceleration
@@ -120,7 +118,7 @@ export const LOCAL_RULES_FUNCTIONS = {
 
   checkIdentitiesUserIDConflict: async (block:BlockDTO, conf:ConfDTO, index:IndexEntry[]) => {
     const creates = Indexer.iindexCreate(index);
-    const uids = _.chain(creates).pluck('uid').uniq().value();
+    const uids = Underscore.chain(creates).pluck('uid').uniq().value();
     if (creates.length !== uids.length) {
       throw Error('Block must not contain twice same identity uid');
     }
@@ -129,7 +127,7 @@ export const LOCAL_RULES_FUNCTIONS = {
 
   checkIdentitiesPubkeyConflict: async (block:BlockDTO, conf:ConfDTO, index:IndexEntry[]) => {
     const creates = Indexer.iindexCreate(index);
-    const pubkeys = _.chain(creates).pluck('pub').uniq().value();
+    const pubkeys = Underscore.chain(creates).pluck('pub').uniq().value();
     if (creates.length !== pubkeys.length) {
       throw Error('Block must not contain twice same identity pubkey');
     }
@@ -140,7 +138,7 @@ export const LOCAL_RULES_FUNCTIONS = {
     const icreates = Indexer.iindexCreate(index);
     const mcreates = Indexer.mindexCreate(index);
     for (const icreate of icreates) {
-      const matching = _(mcreates).filter({ pub: icreate.pub });
+      const matching = Underscore.where(mcreates, { pub: icreate.pub });
       if (matching.length == 0) {
         throw Error('Each identity must match a newcomer line with same userid and certts');
       }
@@ -151,12 +149,11 @@ export const LOCAL_RULES_FUNCTIONS = {
   checkRevokedAreExcluded: async (block:BlockDTO, conf:ConfDTO, index:IndexEntry[]) => {
     const iindex = Indexer.iindex(index);
     const mindex = Indexer.mindex(index);
-    const revocations = _.chain(mindex)
-      .filter((row:MindexEntry) => row.op == constants.IDX_UPDATE && row.revoked_on !== null)
-      .pluck('pub')
-      .value();
+    const revocations = mindex
+      .filter((row:MindexEntry) => !!(row.op == constants.IDX_UPDATE && row.revoked_on !== null))
+      .map(e => e.pub)
     for (const pub of revocations) {
-      const exclusions = _(iindex).where({ op: constants.IDX_UPDATE, member: false, pub });
+      const exclusions = Underscore.where(iindex, { op: constants.IDX_UPDATE, member: false, pub })
       if (exclusions.length == 0) {
         throw Error('A revoked member must be excluded');
       }
@@ -175,7 +172,7 @@ export const LOCAL_RULES_FUNCTIONS = {
 
   checkMembershipUnicity: async (block:BlockDTO, conf:ConfDTO, index:IndexEntry[]) => {
     const mindex = Indexer.mindex(index);
-    const pubkeys = _.chain(mindex).pluck('pub').uniq().value();
+    const pubkeys = Underscore.chain(mindex).pluck('pub').uniq().value();
     if (pubkeys.length !== mindex.length) {
       throw Error('Unicity constraint PUBLIC_KEY on MINDEX is not respected');
     }
@@ -256,7 +253,7 @@ export const LOCAL_RULES_FUNCTIONS = {
   checkCertificationOneByIssuer: async (block:BlockDTO, conf:ConfDTO, index:IndexEntry[]) => {
     if (block.number > 0) {
       const cindex = Indexer.cindex(index);
-      const certFromA = _.uniq(cindex.map((row:CindexEntry) => row.issuer));
+      const certFromA = Underscore.uniq(cindex.map((row:CindexEntry) => row.issuer));
       if (certFromA.length !== cindex.length) {
         throw Error('Block cannot contain two certifications from same issuer');
       }
@@ -266,7 +263,7 @@ export const LOCAL_RULES_FUNCTIONS = {
 
   checkCertificationUnicity: async (block:BlockDTO, conf:ConfDTO, index:IndexEntry[]) => {
     const cindex = Indexer.cindex(index);
-    const certAtoB = _.uniq(cindex.map((row:CindexEntry) => row.issuer + row.receiver));
+    const certAtoB = Underscore.uniq(cindex.map((row:CindexEntry) => row.issuer + row.receiver));
     if (certAtoB.length !== cindex.length) {
       throw Error('Block cannot contain identical certifications (A -> B)');
     }
@@ -279,8 +276,8 @@ export const LOCAL_RULES_FUNCTIONS = {
     const mindex = Indexer.mindex(index);
     const certified = cindex.map((row:CindexEntry) => row.receiver);
     for (const pub of certified) {
-      const exclusions = _(iindex).where({ op: constants.IDX_UPDATE, member: false, pub: pub });
-      const leavers    = _(mindex).where({ op: constants.IDX_UPDATE, leaving: true, pub: pub });
+      const exclusions = Underscore.where(iindex, { op: constants.IDX_UPDATE, member: false, pub: pub })
+      const leavers    = Underscore.where(mindex, { op: constants.IDX_UPDATE, leaving: true, pub: pub })
       if (exclusions.length > 0 || leavers.length > 0) {
         throw Error('Block cannot contain certifications concerning leavers or excluded members');
       }
@@ -347,12 +344,12 @@ export const LOCAL_RULES_FUNCTIONS = {
       }
     }
     const sindex = Indexer.localSIndex(dto);
-    const inputs = _.filter(sindex, (row:SindexEntry) => row.op == constants.IDX_UPDATE).map((row:SindexEntry) => [row.op, row.identifier, row.pos].join('-'));
-    if (inputs.length !== _.uniq(inputs).length) {
+    const inputs = Underscore.filter(sindex, (row:SindexEntry) => row.op == constants.IDX_UPDATE).map((row:SindexEntry) => [row.op, row.identifier, row.pos].join('-'));
+    if (inputs.length !== Underscore.uniq(inputs).length) {
       throw Error('It cannot exist 2 identical sources for transactions inside a given block');
     }
-    const outputs = _.filter(sindex, (row:SindexEntry) => row.op == constants.IDX_CREATE).map((row:SindexEntry) => [row.op, row.identifier, row.pos].join('-'));
-    if (outputs.length !== _.uniq(outputs).length) {
+    const outputs = Underscore.filter(sindex, (row:SindexEntry) => row.op == constants.IDX_CREATE).map((row:SindexEntry) => [row.op, row.identifier, row.pos].join('-'));
+    if (outputs.length !== Underscore.uniq(outputs).length) {
       throw Error('It cannot exist 2 identical sources for transactions inside a given block');
     }
     return true;
@@ -414,7 +411,7 @@ export interface SindexShortEntry {
 }
 
 function getMaxTransactionDepth(sindex:SindexShortEntry[]) {
-  const ids = _.uniq(_.pluck(sindex, 'tx'))
+  const ids = Underscore.uniq(Underscore.pluck(sindex, 'tx')) as string[] // We are sure because at this moment no UD is in the sources
   let maxTxChainingDepth = 0
   for (let id of ids) {
     maxTxChainingDepth = Math.max(maxTxChainingDepth, getTransactionDepth(id, sindex, 0))
@@ -423,13 +420,14 @@ function getMaxTransactionDepth(sindex:SindexShortEntry[]) {
 }
 
 function getTransactionDepth(txHash:string, sindex:SindexShortEntry[], localDepth = 0) {
-  const inputs = _.filter(sindex, (s:SindexShortEntry) => s.op === 'UPDATE' && s.tx === txHash)
+  const inputs = Underscore.filter(sindex, (s:SindexShortEntry) => s.op === 'UPDATE' && s.tx === txHash)
   let depth = localDepth
   for (let input of inputs) {
-    const consumedOutput = _.findWhere(sindex, { op: 'CREATE', identifier: input.identifier, pos: input.pos })
+    const consumedOutput = Underscore.findWhere(sindex, { op: 'CREATE', identifier: input.identifier, pos: input.pos })
     if (consumedOutput) {
       if (localDepth < 5) {
-        const subTxDepth = getTransactionDepth(consumedOutput.tx, sindex, localDepth + 1)
+        // Cast: we are sure because at this moment no UD is in the sources
+        const subTxDepth = getTransactionDepth(consumedOutput.tx as string, sindex, localDepth + 1)
         depth = Math.max(depth, subTxDepth)
       } else {
         depth++
diff --git a/app/lib/streams/multicaster.ts b/app/lib/streams/multicaster.ts
index 43d2a3b0621611c38de47941a7723ff4f19b54ea..cf2cdbf3fc9eb7b2c2e13cd108c14b64c2e03290 100644
--- a/app/lib/streams/multicaster.ts
+++ b/app/lib/streams/multicaster.ts
@@ -13,7 +13,6 @@
 
 import {ConfDTO} from "../dto/ConfDTO"
 import * as stream from "stream"
-import {DBPeer} from "../dal/sqliteDAL/PeerDAL"
 import {BlockDTO} from "../dto/BlockDTO"
 import {RevocationDTO} from "../dto/RevocationDTO"
 import {IdentityDTO} from "../dto/IdentityDTO"
@@ -22,6 +21,7 @@ import {MembershipDTO} from "../dto/MembershipDTO"
 import {TransactionDTO} from "../dto/TransactionDTO"
 import {PeerDTO} from "../dto/PeerDTO"
 import {CommonConstants} from "../common-libs/constants"
+import {DBPeer} from "../db/DBPeer"
 
 const request = require('request');
 const constants = require('../../lib/constants');
diff --git a/app/lib/streams/router.ts b/app/lib/streams/router.ts
index 30953a8689928e2ee715e58ce9a5140fb014d078..d5a88d46b883d934588cf2a138466ff11c488df6 100644
--- a/app/lib/streams/router.ts
+++ b/app/lib/streams/router.ts
@@ -14,8 +14,8 @@
 import * as stream from "stream"
 import {PeeringService} from "../../service/PeeringService"
 import {FileDAL} from "../dal/fileDAL"
-import {DBPeer} from "../dal/sqliteDAL/PeerDAL"
 import {PeerDTO} from "../dto/PeerDTO"
+import {DBPeer} from "../db/DBPeer"
 
 const constants = require('../constants');
 
diff --git a/app/modules/bma/index.ts b/app/modules/bma/index.ts
index 462ee2c857bfbb0c2f7097931e341b99f1ac23f1..7bfd78702290cfb9590907750ebe22282a3b9420 100644
--- a/app/modules/bma/index.ts
+++ b/app/modules/bma/index.ts
@@ -11,25 +11,21 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
 import {NetworkConfDTO} from "../../lib/dto/ConfDTO"
 import {Server} from "../../../server"
 import * as stream from "stream"
-import {BmaApi, Network} from "./lib/network"
-import {UpnpApi} from "./lib/upnp"
+import {BmaApi, Network, NetworkInterface} from "./lib/network"
+import {Upnp, UpnpApi} from "./lib/upnp"
 import {BMAConstants} from "./lib/constants"
 import {BMALimitation} from "./lib/limiter"
 import {PeerDTO} from "../../lib/dto/PeerDTO"
+import {Underscore} from "../../lib/common-libs/underscore"
+import {bma} from "./lib/bma"
 
 const Q = require('q');
-const os = require('os');
 const rp = require('request-promise');
 const async = require('async');
-const _ = require('underscore');
-const upnp = require('./lib/upnp').Upnp
-const bma = require('./lib/bma').bma
 const dtos = require('./lib/dtos')
-const http2raw = require('./lib/http2raw');
 const inquirer = require('inquirer');
 
 let networkWizardDone = false;
@@ -173,7 +169,7 @@ export const BmaDependency = {
         if (!conf.ipv6) delete conf.ipv6;
         if (!conf.remoteipv4) delete conf.remoteipv4;
         if (!conf.remoteipv6) delete conf.remoteipv6;
-        conf.dos.whitelist = _.uniq(conf.dos.whitelist);
+        conf.dos.whitelist = Underscore.uniq(conf.dos.whitelist);
       }
     },
 
@@ -189,7 +185,8 @@ export const BmaDependency = {
 
     methods: {
       noLimit: () => BMALimitation.noLimit(),
-      bma, dtos,
+      bma: async (server: Server, interfaces: (NetworkInterface[] | null) = null, httpLogs = false, logger?: any) => bma(server, interfaces, httpLogs, logger),
+      dtos,
       getMainEndpoint: (conf:NetworkConfDTO) => Promise.resolve(getEndpoint(conf))
     }
   }
@@ -243,7 +240,7 @@ export class BMAPI extends stream.Transform {
     }
     if (this.server.conf.upnp) {
       try {
-        this.upnpAPI = await upnp(this.server.conf.port, this.server.conf.remoteport, this.logger, this.server.conf);
+        this.upnpAPI = await Upnp(this.server.conf.port, this.server.conf.remoteport, this.logger, this.server.conf);
         this.upnpAPI.startRegular();
         const gateway = await this.upnpAPI.findGateway();
         if (gateway) {
@@ -306,7 +303,7 @@ function networkReconfiguration(conf:NetworkConfDTO, autoconf:boolean, logger:an
       const useUPnPOperations = getUseUPnPOperations(conf, logger, autoconf);
 
       if (upnpSuccess) {
-        _.extend(conf, upnpConf);
+        Underscore.extend(conf, upnpConf)
         const local = [conf.ipv4, conf.port].join(':');
         const remote = [conf.remoteipv4, conf.remoteport].join(':');
         if (autoconf) {
@@ -408,7 +405,7 @@ function getLocalNetworkOperations(conf:NetworkConfDTO, autoconf:boolean = false
       const interfaces = [{ name: "None", value: null }];
       osInterfaces.forEach(function(netInterface:any){
         const addresses = netInterface.addresses;
-        const filtered = _(addresses).where({family: 'IPv4'});
+        const filtered = Underscore.where(addresses, {family: 'IPv4'});
         filtered.forEach(function(addr:any){
           interfaces.push({
             name: [netInterface.name, addr.address].join(' '),
@@ -436,7 +433,7 @@ function getLocalNetworkOperations(conf:NetworkConfDTO, autoconf:boolean = false
       const interfaces:any = [{ name: "None", value: null }];
       osInterfaces.forEach(function(netInterface:any){
         const addresses = netInterface.addresses;
-        const filtered = _(addresses).where({ family: 'IPv6' });
+        const filtered = Underscore.where(addresses, { family: 'IPv6' });
         filtered.forEach(function(addr:any){
           let address = addr.address
           if (addr.scopeid)
@@ -495,7 +492,7 @@ function getRemoteNetworkOperations(conf:NetworkConfDTO, remoteipv4:string|null)
       const osInterfaces = Network.listInterfaces();
       osInterfaces.forEach(function(netInterface:any){
         const addresses = netInterface.addresses;
-        const filtered = _(addresses).where({family: 'IPv4'});
+        const filtered = Underscore.where(addresses, {family: 'IPv4'});
         filtered.forEach(function(addr:any){
           choices.push({
             name: [netInterface.name, addr.address].join(' '),
diff --git a/app/modules/bma/lib/bma.ts b/app/modules/bma/lib/bma.ts
index 183125820a98dcc8ed1773bafed2a2273ae0f288..d821c2e2b72ebb456c73aa42831bc14a7a491b3d 100644
--- a/app/modules/bma/lib/bma.ts
+++ b/app/modules/bma/lib/bma.ts
@@ -29,7 +29,7 @@ const co = require('co');
 const es = require('event-stream');
 const WebSocketServer = require('ws').Server;
 
-export const bma = function(server:Server, interfaces:NetworkInterface[], httpLogs:boolean, logger:any): Promise<BmaApi> {
+export const bma = function(server:Server, interfaces:NetworkInterface[]|null, httpLogs:boolean, logger:any): Promise<BmaApi> {
 
   if (!interfaces) {
     interfaces = [];
diff --git a/app/modules/bma/lib/controllers/blockchain.ts b/app/modules/bma/lib/controllers/blockchain.ts
index b035728878b9ae53bd7b1b452ebb7b936cf0f2dd..2fc5fa748dce9a9c453a532cec79b083c30dbf88 100644
--- a/app/modules/bma/lib/controllers/blockchain.ts
+++ b/app/modules/bma/lib/controllers/blockchain.ts
@@ -11,7 +11,6 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
 import {Server} from "../../../../../server"
 import {AbstractController} from "./AbstractController"
 import {ParametersService} from "../parameters"
@@ -30,8 +29,8 @@ import {
 } from "../dtos"
 import {TransactionDTO} from "../../../../lib/dto/TransactionDTO"
 import {DataErrors} from "../../../../lib/common-libs/errors"
+import {Underscore} from "../../../../lib/common-libs/underscore"
 
-const _                = require('underscore');
 const http2raw         = require('../http2raw');
 const toJson = require('../tojson');
 
@@ -214,7 +213,7 @@ export class BlockchainBinding extends AbstractController {
     }
     return {
       "block": number + 1,
-      "levels": _.sortBy(difficulties, (diff:any) => diff.level)
+      "levels": Underscore.sortBy(difficulties, (diff:any) => diff.level)
     };
   }
 
@@ -237,7 +236,7 @@ export class BlockchainBinding extends AbstractController {
         };
       })
     }
-    json.memberships = _.sortBy(json.memberships, 'blockNumber');
+    json.memberships = Underscore.sortBy(json.memberships, 'blockNumber')
     json.memberships.reverse();
     return json;
   }
diff --git a/app/modules/bma/lib/controllers/network.ts b/app/modules/bma/lib/controllers/network.ts
index 6072103feba92f98cc35fdbe01e59acf590136ba..61bfc34dcfc4f2a1476c20a3f0d170d041ca309e 100644
--- a/app/modules/bma/lib/controllers/network.ts
+++ b/app/modules/bma/lib/controllers/network.ts
@@ -15,8 +15,8 @@ import {AbstractController} from "./AbstractController"
 import {BMAConstants} from "../constants"
 import {HttpMerkleOfPeers, HttpPeer, HttpPeers, HttpWS2PHeads, HttpWS2PInfo} from "../dtos"
 import {WS2PHead} from "../../../ws2p/lib/WS2PCluster"
+import {DBPeer} from "../../../../lib/db/DBPeer"
 
-const _                = require('underscore');
 const http2raw         = require('../http2raw');
 
 export class NetworkBinding extends AbstractController {
@@ -64,19 +64,8 @@ export class NetworkBinding extends AbstractController {
   async peers(): Promise<HttpPeers> {
     let peers = await this.server.dal.listAllPeers();
     return {
-      peers: peers.map((p:any) => {
-        return _.pick(p,
-          'version',
-          'currency',
-          'status',
-          'first_down',
-          'last_try',
-          'pubkey',
-          'block',
-          'signature',
-          'endpoints');
-      })
-    };
+      peers: peers.map(p => DBPeer.json(p))
+    }
   }
 
   async ws2pInfo(): Promise<HttpWS2PInfo> {
diff --git a/app/modules/bma/lib/controllers/transactions.ts b/app/modules/bma/lib/controllers/transactions.ts
index 7676feaa8e1bde90c2796419cfb44046e864ee52..e921f4d88f4f0a1969903445f8eb5c3d90067465 100644
--- a/app/modules/bma/lib/controllers/transactions.ts
+++ b/app/modules/bma/lib/controllers/transactions.ts
@@ -18,8 +18,8 @@ import {BMAConstants} from "../constants";
 import {TransactionDTO} from "../../../../lib/dto/TransactionDTO";
 import {HttpSources, HttpTransaction, HttpTxHistory, HttpTxOfHistory, HttpTxPending} from "../dtos";
 import {DBTx} from "../../../../lib/db/DBTx"
+import {Underscore} from "../../../../lib/common-libs/underscore"
 
-const _                = require('underscore');
 const http2raw         = require('../http2raw');
 
 export class TransactionBinding extends AbstractController {
@@ -96,9 +96,9 @@ export class TransactionBinding extends AbstractController {
     const to = await ParametersService.getToP(req);
     return this.getFilteredHistory(pubkey, (res:any) => {
       const histo = res.history;
-      histo.sent =     _.filter(histo.sent, function(tx:any){ return tx && tx.block_number >= from && tx.block_number <= to; });
-      histo.received = _.filter(histo.received, function(tx:any){ return tx && tx.block_number >= from && tx.block_number <= to; });
-      _.extend(histo, { sending: [], receiving: [] });
+      histo.sent =     Underscore.filter(histo.sent, function(tx:any){ return tx && tx.block_number >= from && tx.block_number <= to; });
+      histo.received = Underscore.filter(histo.received, function(tx:any){ return tx && tx.block_number >= from && tx.block_number <= to; });
+      Underscore.extend(histo, { sending: [], receiving: [] });
       return res;
     });
   }
@@ -109,9 +109,9 @@ export class TransactionBinding extends AbstractController {
     const to = await ParametersService.getToP(req);
     return this.getFilteredHistory(pubkey, (res:any) => {
       const histo = res.history;
-      histo.sent =     _.filter(histo.sent, function(tx:any){ return tx && tx.time >= from && tx.time <= to; });
-      histo.received = _.filter(histo.received, function(tx:any){ return tx && tx.time >= from && tx.time <= to; });
-      _.extend(histo, { sending: [], receiving: [] });
+      histo.sent =     Underscore.filter(histo.sent, function(tx:any){ return tx && tx.time >= from && tx.time <= to; });
+      histo.received = Underscore.filter(histo.received, function(tx:any){ return tx && tx.time >= from && tx.time <= to; });
+      Underscore.extend(histo, { sending: [], receiving: [] });
       return res;
     });
   }
@@ -120,7 +120,7 @@ export class TransactionBinding extends AbstractController {
     const pubkey = await ParametersService.getPubkeyP(req);
     return this.getFilteredHistory(pubkey, function(res:any) {
       const histo = res.history;
-      _.extend(histo, { sent: [], received: [] });
+      Underscore.extend(histo, { sent: [], received: [] });
       return res;
     });
   }
diff --git a/app/modules/bma/lib/controllers/uds.ts b/app/modules/bma/lib/controllers/uds.ts
index 14b5f6f29c72c7b0bbd16c0ac8f61cd79a9db377..f2378438797664ce5f6d1c547503f5f66ef9dfd6 100644
--- a/app/modules/bma/lib/controllers/uds.ts
+++ b/app/modules/bma/lib/controllers/uds.ts
@@ -15,8 +15,7 @@ import {AbstractController} from "./AbstractController"
 import {ParametersService} from "../parameters"
 import {Source} from "../entity/source"
 import {HttpUDHistory} from "../dtos";
-
-const _ = require('underscore');
+import {Underscore} from "../../../../lib/common-libs/underscore"
 
 export class UDBinding extends AbstractController {
 
@@ -30,7 +29,7 @@ export class UDBinding extends AbstractController {
     const from = await ParametersService.getFromP(req);
     const to = await ParametersService.getToP(req);
     return this.getUDSources(pubkey, (results:any) => {
-      results.history.history = _.filter(results.history.history, function(ud:any){ return ud.block_number >= from && ud.block_number <= to; });
+      results.history.history = Underscore.filter(results.history.history, function(ud:any){ return ud.block_number >= from && ud.block_number <= to; });
       return results;
     })
   }
@@ -40,7 +39,7 @@ export class UDBinding extends AbstractController {
     const from = await ParametersService.getFromP(req);
     const to = await ParametersService.getToP(req);
     return this.getUDSources(pubkey, (results:any) => {
-      results.history.history = _.filter(results.history.history, function(ud:any){ return ud.time >= from && ud.time <= to; });
+      results.history.history = Underscore.filter(results.history.history, function(ud:any){ return ud.time >= from && ud.time <= to; });
       return results;
     });
   }
@@ -52,10 +51,10 @@ export class UDBinding extends AbstractController {
         "pubkey": pubkey,
         "history": history
       };
-      _.keys(history).map((key:any) => {
+      Underscore.keys(history).map((key:any) => {
         history[key].map((src:any, index:number) => {
-          history[key][index] = _.omit(new Source(src).UDjson(), 'currency', 'raw');
-          _.extend(history[key][index], { block_number: src && src.block_number, time: src && src.time });
+          history[key][index] = new Source(src).UDjson()
+          Underscore.extend(history[key][index], { block_number: src && src.block_number, time: src && src.time });
         });
       });
       return filter(result);
diff --git a/app/modules/bma/lib/controllers/wot.ts b/app/modules/bma/lib/controllers/wot.ts
index a19f44364f93791edf0d7fa692be316d63ec6aec..6a5e8bb23b2d1eea8ad43c1e918f15ec4dcc18b6 100644
--- a/app/modules/bma/lib/controllers/wot.ts
+++ b/app/modules/bma/lib/controllers/wot.ts
@@ -32,8 +32,9 @@ import {
 import {IdentityDTO} from "../../../../lib/dto/IdentityDTO"
 import {FullIindexEntry} from "../../../../lib/indexer"
 import {DBMembership} from "../../../../lib/dal/sqliteDAL/MembershipDAL"
+import {Underscore} from "../../../../lib/common-libs/underscore"
+import {Map} from "../../../../lib/common-libs/crypto/map"
 
-const _        = require('underscore');
 const http2raw = require('../http2raw');
 const constants = require('../../../../lib/constants');
 
@@ -45,7 +46,7 @@ export class WOTBinding extends AbstractController {
     // Get the search parameter from HTTP query
     const search = await ParametersService.getSearchP(req);
     // Make the research
-    const identities:any[] = await this.IdentityService.searchIdentities(search);
+    const identities = await this.IdentityService.searchIdentities(search);
     // Entitify each result
     identities.forEach((idty, index) => identities[index] = DBIdentity.copyFromExisting(idty));
     // Prepare some data to avoid displaying expired certifications
@@ -60,17 +61,17 @@ export class WOTBinding extends AbstractController {
           cert.wasMember = member.wasMember;
         } else {
           const potentials = await this.IdentityService.getPendingFromPubkey(cert.from);
-          cert.uids = _(potentials).pluck('uid');
+          cert.uids = potentials.map(p => p.uid)
           cert.isMember = false;
           cert.wasMember = false;
         }
         validCerts.push(cert);
       }
       idty.certs = validCerts;
-      const signed = await this.server.dal.certsFrom(idty.pubkey);
+      const signed:any = await this.server.dal.certsFrom(idty.pubkey);
       const validSigned = [];
       for (let j = 0; j < signed.length; j++) {
-        const cert = _.clone(signed[j]);
+        const cert = Underscore.clone(signed[j]);
         cert.idty = await this.server.dal.getGlobalIdentityByHashForLookup(cert.target)
         if (cert.idty) {
           validSigned.push(cert);
@@ -83,7 +84,7 @@ export class WOTBinding extends AbstractController {
     if (identities.length == 0) {
       throw BMAConstants.ERRORS.NO_MATCHING_IDENTITY;
     }
-    const resultsByPubkey:{[k:string]:HttpIdentity} = {};
+    const resultsByPubkey:Map<HttpIdentity> = {};
     identities.forEach((identity) => {
       const copy = DBIdentity.copyFromExisting(identity)
       const jsoned = copy.json();
@@ -100,7 +101,7 @@ export class WOTBinding extends AbstractController {
     });
     return {
       partial: false,
-      results: _.values(resultsByPubkey)
+      results: Underscore.values(resultsByPubkey)
     };
   }
 
@@ -290,7 +291,7 @@ export class WOTBinding extends AbstractController {
         };
       })
     };
-    json.memberships = _.sortBy(json.memberships, 'blockNumber');
+    json.memberships = Underscore.sortBy(json.memberships, 'blockNumber');
     json.memberships.reverse();
     return json;
   }
diff --git a/app/modules/bma/lib/dtos.ts b/app/modules/bma/lib/dtos.ts
index 533600a6a350f2e85aa6575a8cac4bac6508e006..d0b7f27d19e7f89c896a36799fc440b2013712cf 100644
--- a/app/modules/bma/lib/dtos.ts
+++ b/app/modules/bma/lib/dtos.ts
@@ -12,8 +12,8 @@
 // GNU Affero General Public License for more details.
 
 import {BlockDTO} from "../../../lib/dto/BlockDTO"
-import {DBPeer as DBPeer2} from "../../../lib/dal/sqliteDAL/PeerDAL"
 import {WS2PHead} from "../../ws2p/lib/WS2PCluster"
+import {JSONDBPeer} from "../../../lib/db/DBPeer"
 
 export const Summary = {
   duniter: {
@@ -400,7 +400,7 @@ export const Peers = {
 };
 
 export interface HttpPeers {
-  peers: DBPeer2[]
+  peers: JSONDBPeer[]
 }
 
 export interface HttpWS2PInfo {
@@ -434,7 +434,7 @@ export interface HttpMerkleOfPeers {
   leaves: string[]
   leaf: {
     hash: string
-    value: DBPeer2
+    value: JSONDBPeer
   }
 }
 
diff --git a/app/modules/bma/lib/entity/source.ts b/app/modules/bma/lib/entity/source.ts
index 2543a55206ffc462e0c6c9e3827b7e738df34070..15e678aacb9569b4d1ed78da3cb97efc3f6ee4c9 100644
--- a/app/modules/bma/lib/entity/source.ts
+++ b/app/modules/bma/lib/entity/source.ts
@@ -11,15 +11,14 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
-const _ = require('underscore');
+import {Underscore} from "../../../../lib/common-libs/underscore"
 
 export class Source {
 
   [k:string]: any
 
   constructor(json:any) {
-    _(json || {}).keys().forEach((key:string) => {
+    Underscore.keys(json || {}).forEach((key:string) => {
       let value = json[key];
       if (key == "number") {
         value = parseInt(value);
diff --git a/app/modules/bma/lib/network.ts b/app/modules/bma/lib/network.ts
index 831dd61ddcc28714768dfcf6fad8f67db4d3bf33..c75d8d79451a7db6dbc1ca7cccd24861c338a673 100644
--- a/app/modules/bma/lib/network.ts
+++ b/app/modules/bma/lib/network.ts
@@ -11,15 +11,14 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
 import {NetworkConfDTO} from "../../../lib/dto/ConfDTO"
 import {Server} from "../../../../server"
 import {BMAConstants} from "./constants"
 import {BMALimitation} from "./limiter"
+import {Underscore} from "../../../lib/common-libs/underscore"
 
 const os = require('os');
 const Q = require('q');
-const _ = require('underscore');
 const ddos = require('ddos');
 const http = require('http');
 const express = require('express');
@@ -67,7 +66,7 @@ export const Network = {
     }
     const ddosConf = server.conf.dos || {};
     ddosConf.silentStart = true
-    ddosConf.whitelist = _.uniq((ddosConf.whitelist || []).concat(whitelist));
+    ddosConf.whitelist = Underscore.uniq((ddosConf.whitelist || []).concat(whitelist));
     const ddosInstance = new ddos(ddosConf);
     app.use(ddosInstance.express);
 
@@ -162,7 +161,7 @@ export const Network = {
       return {
         http: httpServer,
         closeSockets: () => {
-          _.keys(sockets).map((socketId:number) => {
+          Underscore.keys(sockets).map((socketId:string) => {
             sockets[socketId].destroy();
           });
         }
@@ -284,8 +283,8 @@ function getBestLocalIPv6() {
   const osInterfaces = listInterfaces();
   for (let netInterface of osInterfaces) {
     const addresses = netInterface.addresses;
-    const filtered = _(addresses).where({family: 'IPv6', scopeid: 0, internal: false });
-    const filtered2 = _.filter(filtered, (address:any) => !address.address.match(/^fe80/) && !address.address.match(/^::1/));
+    const filtered = Underscore.where(addresses, {family: 'IPv6', scopeid: 0, internal: false })
+    const filtered2 = Underscore.filter(filtered, (address:any) => !address.address.match(/^fe80/) && !address.address.match(/^::1/));
     if (filtered2[0]) {
       return filtered2[0].address;
     }
@@ -295,7 +294,7 @@ function getBestLocalIPv6() {
 
 function getBestLocal(family:string) {
   let netInterfaces = os.networkInterfaces();
-  let keys = _.keys(netInterfaces);
+  let keys = Underscore.keys(netInterfaces);
   let res = [];
   for (const name of keys) {
     let addresses = netInterfaces[name];
@@ -321,7 +320,7 @@ function getBestLocal(family:string) {
     /^Loopback/,
     /^None/
   ];
-  const best = _.sortBy(res, function(entry:any) {
+  const best = Underscore.sortBy(res, function(entry:any) {
     for (let i = 0; i < interfacePriorityRegCatcher.length; i++) {
       // `i` is the priority (0 is the better, 1 is the second, ...)
       if (entry.name.match(interfacePriorityRegCatcher[i])) return i;
@@ -333,7 +332,7 @@ function getBestLocal(family:string) {
 
 function listInterfaces() {
   const netInterfaces = os.networkInterfaces();
-  const keys = _.keys(netInterfaces);
+  const keys = Underscore.keys(netInterfaces);
   const res = [];
   for (const name of keys) {
     res.push({
diff --git a/app/modules/bma/lib/sanitize.ts b/app/modules/bma/lib/sanitize.ts
index d2a5ce5e70c74d43b881e7911342631587101271..0a2716741e5d207690ed214b07bd9019fd552553 100644
--- a/app/modules/bma/lib/sanitize.ts
+++ b/app/modules/bma/lib/sanitize.ts
@@ -11,9 +11,7 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
-
-let _ = require('underscore');
+import {Underscore} from "../../../lib/common-libs/underscore"
 
 module.exports = function sanitize (json:any, contract:any) {
 
@@ -44,9 +42,9 @@ module.exports = function sanitize (json:any, contract:any) {
         }
       }
 
-      let contractFields = _(contract).keys();
-      let objectFields = _(json).keys();
-      let toDeleteFromObj = _.difference(objectFields, contractFields);
+      let contractFields = Underscore.keys(contract)
+      let objectFields = Underscore.keys(json)
+      let toDeleteFromObj = Underscore.difference(objectFields, contractFields)
 
       // Remove unwanted fields
       for (let i = 0, len = toDeleteFromObj.length; i < len; i++) {
@@ -74,7 +72,7 @@ module.exports = function sanitize (json:any, contract:any) {
           }
         }
         // Check coherence & alter member if needed
-        if (!_(json[prop]).isNull() && t.toLowerCase() != tjson.toLowerCase()) {
+        if (json[prop] !== null && t.toLowerCase() != tjson.toLowerCase()) {
           try {
             if (t == "String") {
               let s = json[prop] == undefined ? '' : json[prop];
diff --git a/app/modules/bma/lib/tojson.ts b/app/modules/bma/lib/tojson.ts
index d9528205e898778fde147cf89b8d41ae59731037..75441e665c188820fe2980aa4829718494b35158 100644
--- a/app/modules/bma/lib/tojson.ts
+++ b/app/modules/bma/lib/tojson.ts
@@ -11,10 +11,8 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
 import {BlockDTO} from "../../../lib/dto/BlockDTO"
-
-const _ = require('underscore')
+import {Underscore} from "../../../lib/common-libs/underscore"
 
 export const stat = (stat:any) => {
   return { "blocks": stat.blocks }
@@ -52,7 +50,7 @@ export const block = (block:any) => {
   json.certifications = (block.certifications || [])
   json.transactions = [];
   block.transactions.forEach((obj:any) => {
-    json.transactions.push(_(obj).omit('raw', 'certifiers', 'hash'));
+    json.transactions.push(Underscore.omit(obj, 'raw', 'certifiers', 'hash'))
   });
   json.transactions = block.transactions.map((tx:any) => {
     tx.inputs = tx.inputs.map((i:any) => i.raw || i)
diff --git a/app/modules/config.ts b/app/modules/config.ts
index 88556edb73898cc0a7ff3de74ee75f94dca312c3..0442cb20a68a968f896705e89cd4957b2de1fed7 100644
--- a/app/modules/config.ts
+++ b/app/modules/config.ts
@@ -16,8 +16,7 @@ import {ConfDTO} from "../lib/dto/ConfDTO"
 import {Server} from "../../server"
 import {CommonConstants} from "../lib/common-libs/constants"
 import {Directory} from "../lib/system/directory"
-
-const _ = require('underscore')
+import {Underscore} from "../lib/common-libs/underscore"
 
 module.exports = {
   duniter: {
@@ -45,7 +44,7 @@ module.exports = {
       onConfiguredExecute: async (server:Server, conf:ConfDTO) => {
         const fs = await Directory.getHomeFS(false, Directory.INSTANCE_HOME, false)
         const lines = (await fs.fs.fsReadFile(Directory.INSTANCE_HOMELOG_FILE)).split('\n')
-        const aggregates = _.uniq(
+        const aggregates = Underscore.uniq(
           lines
           .map(l => l.match(/: (\[\w+\](\[\w+\])*)/))
           .filter(l => l)
diff --git a/app/modules/crawler/index.ts b/app/modules/crawler/index.ts
index ddf6fc1fe79a43f8ddb624ea2ed107a561308cef..c27aa53a17adb43bff0187a5d0b4514e19e91707 100644
--- a/app/modules/crawler/index.ts
+++ b/app/modules/crawler/index.ts
@@ -33,7 +33,7 @@ export const CrawlerDependency = {
 
     methods: {
 
-      contacter: (host:string, port:number, opts:any) => new Contacter(host, port, opts),
+      contacter: (host:string, port:number, opts?:any) => new Contacter(host, port, opts),
 
       pullBlocks: async (server:Server, pubkey:string) => {
         const crawler = new Crawler(server, server.conf, server.logger);
diff --git a/app/modules/crawler/lib/contacter.ts b/app/modules/crawler/lib/contacter.ts
index c2e93c4e33f568f5147afa128f851723706e46ff..7789fc0f6c0da8f65c7dd2d713f0c2430ffc085e 100644
--- a/app/modules/crawler/lib/contacter.ts
+++ b/app/modules/crawler/lib/contacter.ts
@@ -62,7 +62,7 @@ export class Contacter {
     return this.get('/network/peering', dtos.Peer)
   }
   
-  getPeers(obj:any) {
+  getPeers(obj?:any) {
     return this.get('/network/peering/peers', dtos.MerkleOfPeers, obj)
   }
   
diff --git a/app/modules/crawler/lib/crawler.ts b/app/modules/crawler/lib/crawler.ts
index 0efe1174b3a1a502da992866e8f7ee6a95283c60..de7c52db73cea671af76354005781057b0616b6c 100644
--- a/app/modules/crawler/lib/crawler.ts
+++ b/app/modules/crawler/lib/crawler.ts
@@ -24,10 +24,9 @@ import {connect} from "./connect"
 import {CrawlerConstants} from "./constants"
 import {pullSandboxToLocalServer} from "./sandbox"
 import {cleanLongDownPeers} from "./garbager"
+import {Underscore} from "../../../lib/common-libs/underscore"
 
-const _ = require('underscore');
 const async = require('async');
-const querablep = require('querablep');
 
 /**
  * Service which triggers the server's peering generation (actualization of the Peer document).
@@ -119,7 +118,7 @@ export class PeerCrawler implements DuniterService {
     if (peers.length > CrawlerConstants.COUNT_FOR_ENOUGH_PEERS && dontCrawlIfEnoughPeers == this.DONT_IF_MORE_THAN_FOUR_PEERS) {
       return;
     }
-    let peersToTest = peers.slice().map((p:PeerDTO) => PeerDTO.fromJSONObject(p));
+    let peersToTest = peers.slice().map(p => PeerDTO.fromJSONObject(p))
     let tested:string[] = [];
     const found = [];
     while (peersToTest.length > 0) {
@@ -144,7 +143,7 @@ export class PeerCrawler implements DuniterService {
         }
       }
       // Make unique list
-      peersToTest = _.uniq(peersToTest, false, (p:PeerDTO) => p.pubkey);
+      peersToTest = Underscore.uniq(peersToTest, false, (p:PeerDTO) => p.pubkey)
     }
     this.logger.info('Crawling done.');
     for (let i = 0, len = found.length; i < len; i++) {
@@ -205,7 +204,7 @@ export class SandboxCrawler implements DuniterService {
   async sandboxPull(server:Server) {
     this.logger && this.logger.info('Sandbox pulling started...');
       const peers = await server.dal.getRandomlyUPsWithout([this.conf.pair.pub])
-      const randoms = chooseXin(peers, CrawlerConstants.SANDBOX_PEERS_COUNT)
+      const randoms = chooseXin(peers.map(p => PeerDTO.fromDBPeer(p)), CrawlerConstants.SANDBOX_PEERS_COUNT)
       let peersToTest = randoms.slice().map((p) => PeerDTO.fromJSONObject(p));
       for (const peer of peersToTest) {
         const fromHost = await connect(peer)
@@ -241,7 +240,7 @@ export class PeerTester implements DuniterService {
   private async testPeers(server:Server, conf:ConfDTO, displayDelays:boolean) {
     let peers = await server.dal.listAllPeers();
     let now = (new Date().getTime());
-    peers = _.filter(peers, (p:any) => p.pubkey != conf.pair.pub);
+    peers = Underscore.filter(peers, (p:any) => p.pubkey != conf.pair.pub);
     await Promise.all(peers.map(async (thePeer:any) => {
       let p = PeerDTO.fromJSONObject(thePeer);
       if (thePeer.status == 'DOWN') {
@@ -369,17 +368,17 @@ export class BlockCrawler {
         this.pullingEvent(server, 'start', current.number);
         this.logger && this.logger.info("Pulling blocks from the network...");
         let peers = await server.dal.findAllPeersNEWUPBut([server.conf.pair.pub]);
-        peers = _.shuffle(peers);
+        peers = Underscore.shuffle(peers);
         if (pubkey) {
-          _(peers).filter((p:any) => p.pubkey == pubkey);
+          peers = Underscore.filter(peers, (p:any) => p.pubkey == pubkey)
         }
         // Shuffle the peers
-        peers = _.shuffle(peers);
+        peers = Underscore.shuffle(peers);
         // Only take at max X of them
         peers = peers.slice(0, CrawlerConstants.MAX_NUMBER_OF_PEERS_FOR_PULLING);
         await Promise.all(peers.map(async (thePeer:any, i:number) => {
           let p = PeerDTO.fromJSONObject(thePeer);
-          this.pullingEvent(server, 'peer', _.extend({number: i, length: peers.length}, p));
+          this.pullingEvent(server, 'peer', Underscore.extend({number: i, length: peers.length}, p));
           this.logger && this.logger.trace("Try with %s %s", p.getURL(), p.pubkey.substr(0, 6));
           try {
             let node:any = await connect(p);
diff --git a/app/modules/crawler/lib/pulling.ts b/app/modules/crawler/lib/pulling.ts
index 7dc23418d1ce38ee117803d74aa8971ba1f9714c..7c785d280b2c2ac671c3990c16168d52c892d3b9 100644
--- a/app/modules/crawler/lib/pulling.ts
+++ b/app/modules/crawler/lib/pulling.ts
@@ -15,9 +15,8 @@
 import {BlockDTO} from "../../../lib/dto/BlockDTO"
 import {DBBlock} from "../../../lib/db/DBBlock"
 import {PeerDTO} from "../../../lib/dto/PeerDTO"
-import {BranchingDTO, ConfDTO} from "../../../lib/dto/ConfDTO"
-
-const _ = require('underscore');
+import {BranchingDTO} from "../../../lib/dto/ConfDTO"
+import {Underscore} from "../../../lib/common-libs/underscore"
 
 export abstract class PullingDao {
   abstract applyBranch(blocks:BlockDTO[]): Promise<boolean>
@@ -211,7 +210,7 @@ export abstract class AbstractDAO extends PullingDao {
       }
       return result;
     });
-    memberForks = _.filter(memberForks, (fork:any) => {
+    memberForks = Underscore.filter(memberForks, (fork:any) => {
       let blockDistanceInBlocks = (fork.current.number - localCurrent.number)
       let timeDistanceInBlocks = (fork.current.medianTime - localCurrent.medianTime) / conf.avgGenTime
       const requiredTimeAdvance = conf.switchOnHeadAdvance
diff --git a/app/modules/crawler/lib/sync.ts b/app/modules/crawler/lib/sync.ts
index 19dd460f6d428c089e17b6becc6036257a015817..7325a907c457eeaf8840947e181bea893582f9b5 100644
--- a/app/modules/crawler/lib/sync.ts
+++ b/app/modules/crawler/lib/sync.ts
@@ -30,8 +30,10 @@ import {hashf} from "../../../lib/common"
 import {ConfDTO} from "../../../lib/dto/ConfDTO"
 import {PeeringService} from "../../../service/PeeringService"
 import {CommonConstants} from "../../../lib/common-libs/constants"
+import {Underscore} from "../../../lib/common-libs/underscore"
+import {HttpMerkleOfPeers} from "../../bma/lib/dtos"
+import {DBPeer, JSONDBPeer} from "../../../lib/db/DBPeer"
 
-const _            = require('underscore');
 const moment       = require('moment');
 const multimeter   = require('multimeter');
 const makeQuerablePromise = require('querablep');
@@ -161,17 +163,17 @@ export class Synchroniser extends stream.Duplex {
       //=======
       // Peers (just for P2P download)
       //=======
-      let peers:PeerDTO[] = [];
+      let peers:(JSONDBPeer|null)[] = [];
       if (!nopeers && (to - localNumber > 1000)) { // P2P download if more than 1000 blocs
         this.watcher.writeStatus('Peers...');
         const merkle = await this.dal.merkleForPeers();
-        const getPeers = node.getPeers.bind(node);
+        const getPeers:(params:any) => Promise<HttpMerkleOfPeers> = node.getPeers.bind(node);
         const json2 = await getPeers({});
         const rm = new NodesMerkle(json2);
         if(rm.root() != merkle.root()){
           const leavesToAdd:string[] = [];
           const json = await getPeers({ leaves: true });
-          _(json.leaves).forEach((leaf:string) => {
+          json.leaves.forEach((leaf:string) => {
             if(merkle.leaves().indexOf(leaf) == -1){
               leavesToAdd.push(leaf);
             }
@@ -195,7 +197,7 @@ export class Synchroniser extends stream.Duplex {
       }
 
       if (!peers.length) {
-        peers.push(peer);
+        peers.push(DBPeer.fromPeerDTO(peer))
       }
       peers = peers.filter((p) => p);
 
@@ -206,7 +208,7 @@ export class Synchroniser extends stream.Duplex {
 
       // We use cautious mode if it is asked, or not particulary asked but blockchain has been started
       const cautious = (askedCautious === true || localNumber >= 0);
-      const shuffledPeers = noShufflePeers ? peers : _.shuffle(peers);
+      const shuffledPeers = (noShufflePeers ? peers : Underscore.shuffle(peers)).filter(p => !!(p)) as JSONDBPeer[]
       const downloader = new P2PDownloader(rCurrent.currency, localNumber, to, rCurrent.hash, shuffledPeers, this.watcher, this.logger, hashf, this.dal, this.slowOption, !cautious, this.otherDAL);
 
       downloader.start();
@@ -224,7 +226,7 @@ export class Synchroniser extends stream.Duplex {
         }
 
         async applyBranch(blocks:BlockDTO[]) {
-          blocks = _.filter(blocks, (b:BlockDTO) => b.number <= to);
+          blocks = Underscore.filter(blocks, (b:BlockDTO) => b.number <= to);
           if (cautious) {
             for (const block of blocks) {
               if (block.number == 0) {
@@ -357,13 +359,13 @@ export class Synchroniser extends stream.Duplex {
       this.watcher.writeStatus('Peers...');
       await this.syncPeer(node);
       const merkle = await this.dal.merkleForPeers();
-      const getPeers = node.getPeers.bind(node);
+      const getPeers:(params:any) => Promise<HttpMerkleOfPeers> = node.getPeers.bind(node);
       const json2 = await getPeers({});
       const rm = new NodesMerkle(json2);
       if(rm.root() != merkle.root()){
         const leavesToAdd:string[] = [];
         const json = await getPeers({ leaves: true });
-        _(json.leaves).forEach((leaf:string) => {
+        json.leaves.forEach((leaf:string) => {
           if(merkle.leaves().indexOf(leaf) == -1){
             leavesToAdd.push(leaf);
           }
@@ -374,9 +376,11 @@ export class Synchroniser extends stream.Duplex {
             const jsonEntry = json3.leaf.value;
             const sign = json3.leaf.value.signature;
             const entry:any = {};
-            ["version", "currency", "pubkey", "endpoints", "block"].forEach((key) => {
-              entry[key] = jsonEntry[key];
-            });
+            entry.version = jsonEntry.version
+            entry.currency = jsonEntry.currency
+            entry.pubkey = jsonEntry.pubkey
+            entry.endpoints = jsonEntry.endpoints
+            entry.block = jsonEntry.block
             entry.signature = sign;
             this.watcher.writeStatus('Peer ' + entry.pubkey);
             await this.PeeringService.submitP(entry, false, to === undefined);
@@ -673,7 +677,7 @@ class P2PDownloader {
     private localNumber:number,
     private to:number,
     private toHash:string,
-    private peers:PeerDTO[],
+    private peers:JSONDBPeer[],
     private watcher:Watcher,
     private logger:any,
     private hashf:any,
@@ -832,7 +836,7 @@ class P2PDownloader {
       throw this.NO_NODES_AVAILABLE;
     }
     // We remove the nodes impossible to reach (timeout)
-    let withGoodDelays = _.filter(candidates, (c:any) => c.tta <= this.MAX_DELAY_PER_DOWNLOAD);
+    let withGoodDelays = Underscore.filter(candidates, (c:any) => c.tta <= this.MAX_DELAY_PER_DOWNLOAD);
     if (withGoodDelays.length === 0) {
       // No node can be reached, we can try to lower the number of nodes on which we download
       this.downloadSlots = Math.floor(this.downloadSlots / 2);
@@ -842,7 +846,7 @@ class P2PDownloader {
       return this.getP2Pcandidates();
     }
     const parallelMax = Math.min(this.PARALLEL_PER_CHUNK, withGoodDelays.length);
-    withGoodDelays = _.sortBy(withGoodDelays, (c:any) => c.tta);
+    withGoodDelays = Underscore.sortBy(withGoodDelays, (c:any) => c.tta);
     withGoodDelays = withGoodDelays.slice(0, parallelMax);
     // We temporarily augment the tta to avoid asking several times to the same node in parallel
     withGoodDelays.forEach((c:any) => c.tta = this.MAX_DELAY_PER_DOWNLOAD);
@@ -876,8 +880,8 @@ class P2PDownloader {
 
         // Opening/Closing slots depending on the Interne connection
         if (this.slots.length == this.downloadSlots) {
-          const peers = await Promise.all(_.values(this.nodes))
-          const downloading = _.filter(peers, (p:any) => p.downloading && p.ttas.length);
+          const peers = await Promise.all(Underscore.values(this.nodes))
+          const downloading = Underscore.filter(peers, (p:any) => p.downloading && p.ttas.length);
           const currentAvgDelay = downloading.reduce((sum:number, c:any) => {
               const tta = Math.round(c.ttas.reduce((sum:number, tta:number) => sum + tta, 0) / c.ttas.length);
               return sum + tta;
diff --git a/app/modules/export-bc.ts b/app/modules/export-bc.ts
index 2deb97a2ad1186a798ddf5bee0d3d44629b079e1..1a0de70cbdefa1b29ac33335d5680eb11eebc1c1 100644
--- a/app/modules/export-bc.ts
+++ b/app/modules/export-bc.ts
@@ -11,13 +11,10 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
 import {ConfDTO} from "../lib/dto/ConfDTO"
 import {Server} from "../../server"
 import {BlockDTO} from "../lib/dto/BlockDTO"
 
-const _ = require('underscore');
-
 module.exports = {
   duniter: {
     cli: [{
@@ -48,7 +45,7 @@ module.exports = {
           for (const chunk of chunks) {
             let blocks = await server.dal.getBlocksBetween(chunk.start, chunk.to);
             blocks.forEach(function (block:any) {
-              jsoned.push(_(BlockDTO.fromJSONObject(block).json()).omit('raw'));
+              jsoned.push(BlockDTO.fromJSONObject(block).json())
             });
           }
           if (!program.nostdout) {
diff --git a/app/modules/prover/index.ts b/app/modules/prover/index.ts
index 71dcdc6a5555a1fec4dd221e811c38deba73b342..2cd89b4d8ec6300b0282947703bbe7f61270c723 100644
--- a/app/modules/prover/index.ts
+++ b/app/modules/prover/index.ts
@@ -69,7 +69,7 @@ export const ProverDependency = {
         server.generatorComputeNewCerts = generator.computeNewCerts.bind(generator)
         server.generatorNewCertsToLinks = generator.newCertsToLinks.bind(generator)
       },
-      prover: (server:Server, conf:ConfDTO, logger:any) => new Prover(server),
+      prover: (server:Server) => new Prover(server),
       blockGenerator: (server:Server, prover:any) => new BlockGeneratorWhichProves(server, prover),
       generateTheNextBlock: async (server:Server, manualValues:any) => {
         const prover = new BlockProver(server);
diff --git a/app/modules/prover/lib/blockGenerator.ts b/app/modules/prover/lib/blockGenerator.ts
index 7e9d229ec2630a849be853f1c55cbdb9fba62e5c..0076a28577ed54a19b321ed55fe7b3f7cc9e478b 100644
--- a/app/modules/prover/lib/blockGenerator.ts
+++ b/app/modules/prover/lib/blockGenerator.ts
@@ -11,7 +11,6 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
 import {Server} from "../../../../server"
 import {BlockchainContext} from "../../../lib/computation/BlockchainContext"
 import {TransactionDTO} from "../../../lib/dto/TransactionDTO"
@@ -30,14 +29,16 @@ import {BlockDTO} from "../../../lib/dto/BlockDTO"
 import {ConfDTO} from "../../../lib/dto/ConfDTO"
 import {FileDAL} from "../../../lib/dal/fileDAL"
 import {DataErrors} from "../../../lib/common-libs/errors"
+import {Underscore} from "../../../lib/common-libs/underscore"
+import {DBCert} from "../../../lib/dal/sqliteDAL/CertDAL"
+import {Map} from "../../../lib/common-libs/crypto/map"
 
-const _               = require('underscore');
 const moment          = require('moment');
 const inquirer        = require('inquirer');
 
 const constants     = CommonConstants
 
-interface PreJoin {
+export interface PreJoin {
   identity: {
     pubkey: string
     uid: string
@@ -49,7 +50,7 @@ interface PreJoin {
   }
   key: null
   idHash: string
-  certs: any[]
+  certs: DBCert[]
   ms: any
 }
 
@@ -107,20 +108,19 @@ export class BlockGenerator {
     const exclusions = await this.dal.getToBeKickedPubkeys();
     const wereExcludeds = await this.dal.getRevokedPubkeys();
     const newCertsFromWoT = await generator.findNewCertsFromWoT(current);
-    const newcomers = await this.findNewcomers(current, (joinersData:any) => generator.filterJoiners(joinersData))
+    const newcomers = await this.findNewcomers(current, joinersData => generator.filterJoiners(joinersData))
     const leavers = await this.findLeavers(current)
     const transactions = await this.findTransactions(current, manualValues);
-    const certifiersOfNewcomers = _.uniq(_.keys(newcomers).reduce((theCertifiers:any, newcomer:string) => {
-      return theCertifiers.concat(_.pluck(newcomers[newcomer].certs, 'from'));
-    }, []));
-    const certifiers:string[] = [].concat(certifiersOfNewcomers);
+    const certifiersOfNewcomers = Underscore.uniq(Underscore.keys(newcomers).reduce((theCertifiers, newcomer:string) => {
+      return theCertifiers.concat(Underscore.pluck(newcomers[newcomer].certs, 'from'));
+    }, <string[]>[]))
     // Merges updates
-    _(newCertsFromWoT).keys().forEach(function(certified:string){
+    Underscore.keys(newCertsFromWoT).forEach(function(certified:string){
       newCertsFromWoT[certified] = newCertsFromWoT[certified].filter((cert:any) => {
         // Must not certify a newcomer, since it would mean multiple certifications at same time from one member
-        const isCertifier = certifiers.indexOf(cert.from) != -1;
+        const isCertifier = certifiersOfNewcomers.indexOf(cert.from) != -1;
         if (!isCertifier) {
-          certifiers.push(cert.from);
+          certifiersOfNewcomers.push(cert.from);
         }
         return !isCertifier;
       });
@@ -144,7 +144,7 @@ export class BlockGenerator {
         await LOCAL_RULES_HELPERS.checkBunchOfTransactions(passingTxs.concat(tx), this.conf, options)
         const nextBlockWithFakeTimeVariation = { medianTime: current.medianTime + 1 };
         await GLOBAL_RULES_HELPERS.checkSingleTransaction(tx, nextBlockWithFakeTimeVariation, this.conf, this.dal, async (txHash:string) => {
-          return _.findWhere(passingTxs, { hash: txHash }) || null
+          return Underscore.findWhere(passingTxs, { hash: txHash }) || null
         });
         await GLOBAL_RULES_HELPERS.checkTxBlockStamp(tx, this.dal);
         transactions.push(tx);
@@ -191,21 +191,21 @@ export class BlockGenerator {
     return leaveData;
   }
 
-  private async findNewcomers(current:DBBlock|null, filteringFunc: (joinData: { [pub:string]: any }) => Promise<{ [pub:string]: any }>) {
+  private async findNewcomers(current:DBBlock|null, filteringFunc: (joinData: Map<PreJoin>) => Promise<Map<PreJoin>>) {
     const preJoinData = await this.getPreJoinData(current);
     const joinData = await filteringFunc(preJoinData);
     const members = await this.dal.getMembers();
-    const wotMembers = _.pluck(members, 'pubkey');
+    const wotMembers = Underscore.pluck(members, 'pubkey');
     // Checking step
-    let newcomers = _(joinData).keys();
-    newcomers = _.shuffle(newcomers)
+    let newcomers = Underscore.keys(joinData)
+    newcomers = Underscore.shuffle(newcomers)
     const nextBlockNumber = current ? current.number + 1 : 0;
     try {
       const realNewcomers = await this.iteratedChecking(newcomers, async (someNewcomers:string[]) => {
         const nextBlock = {
           number: nextBlockNumber,
           joiners: someNewcomers,
-          identities: _.filter(newcomers.map((pub:string) => joinData[pub].identity), { wasMember: false }).map((idty:any) => idty.pubkey)
+          identities: Underscore.where(newcomers.map((pub:string) => joinData[pub].identity), { wasMember: false }).map((idty:any) => idty.pubkey)
         };
         const theNewLinks = await this.computeNewLinks(nextBlockNumber, someNewcomers, joinData)
         await this.checkWoTConstraints(nextBlock, theNewLinks, current);
@@ -314,22 +314,22 @@ export class BlockGenerator {
     return preJoinData;
   }
 
-  private async computeNewLinks(forBlock:number, theNewcomers:any, joinData:any) {
+  private async computeNewLinks(forBlock:number, theNewcomers:any, joinData:Map<PreJoin>) {
     let newCerts = await this.computeNewCerts(forBlock, theNewcomers, joinData);
     return this.newCertsToLinks(newCerts);
   }
 
-  newCertsToLinks(newCerts:any) {
-    let newLinks:any = {};
-    _.mapObject(newCerts, function(certs:any, pubkey:string) {
-      newLinks[pubkey] = _.pluck(certs, 'from');
-    });
-    return newLinks;
+  newCertsToLinks(newCerts:Map<DBCert[]>) {
+    let newLinks: Map<string[]> = {}
+    for (const pubkey of Underscore.keys(newCerts)) {
+      newLinks[pubkey] = Underscore.pluck(newCerts[pubkey], 'from')
+    }
+    return newLinks
   }
 
-  async computeNewCerts(forBlock:number, theNewcomers:any, joinData:any) {
-    const newCerts:any = {}, certifiers = [];
-    const certsByKey = _.mapObject(joinData, function(val:any){ return val.certs; });
+  async computeNewCerts(forBlock:number, theNewcomers:any, joinData:Map<PreJoin>) {
+    const newCerts:Map<DBCert[]> = {}, certifiers:string[] = []
+    const certsByKey = Underscore.mapObjectByProp(joinData, 'certs')
     for (const newcomer of theNewcomers) {
       // New array of certifiers
       newCerts[newcomer] = newCerts[newcomer] || [];
@@ -352,10 +352,10 @@ export class BlockGenerator {
         }
       }
     }
-    return newCerts;
+    return newCerts
   }
 
-  async getSinglePreJoinData(current:DBBlock|null, idHash:string, joiners:string[]) {
+  async getSinglePreJoinData(current:DBBlock|null, idHash:string, joiners:string[]): Promise<PreJoin> {
     const identity = await this.dal.getGlobalIdentityByHashForJoining(idHash)
     let foundCerts = [];
     const vHEAD_1 = await this.mainContext.getvHEAD_1();
@@ -387,9 +387,9 @@ export class BlockGenerator {
       if (!current) {
         // Look for certifications from initial joiners
         const certs = await this.dal.certsNotLinkedToTarget(idHash);
-        foundCerts = _.filter(certs, function(cert:any){
+        foundCerts = Underscore.filter(certs, (cert:any) => {
           // Add 'joiners && ': special case when block#0 not written ANd not joiner yet (avoid undefined error)
-          return joiners && ~joiners.indexOf(cert.from);
+          return !!(joiners && ~joiners.indexOf(cert.from))
         });
       } else {
         // Look for certifications from WoT members
@@ -473,20 +473,20 @@ export class BlockGenerator {
     // Revocations have an impact on exclusions
     revocations.forEach((idty:any) => exclusions.push(idty.pubkey));
     // Prevent writing joins/updates for members who will be excluded
-    exclusions = _.uniq(exclusions);
+    exclusions = Underscore.uniq(exclusions);
     exclusions.forEach((excluded:any) => {
       delete updates[excluded];
       delete joinData[excluded];
       delete leaveData[excluded];
     });
     // Prevent writing joins/updates for excluded members
-    wereExcluded = _.uniq(wereExcluded);
+    wereExcluded = Underscore.uniq(wereExcluded);
     wereExcluded.forEach((excluded:any) => {
       delete updates[excluded];
       delete joinData[excluded];
       delete leaveData[excluded];
     });
-    _(leaveData).keys().forEach((leaver:any) => {
+    Underscore.keys(leaveData).forEach((leaver:any) => {
       delete updates[leaver];
       delete joinData[leaver];
     });
@@ -528,7 +528,7 @@ export class BlockGenerator {
       block.issuer = this.selfPubkey
     }
     // Members merkle
-    const joiners = _(joinData).keys();
+    const joiners = Underscore.keys(joinData)
     joiners.sort()
     const previousCount = current ? current.membersCount : 0;
     if (joiners.length == 0 && !current) {
@@ -542,7 +542,7 @@ export class BlockGenerator {
      * Priority 1: keep the WoT sane
      */
     // Certifications from the WoT, to the WoT
-    _(updates).keys().forEach((certifiedMember:any) => {
+    Underscore.keys(updates).forEach((certifiedMember:any) => {
       const certs = updates[certifiedMember] || [];
       certs.forEach((cert:any) => {
         if (blockLen < maxLenOfBlock) {
@@ -563,7 +563,7 @@ export class BlockGenerator {
       }
     });
     // Leavers
-    const leavers = _(leaveData).keys();
+    const leavers = Underscore.keys(leaveData)
     leavers.forEach((leaver:any) => {
       const data = leaveData[leaver];
       // Join only for non-members
@@ -602,7 +602,7 @@ export class BlockGenerator {
         block.joiners.push(MembershipDTO.fromJSONObject(data.ms).inline());
       }
     });
-    block.identities = _.sortBy(block.identities, (line:string) => {
+    block.identities = Underscore.sortBy(block.identities, (line:string) => {
       const sp = line.split(':');
       return sp[2] + sp[3];
     });
@@ -676,7 +676,7 @@ export class BlockGenerator {
     block.issuersFrameVar = vHEAD.issuersFrameVar;
     // Manual values before hashing
     if (manualValues) {
-      _.extend(block, _.omit(manualValues, 'time'));
+      Underscore.extend(block, Underscore.omit(manualValues, 'time'));
     }
     // InnerHash
     block.time = block.medianTime;
@@ -738,15 +738,16 @@ class NextBlockGenerator implements BlockGeneratorInterface {
         // Check if writable
         let duration = current && targetBlock ? current.medianTime - targetBlock.medianTime : 0;
         if (targetBlock && duration <= this.conf.sigWindow) {
-          cert.sig = '';
-          cert.currency = this.conf.currency;
-          cert.issuer = cert.from;
-          cert.idty_issuer = targetIdty.pubkey;
-          cert.idty_uid = targetIdty.uid;
-          cert.idty_buid = targetIdty.buid;
-          cert.idty_sig = targetIdty.sig;
-          cert.buid = current ? [cert.block_number, targetBlock.hash].join('-') : CommonConstants.SPECIAL_BLOCK;
-          const rawCert = CertificationDTO.fromJSONObject(cert).getRawUnSigned();
+          const rawCert = CertificationDTO.fromJSONObject({
+            sig: '',
+            currency: this.conf.currency,
+            issuer: cert.from,
+            idty_issuer: targetIdty.pubkey,
+            idty_uid: targetIdty.uid,
+            idty_buid: targetIdty.buid,
+            idty_sig: targetIdty.sig,
+            buid: current ? [cert.block_number, targetBlock.hash].join('-') : CommonConstants.SPECIAL_BLOCK,
+          }).getRawUnSigned();
           if (verify(rawCert, certSig, cert.from)) {
             cert.sig = certSig;
             let exists = false;
@@ -801,7 +802,7 @@ class NextBlockGenerator implements BlockGeneratorInterface {
         this.logger.warn(err);
       }
     }
-    _.keys(preJoinData).forEach( (joinPubkey:any) => filterings.push(filter(joinPubkey)));
+    Underscore.keys(preJoinData).forEach( (joinPubkey:any) => filterings.push(filter(joinPubkey)));
     await Promise.all(filterings)
     return filtered;
   }
@@ -819,7 +820,7 @@ class ManualRootGenerator implements BlockGeneratorInterface {
 
   async filterJoiners(preJoinData:any) {
     const filtered:any = {};
-    const newcomers = _(preJoinData).keys();
+    const newcomers = Underscore.keys(preJoinData)
     const uids:string[] = [];
     newcomers.forEach((newcomer:string) => uids.push(preJoinData[newcomer].ms.userid));
 
diff --git a/app/modules/prover/lib/powCluster.ts b/app/modules/prover/lib/powCluster.ts
index 4b3fa0127ae5be06215c62bf91ac3b406d7087f0..3ee90d488df904aff629220b522c99ce55b7e63c 100644
--- a/app/modules/prover/lib/powCluster.ts
+++ b/app/modules/prover/lib/powCluster.ts
@@ -16,8 +16,8 @@ import {ProverConstants} from "./constants"
 import {createPowWorker} from "./proof"
 import {PowWorker} from "./PowWorker"
 import {FileDAL} from "../../../lib/dal/fileDAL";
+import {Underscore} from "../../../lib/common-libs/underscore"
 
-const _ = require('underscore')
 const nuuid = require('node-uuid');
 const cluster = require('cluster')
 const querablep = require('querablep')
@@ -140,7 +140,7 @@ export class Master {
         value: this.conf
       })
     })
-    return Promise.resolve(_.clone(conf))
+    return Promise.resolve(Underscore.clone(conf))
   }
 
   private cancelWorkersWork() {
@@ -205,7 +205,7 @@ export class Master {
             nonceBeginning: s.nonceBeginning,
             zeros: stuff.newPoW.zeros,
             highMark: stuff.newPoW.highMark,
-            pair: _.clone(stuff.newPoW.pair),
+            pair: Underscore.clone(stuff.newPoW.pair),
             forcedTime: stuff.newPoW.forcedTime,
             conf: {
               powNoSecurity: stuff.newPoW.conf.powNoSecurity,
diff --git a/app/modules/wizard.ts b/app/modules/wizard.ts
index a6b6e3b4e3cb9e8470d7f4fa13d17d9ff5d7f7f5..51c3e38c08469b79195de403073523d4448500fe 100644
--- a/app/modules/wizard.ts
+++ b/app/modules/wizard.ts
@@ -14,8 +14,8 @@
 import {ConfDTO} from "../lib/dto/ConfDTO"
 import {Server} from "../../server"
 import {Wizard} from "../lib/wizard"
+import {Underscore} from "../lib/common-libs/underscore"
 
-const _ = require('underscore')
 const logger = require('../lib/logger').NewLogger('wizard');
 
 module.exports = {
@@ -34,7 +34,7 @@ module.exports = {
 
       onConfiguredExecute: async (server:Server, conf:ConfDTO, program:any, params:any, wizardTasks:any) => {
         const step = params[0];
-        const tasks = step ? [wizardTasks[step]] : _.values(wizardTasks);
+        const tasks = step ? [wizardTasks[step]] : Underscore.values(wizardTasks);
         for (const task of tasks) {
           if (!task) {
             throw 'Unknown task';
diff --git a/app/modules/ws2p/lib/WS2PCluster.ts b/app/modules/ws2p/lib/WS2PCluster.ts
index 2572225fa4dcdbd42020b06c07cf74e324da31bc..999c28a6b8f0bda0eb8ec968c69bb79d4b32b4af 100644
--- a/app/modules/ws2p/lib/WS2PCluster.ts
+++ b/app/modules/ws2p/lib/WS2PCluster.ts
@@ -31,10 +31,10 @@ import {CommonConstants} from '../../../lib/common-libs/constants';
 import {Package} from "../../../lib/common/package";
 import {ProverConstants} from "../../prover/lib/constants";
 import {ProxiesConf} from '../../../lib/proxy';
+import {Underscore} from "../../../lib/common-libs/underscore"
 
 const es = require('event-stream')
 const nuuid = require('node-uuid')
-const _ = require('underscore')
 
 export interface WS2PHead {
   message:string
@@ -699,7 +699,7 @@ export class WS2PCluster {
     }
     // Disconnect Private connexions already present under Public
     let uuids = Object.keys(this.ws2pClients)
-    uuids = _.shuffle(uuids)
+    uuids = Underscore.shuffle(uuids)
     for (const uuid of uuids) {
       const client = this.ws2pClients[uuid]
       const pub = client.connection.pubkey
@@ -716,7 +716,7 @@ export class WS2PCluster {
     // Disconnect Private connexions until the maximum size is respected
     while (this.clientsCount() > this.maxLevel1Size) {
       let uuids = Object.keys(this.ws2pClients)
-      uuids = _.shuffle(uuids)
+      uuids = Underscore.shuffle(uuids)
       let lowPriorityConnectionUUID:string = uuids[0]
       let minPriorityLevel = await this.keyPriorityLevel(this.ws2pClients[lowPriorityConnectionUUID].connection.pubkey, preferedKeys)
       for (const uuid of uuids) {
diff --git a/app/service/BlockchainService.ts b/app/service/BlockchainService.ts
index 63b6c89e688773bde85ba4cb761f664da62f17e9..bcd1859acc9c31772984ea775bf06acd4131b96c 100644
--- a/app/service/BlockchainService.ts
+++ b/app/service/BlockchainService.ts
@@ -31,9 +31,6 @@ import {OtherConstants} from "../lib/other_constants"
 import {DataErrors} from "../lib/common-libs/errors"
 import {DuniterBlockchain} from "../lib/blockchain/DuniterBlockchain"
 
-"use strict";
-
-const _               = require('underscore');
 const constants       = require('../lib/constants');
 
 export interface IdentityForRequirements {
diff --git a/app/service/PeeringService.ts b/app/service/PeeringService.ts
index 4187ef593825c12d223da7f46988ae7d4fea1ac2..8e34626a565889010e5d170bc3e778573fce3e39 100644
--- a/app/service/PeeringService.ts
+++ b/app/service/PeeringService.ts
@@ -13,7 +13,6 @@
 
 import {ConfDTO} from "../lib/dto/ConfDTO"
 import {FileDAL} from "../lib/dal/fileDAL"
-import {DBPeer} from "../lib/dal/sqliteDAL/PeerDAL"
 import {DBBlock} from "../lib/db/DBBlock"
 import {Multicaster} from "../lib/streams/multicaster"
 import {PeerDTO} from "../lib/dto/PeerDTO"
@@ -22,9 +21,10 @@ import {dos2unix} from "../lib/common-libs/dos2unix"
 import {rawer} from "../lib/common-libs/index"
 import {Server} from "../../server"
 import {GlobalFifoPromise} from "./GlobalFifoPromise"
+import {DBPeer} from "../lib/db/DBPeer"
+import {Underscore} from "../lib/common-libs/underscore"
 
 const util           = require('util');
-const _              = require('underscore');
 const events         = require('events');
 const logger         = require('../lib/logger').NewLogger('peering');
 const constants      = require('../lib/constants');
@@ -131,8 +131,8 @@ export class PeeringService {
           const isOutdatedDocument = blockNumber < previousBlockNumber && !eraseIfAlreadyRecorded;
           const isAlreadyKnown = blockNumber == previousBlockNumber && !eraseIfAlreadyRecorded;
           if (isOutdatedDocument){
-            const error = _.extend({}, constants.ERRORS.NEWER_PEER_DOCUMENT_AVAILABLE);
-            _.extend(error.uerr, { peer: found });
+            const error = Underscore.extend({}, constants.ERRORS.NEWER_PEER_DOCUMENT_AVAILABLE);
+            Underscore.extend(error.uerr, { peer: found });
             throw error;
           } else if (isAlreadyKnown) {
             throw constants.ERRORS.PEER_DOCUMENT_ALREADY_KNOWN;
@@ -186,7 +186,7 @@ export class PeeringService {
     return this.server.writePeer(pretendedNewer)
   }
 
-  async generateSelfPeer(theConf:ConfDTO, signalTimeInterval = 0): Promise<DBPeer|null> {
+  async generateSelfPeer(theConf:{ currency: string }, signalTimeInterval = 0): Promise<DBPeer|null> {
     const current = await this.server.dal.getCurrentBlockOrNull();
     const currency = theConf.currency || constants.DEFAULT_CURRENCY_NAME;
     const peers = await this.dal.findPeers(this.selfPubkey);
@@ -194,11 +194,13 @@ export class PeeringService {
       version: constants.DOCUMENTS_VERSION,
       currency: currency,
       block: '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855',
-      endpoints: []
+      endpoints: <string[]>[]
     };
     const currentSelfPeer = peers[0]
     if (peers.length != 0 && currentSelfPeer) {
-      p1 = _(currentSelfPeer).extend({version: constants.DOCUMENTS_VERSION, currency: currency});
+      p1 = currentSelfPeer
+      p1.version = constants.DOCUMENTS_VERSION
+      p1.currency = currency
     }
     const localEndpoints = await this.server.getEndpoints()
     const otherPotentialEndpoints = this.getOtherEndpoints(p1.endpoints, localEndpoints)
@@ -239,7 +241,7 @@ export class PeeringService {
         currency: currency,
         pubkey: this.selfPubkey,
         block: targetBlockstamp ? targetBlockstamp : constants.PEER.SPECIAL_BLOCK,
-        endpoints: _.uniq(endpointsToDeclare)
+        endpoints: Underscore.uniq(endpointsToDeclare)
       };
       const raw2 = dos2unix(PeerDTO.fromJSONObject(p2).getRaw());
       const bmaAccess = PeerDTO.fromJSONObject(p2).getURL()
diff --git a/index.ts b/index.ts
index f944fabbfe04f12d07a82784201c4ec70cfc3189..a19e14c527b0860666f606b871654c7140538983 100644
--- a/index.ts
+++ b/index.ts
@@ -25,9 +25,9 @@ import {ProxiesConf} from './app/lib/proxy';
 import {RouterDependency} from "./app/modules/router"
 import {OtherConstants} from "./app/lib/other_constants"
 import {Directory} from "./app/lib/system/directory"
+import {Underscore} from "./app/lib/common-libs/underscore"
 
 const path = require('path');
-const _ = require('underscore');
 const constants = require('./app/lib/constants');
 const logger = require('./app/lib/logger').NewLogger('duniter');
 
@@ -351,7 +351,7 @@ class Stack {
 
         // Register the configuration hook for saving phase (overrides the saved data)
         server.dal.saveConfHook = async (conf:ConfDTO) => {
-          const clonedConf = _.clone(conf);
+          const clonedConf = Underscore.clone(conf)
           for (const callback of this.configBeforeSaveCallbacks) {
             await callback(clonedConf, program, logger, server.dal.confDAL);
           }
diff --git a/server.ts b/server.ts
index 9f371e3beda80d5993e5b84ff3190b5885a3e6ab..84f7cb4a95f3ae3722f9a43f30a465949d48978a 100644
--- a/server.ts
+++ b/server.ts
@@ -36,9 +36,9 @@ import {OtherConstants} from "./app/lib/other_constants"
 import {WS2PCluster} from "./app/modules/ws2p/lib/WS2PCluster"
 import {DBBlock} from "./app/lib/db/DBBlock"
 import {ProxiesConf} from './app/lib/proxy';
-import {DBPeer} from "./app/lib/dal/sqliteDAL/PeerDAL"
 import {Directory, FileSystem} from "./app/lib/system/directory"
 import {DataErrors} from "./app/lib/common-libs/errors"
+import {DBPeer} from "./app/lib/db/DBPeer"
 
 export interface HookableServer {
   generatorGetJoinData: (...args:any[]) => Promise<any>
diff --git a/test/dal/dal.js b/test/dal/basic-dal-tests.ts
similarity index 76%
rename from test/dal/dal.js
rename to test/dal/basic-dal-tests.ts
index 302879a1309fdc3eed06996eb873aea056d84aa7..3a8143c540c00de0bdfd77b5a06df71226d512e2 100644
--- a/test/dal/dal.js
+++ b/test/dal/basic-dal-tests.ts
@@ -11,15 +11,15 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
-var co = require('co');
-var _ = require('underscore');
+import {FileDAL} from "../../app/lib/dal/fileDAL"
+import {PeerDTO} from "../../app/lib/dto/PeerDTO"
+import {Directory} from "../../app/lib/system/directory"
+import {DBBlock} from "../../app/lib/db/DBBlock"
+import {Underscore} from "../../app/lib/common-libs/underscore"
+
 var should = require('should');
 var assert = require('assert');
-var dal = require('../../app/lib/dal/fileDAL').FileDAL
-var dir = require('../../app/lib/system/directory').Directory
 var constants = require('../../app/lib/constants');
-var PeerDTO   = require('../../app/lib/dto/PeerDTO').PeerDTO
 
 var mocks = {
   peer1: {
@@ -102,22 +102,22 @@ var mocks = {
   }
 };
 
-var fileDAL = null;
+let fileDAL:FileDAL
 
 describe("DAL", function(){
 
-  before(() => co(function *() {
-    let params = yield dir.getHomeParams(true, 'db0');
-    fileDAL = new dal(params);
-    yield fileDAL.init();
-    return fileDAL.saveConf({ currency: "meta_brouzouf" });
-  }));
+  before(async () => {
+    let params = await Directory.getHomeParams(true, 'db0');
+    fileDAL = new FileDAL(params);
+    await fileDAL.init({} as any);
+    return fileDAL.saveConf({ currency: "meta_brouzouf" } as any);
+  })
 
-  it('should have DB version 21', () => co(function *() {
-    let version = yield fileDAL.getDBVersion();
+  it('should have DB version 21', async () => {
+    let version = await fileDAL.getDBVersion();
     should.exist(version);
     version.should.equal(constants.CURRENT_DB_VERSION);
-  }));
+  })
 
   it('should have no peer in a first time', function(){
     return fileDAL.listAllPeers().then(function(peers){
@@ -126,7 +126,7 @@ describe("DAL", function(){
   });
 
   it('should have 1 peer if 1 is created', function(){
-    return fileDAL.savePeer(PeerDTO.fromJSONObject(mocks.peer1))
+    return fileDAL.savePeer(PeerDTO.fromJSONObject(mocks.peer1).toDBPeer())
       .then(() => fileDAL.listAllPeers())
       .then(function(peers){
         peers.should.have.length(1);
@@ -150,39 +150,37 @@ describe("DAL", function(){
     });
   });
 
-  it('should be able to save a Block', function(){
-    return co(function *() {
-      yield fileDAL.saveBlock(_.extend({ fork: false }, mocks.block0));
-      let block = yield fileDAL.getFullBlockOf(0);
-      block.should.have.property('hash').equal(mocks.block0.hash);
-      block.should.have.property('signature').equal(mocks.block0.signature);
-      block.should.have.property('version').equal(mocks.block0.version);
-      block.should.have.property('currency').equal(mocks.block0.currency);
-      block.should.have.property('issuer').equal(mocks.block0.issuer);
-      block.should.have.property('parameters').equal(mocks.block0.parameters);
-      block.should.have.property('previousHash').equal(mocks.block0.previousHash);
-      block.should.have.property('previousIssuer').equal(mocks.block0.previousIssuer);
-      block.should.have.property('membersCount').equal(mocks.block0.membersCount);
-      block.should.have.property('monetaryMass').equal(mocks.block0.monetaryMass);
-      block.should.have.property('UDTime').equal(mocks.block0.UDTime);
-      block.should.have.property('medianTime').equal(mocks.block0.medianTime);
-      block.should.have.property('dividend').equal(mocks.block0.dividend);
-      block.should.have.property('unitbase').equal(mocks.block0.unitbase);
-      block.should.have.property('time').equal(mocks.block0.time);
-      block.should.have.property('powMin').equal(mocks.block0.powMin);
-      block.should.have.property('number').equal(mocks.block0.number);
-      block.should.have.property('nonce').equal(mocks.block0.nonce);
+  it('should be able to save a Block', async () => {
+    await fileDAL.saveBlock(Underscore.extend({ fork: false } as any, mocks.block0));
+    let block = (await fileDAL.getFullBlockOf(0)) as DBBlock
+    block.should.have.property('hash').equal(mocks.block0.hash);
+    block.should.have.property('signature').equal(mocks.block0.signature);
+    block.should.have.property('version').equal(mocks.block0.version);
+    block.should.have.property('currency').equal(mocks.block0.currency);
+    block.should.have.property('issuer').equal(mocks.block0.issuer);
+    block.should.have.property('parameters').equal(mocks.block0.parameters);
+    block.should.have.property('previousHash').equal(mocks.block0.previousHash);
+    block.should.have.property('previousIssuer').equal(mocks.block0.previousIssuer);
+    block.should.have.property('membersCount').equal(mocks.block0.membersCount);
+    block.should.have.property('monetaryMass').equal(mocks.block0.monetaryMass);
+    block.should.have.property('UDTime').equal(mocks.block0.UDTime);
+    block.should.have.property('medianTime').equal(mocks.block0.medianTime);
+    block.should.have.property('dividend').equal(mocks.block0.dividend);
+    block.should.have.property('unitbase').equal(mocks.block0.unitbase);
+    block.should.have.property('time').equal(mocks.block0.time);
+    block.should.have.property('powMin').equal(mocks.block0.powMin);
+    block.should.have.property('number').equal(mocks.block0.number);
+    block.should.have.property('nonce').equal(mocks.block0.nonce);
 
-      //assert.deepEqual(block, mocks.block0);
-      assert.deepEqual(block.identities, mocks.block0.identities);
-      assert.deepEqual(block.certifications, mocks.block0.certifications);
-      assert.deepEqual(block.actives, mocks.block0.actives);
-      assert.deepEqual(block.revoked, mocks.block0.revoked);
-      assert.deepEqual(block.excluded, mocks.block0.excluded);
-      assert.deepEqual(block.leavers, mocks.block0.leavers);
-      assert.deepEqual(block.actives, mocks.block0.actives);
-      assert.deepEqual(block.joiners, mocks.block0.joiners);
-      assert.deepEqual(block.transactions, mocks.block0.transactions);
-    });
+    //assert.deepEqual(block, mocks.block0);
+    assert.deepEqual(block.identities, mocks.block0.identities);
+    assert.deepEqual(block.certifications, mocks.block0.certifications);
+    assert.deepEqual(block.actives, mocks.block0.actives);
+    assert.deepEqual(block.revoked, mocks.block0.revoked);
+    assert.deepEqual(block.excluded, mocks.block0.excluded);
+    assert.deepEqual(block.leavers, mocks.block0.leavers);
+    assert.deepEqual(block.actives, mocks.block0.actives);
+    assert.deepEqual(block.joiners, mocks.block0.joiners);
+    assert.deepEqual(block.transactions, mocks.block0.transactions);
   });
 });
diff --git a/test/fast/block_global.disabled b/test/fast/block_global.disabled
deleted file mode 100644
index 7611166fd585ea3d7d3ea15ffea5d38b2937f23d..0000000000000000000000000000000000000000
--- a/test/fast/block_global.disabled
+++ /dev/null
@@ -1,678 +0,0 @@
-"use strict";
-const co            = require('co');
-const Q             = require('q');
-const _             = require('underscore');
-const async         = require('async');
-const should        = require('should');
-const rules         = require('../../app/lib/rules');
-const wotb          = require('../../app/lib/wot');
-const parsers       = require('duniter-common').parsers;
-const blocks        = require('../data/blocks');
-const parser        = parsers.parseBlock;
-const Block         = require('../../app/lib/entity/block');
-const Identity      = require('../../app/lib/entity/identity');
-
-const conf = {
-  currency: 'bb',
-  msValidity: 365.25 * 24 * 3600, // 1 year
-  sigValidity: 365.25 * 24 * 3600, // 1 year
-  sigQty: 1,
-  xpercent: 0.9,
-  powZeroMin: 1,
-  powPeriod: 18,
-  incDateMin: 10,
-  dt: 100,
-  ud0: 100,
-  c: 0.1,
-  medianTimeBlocks: 200,
-  percentRot: 2 / 3,
-  blockRot: 300,
-  dtDiffEval: 500,
-  stepMax: 1
-};
-
-function getDAL(overrides) {
-  return _.extend({
-    wotb: wotb.memoryInstance(),
-    getCurrentBlockOrNull: () => Q(null),
-    getWrittenIdtyByUID: () => Q(null),
-    getWrittenIdtyByPubkey: () => Q(null),
-    getToBeKicked: () => Q([]),
-    isLeaving: () => Q(false),
-    getPreviousLinks: () => Q(null),
-    getLastValidFrom: () => Q(null),
-    lastUDBlock: () => Q(null),
-    getBlock: () => Q(null),
-    isMember: () => Q(false),
-    getBlocksBetween: () => Q([]),
-    lastBlockOfIssuer: () => Q(null)
-  }, overrides);
-}
-
-/**
- * TODO: reimplement tests according to new convention:
- *
- *   - Name: protocol-brg<number>-<title>.js
- *   - Content: see existing tests
- */
-
-describe("Block global coherence:", function(){
-
-  it('a valid block should not have any error', validate(blocks.VALID_ROOT, getDAL(), {
-    getIssuerPersonalizedDifficulty: () => Q(1),
-    getvHEAD_1: () => Q({ version : 2 })
-  }, function (err) {
-    should.not.exist(err);
-  }));
-
-  it('a valid (next) block should not have any error', validate(blocks.VALID_NEXT, getDAL({
-    getCurrentBlockOrNull: () => Q({ number: 2, hash: '52DC8A585C5D89571C511BB83F7E7D3382F0041452064B1272E65F0B42B82D57', issuer: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', membersCount: 3, time: 1411776000, medianTime: 1411776000 }),
-    getBlock: (number) => {
-      if (number == 1) {
-        return Q({ time: 1411776000, powMin: 1 });
-      }
-      if (number == 2) {
-        return Q({ number: 3, powMin: 1 });
-      }
-      return Q(null);
-    },
-    isMember: () => Q(true),
-    getBlocksBetween: () => Q([{time:1411776000},{time:1411776000},{time:1411776000}])
-  }), {
-    getIssuerPersonalizedDifficulty: () => Q(2),
-    getvHEAD_1: () => Q({ version : 2 })
-  }, function (err) {
-    should.not.exist(err);
-  }));
-
-  it('a block with wrong PreviousHash should fail', test(rules.GLOBAL.checkPreviousHash, blocks.WRONG_PREVIOUS_HASH, {
-    getCurrentBlockOrNull: () => Q({ number: 50, hash: '4C8800825C44A22F230AFC0D140BF1930331A686899D16EBE4C58C9F34C609E8', issuer: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', membersCount: 3 })
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('PreviousHash not matching hash of current block');
-  }));
-
-  it('a block with wrong PreviousIssuer should fail', test(rules.GLOBAL.checkPreviousIssuer, blocks.WRONG_PREVIOUS_ISSUER, {
-    getCurrentBlockOrNull: () => Q({ number: 50, hash: '4C8800825C44A22F230AFC0D140BF1930331A686899D16EBE4C58C9F34C609E8', issuer: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', membersCount: 3 })
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('PreviousIssuer not matching issuer of current block');
-  }));
-
-  it('a block with wrong DifferentIssuersCount following V2 should fail', test(rules.GLOBAL.checkDifferentIssuersCount, blocks.WRONG_DIFFERENT_ISSUERS_COUNT_FOLLOWING_V2, {
-    getCurrentBlockOrNull: () => Q({ version: 2 }),
-    getBlocksBetween: () => Q([])
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('DifferentIssuersCount is not correct');
-  }));
-  
-  it('a block with wrong DifferentIssuersCount following V3 should fail', test(rules.GLOBAL.checkDifferentIssuersCount, blocks.WRONG_DIFFERENT_ISSUERS_COUNT_FOLLOWING_V3, {
-    getCurrentBlockOrNull: () => Q({ version: 3, issuersCount: 4 }),
-    getBlocksBetween: () => Q([
-      // 5 blocks, 4 different issuers
-      { issuer: 'A' },
-      { issuer: 'B' },
-      { issuer: 'A' },
-      { issuer: 'C' },
-      { issuer: 'D' }
-    ])
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('DifferentIssuersCount is not correct');
-  }));
-
-  it('a block with wrong IssuersFrame following V2 should fail', test(rules.GLOBAL.checkIssuersFrame, blocks.WRONG_ISSUERS_FRAME_FOLLOWING_V2, {
-    getCurrentBlockOrNull: () => Q({ version: 2 })
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('IssuersFrame is not correct');
-  }));
-
-  it('a block with wrong IssuersFrame following V3 should fail', test(rules.GLOBAL.checkIssuersFrameVar, blocks.WRONG_ISSUERS_FRAME_FOLLOWING_V3, {
-    getCurrentBlockOrNull: () => Q({ version: 3, issuersCount: 3, issuersFrame: 56, issuersFrameVar: 6 })
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('IssuersFrameVar is not correct');
-  }));
-
-  it('a block with wrong Issuer should fail', test(rules.GLOBAL.checkIssuerIsMember, blocks.WRONG_ISSUER, {
-    isMember: () => Q(false)
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Issuer is not a member');
-  }));
-
-  it('a block with joiner for root block without root number shoud fail', test(rules.GLOBAL.checkJoiners, blocks.WRONG_JOIN_ROOT_NUMBER, {
-    getCurrentBlockOrNull: () => Q(null)
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Number must be 0 for root block\'s memberships');
-  }));
-
-  it('a block with joiner for root block without root hash shoud fail', test(rules.GLOBAL.checkJoiners, blocks.WRONG_JOIN_ROOT_HASH, {
-    getCurrentBlockOrNull: () => Q(null)
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Hash must be E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 for root block\'s memberships');
-  }));
-
-  it('a block with joiner targeting unexisting block fail', test(rules.GLOBAL.checkJoiners, blocks.WRONG_JOIN_BLOCK_TARGET, {
-    getCurrentBlockOrNull: () => Q(null)
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Membership based on an unexisting block');
-  }));
-
-  it('a block with joiner membership number lower or equal than previous should fail', test(rules.GLOBAL.checkJoiners, blocks.WRONG_JOIN_NUMBER_TOO_LOW, {
-    getCurrentBlockOrNull: () => Q(null),
-    getWrittenIdtyByPubkey: () => Q({ currentMSN: 2 }),
-    getBlockByNumberAndHash: () => Q({ number: 3, powMin: 1 })
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Membership\'s number must be greater than last membership of the pubkey');
-  }));
-
-  it('a block with joiner membership of a yet member should fail', test(rules.GLOBAL.checkJoiners, blocks.WRONG_JOIN_ALREADY_MEMBER, {
-    isMember: () => Q(true),
-    getWrittenIdtyByPubkey: () => Q({ currentMSN: 2, member: true }),
-    getBlockByNumberAndHash: () => Q({ number: 3, powMin: 1 }),
-    getCurrentBlockOrNull: () => Q({ number: 50, hash: '4C8800825C44A22F230AFC0D140BF1930331A686899D16EBE4C58C9F34C609E8', issuer: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', membersCount: 3 })
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Cannot be in joiners if already a member');
-  }));
-
-  it('a block with at least one revoked joiner should fail', test(rules.GLOBAL.checkJoinersAreNotRevoked, blocks.REVOKED_JOINER, {
-    getWrittenIdtyByPubkey: () => Q({ currentMSN: 2, revoked: true })
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Revoked pubkeys cannot join');
-  }));
-
-  it('a block with at least one joiner without enough certifications should fail', test(rules.GLOBAL.checkJoinersHaveEnoughCertifications, blocks.NOT_ENOUGH_CERTIFICATIONS_JOINER, {
-    getValidLinksTo: () => Q([])
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Joiner/Active does not gathers enough certifications');
-  }));
-
-  it('a block with at least one joiner without enough certifications should succeed', test(rules.GLOBAL.checkJoinersHaveEnoughCertifications, blocks.NOT_ENOUGH_CERTIFICATIONS_JOINER_BLOCK_0, {
-  }, function (err) {
-    should.not.exist(err);
-  }));
-
-  it('a block with expired membership should fail', test(rules.GLOBAL.checkJoiners, blocks.EXPIRED_MEMBERSHIP, {
-    getWrittenIdtyByPubkey: () => Q({ currentMSN: 2 }),
-    getBlockByNumberAndHash: () => Q({ medianTime: 1411775000, powMin: 1 }),
-    getCurrentBlockOrNull: () => Q({ time: 1443333600, medianTime: 1443333600 })
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Membership has expired');
-  }));
-
-  it('a block with at least one joiner outdistanced from WoT should fail', test(rules.GLOBAL.checkJoinersAreNotOudistanced, blocks.OUTDISTANCED_JOINER, {
-    wotb: {
-      addNode: () => 1,
-      setEnabled: () => 1,
-      addLink: () => 1,
-      removeLink: () => 1,
-      removeNode: () => 1,
-      isOutdistanced: () => true
-    },
-    getCurrentBlockOrNull: () => Q({ number: 2, hash: '52DC8A585C5D89571C511BB83F7E7D3382F0041452064B1272E65F0B42B82D57', issuer: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', membersCount: 3, time: 1411776000, medianTime: 1411776000 }),
-    getWrittenIdtyByPubkey: () => Q({ wotb_id: 0 })
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Joiner/Active is outdistanced from WoT');
-  }));
-
-  it('a block with active targeting unexisting block fail', test(rules.GLOBAL.checkActives, blocks.WRONG_ACTIVE_BLOCK_TARGET, {
-    getCurrentBlockOrNull: () => Q(null)
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Membership based on an unexisting block');
-  }));
-
-  it('a block with certification of unknown pubkey should fail', test(rules.GLOBAL.checkCertificationsAreValid, blocks.WRONGLY_SIGNED_CERTIFICATION, {
-    getCurrentBlockOrNull: () => Q(null),
-    getBlock: () => Q({}),
-    getBlockByNumberAndHash: () => Q({})
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Wrong signature for certification');
-  }));
-
-  it('a block with certification to non-zero block for root block should fail', test(rules.GLOBAL.checkCertificationsAreValid, blocks.CERT_BASED_ON_NON_ZERO_FOR_ROOT, {
-    getCurrentBlockOrNull: () => Q(null)
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Number must be 0 for root block\'s certifications');
-  }));
-
-  it('a block with certification to unknown block should fail', test(rules.GLOBAL.checkCertificationsAreValid, blocks.CERT_BASED_ON_NON_EXISTING_BLOCK, {
-    getCurrentBlockOrNull: () => Q(null)
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Certification based on an unexisting block');
-  }));
-
-  it('a block with expired certifications should fail', test(rules.GLOBAL.checkCertificationsAreValid, blocks.EXPIRED_CERTIFICATIONS, {
-    getCurrentBlockOrNull: () => Q({ time: 1443333600, medianTime: 1443333600 }),
-    getBlock: () => Q({ medianTime: 1411775000, powMin: 1 })
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Certification has expired');
-  }));
-
-  it('a block with certification from non-member pubkey should fail', test(rules.GLOBAL.checkCertificationsAreMadeByMembers, blocks.UNKNOWN_CERTIFIER, {
-    getCurrentBlockOrNull: () => Q(null)
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Certification from non-member');
-  }));
-
-  it('a block with certification to non-member pubkey should fail', test(rules.GLOBAL.checkCertificationsAreMadeToMembers, blocks.UNKNOWN_CERTIFIED, {
-    isMember: () => Q(false)
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Certification to non-member');
-  }));
-
-  it('a block with already used UserID should fail', test(rules.GLOBAL.checkIdentityUnicity, blocks.EXISTING_UID, {
-    getWrittenIdtyByUID: () => Q({})
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Identity already used');
-  }));
-
-  it('a block with already used pubkey should fail', test(rules.GLOBAL.checkPubkeyUnicity, blocks.EXISTING_PUBKEY, {
-    getWrittenIdtyByPubkey: () => Q({})
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Pubkey already used');
-  }));
-
-  it('a block with too early certification replay should fail', test(rules.GLOBAL.checkCertificationsDelayIsRespected, blocks.TOO_EARLY_CERTIFICATION_REPLAY, {
-    getPreviousLinks: (from, to) => {
-      if (from == 'G2CBgZBPLe6FSFUgpx2Jf1Aqsgta6iib3vmDRA1yLiqU'
-        && to == 'CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC') {
-        // Exactly 1 second remaining
-        return Q({ timestamp: '1380218401' });
-      }
-      return Q(null);
-    }
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('A similar certification is already active');
-  }));
-
-  it('a block with kicked members not written under Excluded field should fail', test(rules.GLOBAL.checkKickedMembersAreExcluded, blocks.KICKED_NOT_EXCLUDED, {
-    getToBeKicked: () => Q([{}])
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('All kicked members must be present under Excluded members');
-  }));
-
-  it('a block with kicked members well written under Excluded field should succeed', test(rules.GLOBAL.checkKickedMembersAreExcluded, blocks.KICKED_EXCLUDED, {
-    getToBeKicked: () => Q([
-      { pubkey: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd' },
-      { pubkey: 'G2CBgZBPLe6FSFUgpx2Jf1Aqsgta6iib3vmDRA1yLiqU' }
-    ])
-  }, function (err) {
-    should.not.exist(err);
-  }));
-  it('a block with kicked members not well written under Excluded field should fail', test(rules.GLOBAL.checkKickedMembersAreExcluded, blocks.KICKED_EXCLUDED, {
-    getToBeKicked: () => Q([
-      { pubkey: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd' },
-      { pubkey: 'G2CBgZBPLe6FSFUgpx2Jf1Aqsgta6iib3vmDRA1yLiqU' },
-      { pubkey: 'D2CBgZBPLe6FSFUgpx2Jf1Aqsgta6iib3vmDRA1yLiqU' }
-    ])
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('All kicked members must be present under Excluded members');
-  }));
-
-  it('a block with wrong members count should fail', test(rules.GLOBAL.checkMembersCountIsGood, blocks.WRONG_MEMBERS_COUNT, {
-    getCurrentBlockOrNull: () => Q(null)
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Wrong members count');
-  }));
-
-  it('a block not starting with a leading zero should fail', test(rules.GLOBAL.checkProofOfWork, blocks.NO_LEADING_ZERO, {
-    bcContext: {
-      getIssuerPersonalizedDifficulty: () => Q(8)
-    }
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Wrong proof-of-work level: given 0 zeros and \'F\', required was 0 zeros and an hexa char between [0-7]');
-  }));
-
-  it('a block requiring 2 leading zeros but providing less should fail', test(rules.GLOBAL.checkProofOfWork, blocks.REQUIRES_7_LEADING_ZEROS, {
-    bcContext: {
-      getIssuerPersonalizedDifficulty: () => Q(12)
-    }
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Wrong proof-of-work level: given 0 zeros and \'B\', required was 0 zeros and an hexa char between [0-3]');
-  }));
-
-  it('a block requiring 1 leading zeros but providing less should fail', test(rules.GLOBAL.checkProofOfWork, blocks.REQUIRES_6_LEADING_ZEROS, {
-    bcContext: {
-      getIssuerPersonalizedDifficulty: () => Q(8)
-    }
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Wrong proof-of-work level: given 0 zeros and \'8\', required was 0 zeros and an hexa char between [0-7]');
-  }));
-
-  it('a block requiring 1 leading zeros as first block of newcomer should succeed', test(rules.GLOBAL.checkProofOfWork, blocks.FIRST_BLOCK_OF_NEWCOMER, {
-    bcContext: {
-      getIssuerPersonalizedDifficulty: () => Q(1)
-    }
-  }, function (err) {
-    should.not.exist(err);
-  }));
-
-  it('a block requiring 40 leading zeros as second block of newcomer should fail', test(rules.GLOBAL.checkProofOfWork, blocks.SECOND_BLOCK_OF_NEWCOMER, {
-    bcContext: {
-      getIssuerPersonalizedDifficulty: () => Q(160)
-    }
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Wrong proof-of-work level: given 0 zeros and \'F\', required was 10 zeros and an hexa char between [0-9A-F]');
-  }));
-
-  it('a root block should not fail for time reason', test(rules.GLOBAL.checkTimes, blocks.WRONG_ROOT_DATES, {
-    getCurrentBlockOrNull: () => Q(null)
-  }, function (err) {
-    should.not.exist(err);
-  }));
-
-  it('a block with wrong median for an odd number of blocks should fail', test(rules.GLOBAL.checkTimes, blocks.WRONG_MEDIAN_TIME_ODD, {
-    getBlocksBetween: () => Q([{time: 1},{time: 12}])
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Wrong MedianTime');
-  }));
-
-  it('a block with wrong median for an even number of blocks should fail', test(rules.GLOBAL.checkTimes, blocks.WRONG_MEDIAN_TIME_EVEN, {
-    getBlocksBetween: () => Q([{time: 1},{time: 12}])
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Wrong MedianTime');
-  }));
-
-  it('a block whose median time is correct (odd) should pass', test(rules.GLOBAL.checkTimes, blocks.GOOD_MEDIAN_TIME_ODD, {
-    getBlocksBetween: () => {
-      let times = [];
-      for (let i = 0; i < 103; i++)
-        times.push({ time: 161 });
-      return Q(times);
-    }
-  }, function (err) {
-    should.not.exist(err);
-  }));
-
-  it('a block whose median time is correct (even) should pass', test(rules.GLOBAL.checkTimes, blocks.GOOD_MEDIAN_TIME_EVEN, {
-    getBlocksBetween: () => {
-      let times = [];
-      for (let i = 0; i < 104; i++)
-        times.push({ time: 162 });
-      return Q(times);
-    }
-  }, function (err) {
-    should.not.exist(err);
-  }));
-
-  it('a root block with Universal Dividend should fail', test(rules.GLOBAL.checkUD, blocks.ROOT_BLOCK_WITH_UD, {
-    lastUDBlock: () => Q(null),
-    getBlock: () => Q(null),
-    getCurrentBlockOrNull: () => Q(null)
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Root block cannot have UniversalDividend field');
-  }));
-
-  it('first block with Universal Dividend should not happen before root time + dt', test(rules.GLOBAL.checkUD, blocks.FIRST_UD_BLOCK_WITH_UD_THAT_SHOULDNT, {
-    lastUDBlock: () => Q(null),
-    getBlock: () => Q({ hash: 'E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855', medianTime: 1411773000, powMin: 1 }),
-    getCurrentBlockOrNull: () => Q({ number: 19, time: 1411773000, medianTime: 1411773000 })
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('This block cannot have UniversalDividend');
-  }));
-
-  it('first block with Universal Dividend should happen on root time + dt', test(rules.GLOBAL.checkUD, blocks.FIRST_UD_BLOCK_WITH_UD_THAT_SHOULD, {
-    lastUDBlock: () => Q(null),
-    getBlock: () => Q({ hash: 'E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855', medianTime: 1411773000, powMin: 1 }),
-    getCurrentBlockOrNull: () => Q({ number: 19, time: 1411773000, medianTime: 1411773000 })
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Block must have a UniversalDividend field');
-  }));
-
-  it('a block without Universal Dividend whereas it have to have one should fail', test(rules.GLOBAL.checkUD, blocks.UD_BLOCK_WIHTOUT_UD, {
-    lastUDBlock: () => Q(null),
-    getBlock: () => Q({ hash: 'E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855', medianTime: 1411773000, powMin: 1 }),
-    getCurrentBlockOrNull: () => Q({ number: 19, time: 1411773000, medianTime: 1411773000 })
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Block must have a UniversalDividend field');
-  }));
-
-  it('a block with wrong (version 2) Universal Dividend value should fail', test(rules.GLOBAL.checkUD, blocks.BLOCK_WITH_WRONG_UD, {
-    lastUDBlock: () => Q({ UDTime: 1411776900, medianTime: 1411776900, monetaryMass: 3620 * 10000, dividend: 110, unitbase: 4 }),
-    getBlock: () => Q(),
-    getCurrentBlockOrNull: () => Q({ time: 1411777000, medianTime: 1411777000 })
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('UniversalDividend must be equal to 121');
-  }));
-
-  it('a block with wrong (version 3) Universal Dividend value should fail', test(rules.GLOBAL.checkUD, blocks.BLOCK_WITH_WRONG_UD_V3, {
-    lastUDBlock: () => Q({ UDTime: 1411776900, medianTime: 1411776900, dividend: 110, unitbase: 4 }),
-    getBlock: () => Q(),
-    getCurrentBlockOrNull: () => Q({ time: 1411777000, medianTime: 1411777000 })
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('UniversalDividend must be equal to 121');
-  }));
-
-  it('a block with wrong UnitBase value should fail', test(rules.GLOBAL.checkUD, blocks.BLOCK_WITH_WRONG_UNIT_BASE, {
-    lastUDBlock: () => Q({ UDTime: 1411777000, medianTime: 1411777000, monetaryMass: 12345678900, dividend: 100, unitbase: 2 }),
-    getBlock: () => Q(),
-    getCurrentBlockOrNull: () => Q({ time: 1411777000, medianTime: 1411777000 })
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('UnitBase must be equal to 3');
-  }));
-
-  it('a block without UD with wrong UnitBase value should fail', test(rules.GLOBAL.checkUD, blocks.BLOCK_WITH_WRONG_UNIT_BASE_NO_UD, {
-    lastUDBlock: () => Q({ UDTime: 1411777000, medianTime: 1411777000, monetaryMass: 12345678900, dividend: 100, unitbase: 8 }),
-    getBlock: () => Q(),
-    getCurrentBlockOrNull: () => Q({ time: 1411777000, medianTime: 1411777000, unitbase: 5 })
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('UnitBase must be equal to previous unit base = 5');
-  }));
-
-  it('a root block with unlegitimated Universal Dividend presence should fail', test(rules.GLOBAL.checkUD, blocks.BLOCK_UNLEGITIMATE_UD, {
-    lastUDBlock: () => Q({ UDTime: 1411777000, medianTime: 1411777000, monetaryMass: 3620 * 10000, dividend: 110, unitbase: 4 }),
-    getBlock: () => Q(),
-    getCurrentBlockOrNull: () => Q({ time: 1411777000, medianTime: 1411777000 })
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('This block cannot have UniversalDividend');
-  }));
-
-  it('a root block with unlegitimated Universal Dividend presence should fail', test(rules.GLOBAL.checkUD, blocks.BLOCK_UNLEGITIMATE_UD_2, {
-    lastUDBlock: () => Q({ UDTime: 1411777000, medianTime: 1411777000, monetaryMass: 3620 * 10000, dividend: 110, unitbase: 4 }),
-    getBlock: () => Q(),
-    getCurrentBlockOrNull: () => Q({ time: 1411777000, medianTime: 1411777000 })
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('This block cannot have UniversalDividend');
-  }));
-
-
-  it('a block without transactions should pass', test(rules.GLOBAL.checkSourcesAvailability, blocks.BLOCK_WITHOUT_TRANSACTIONS, {
-    getCurrentBlockOrNull: () => Q(null)
-  }, function (err) {
-    should.not.exist(err);
-  }));
-
-  it('a block with good transactions should pass', test(rules.GLOBAL.checkSourcesAvailability, blocks.BLOCK_WITH_GOOD_TRANSACTIONS, {
-    getCurrentBlockOrNull: () => Q({ unitbase: 5 }),
-    getSource: (id, noffset) => {
-      if (id == '6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3' && noffset == 4)   return Q({ amount: 0,   base: 4 });
-      if (id == '3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435' && noffset == 10)  return Q({ amount: 0,   base: 3 });
-      if (id == 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd' && noffset == 46)                      return Q({ amount: 0,   base: 4 });
-      if (id == 'A0D9B4CDC113ECE1145C5525873821398890AE842F4B318BD076095A23E70956' && noffset == 66)  return Q({ amount: 235, base: 4 });
-      if (id == '67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B' && noffset == 176) return Q({ amount: 0,   base: 4 });
-      return Q(null);
-    }
-  }, function (err) {
-    should.not.exist(err);
-  }));
-
-  it('a block with wrong transaction sum should fail', test(rules.GLOBAL.checkSourcesAvailability, blocks.BLOCK_WITH_WRONG_TRANSACTION_SUMS, {
-    getCurrentBlockOrNull: () => Q({ unitbase: 5 }),
-    getSource: (id, noffset) => {
-      if (id == '6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3' && noffset == 4)   return Q({ amount: 0,   base: 4 });
-      if (id == '3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435' && noffset == 10)  return Q({ amount: 0,   base: 3 });
-      if (id == 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd' && noffset == 46)                      return Q({ amount: 0,   base: 4 });
-      if (id == 'A0D9B4CDC113ECE1145C5525873821398890AE842F4B318BD076095A23E70956' && noffset == 66)  return Q({ amount: 235, base: 4 });
-      if (id == '67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B' && noffset == 176) return Q({ amount: 0,   base: 4 });
-      return Q(null);
-    }
-  }, function (err) {
-    should.exist(err);
-    err.uerr.message.should.equal('Sum of inputs must equal sum of outputs');
-  }));
-
-  it('a block with wrong transaction unit bases should fail', test(rules.GLOBAL.checkSourcesAvailability, blocks.BLOCK_WITH_WRONG_TRANSACTION_SUMS, {
-    getCurrentBlockOrNull: () => Q({ unitbase: 5 }),
-    getSource: (id, noffset) => {
-      if (id == '6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3' && noffset == 4)   return Q({ amount: 0,   base: 4 });
-      if (id == '3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435' && noffset == 10)  return Q({ amount: 0,   base: 3 });
-      if (id == 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd' && noffset == 46)                      return Q({ amount: 0,   base: 4 });
-      if (id == 'A0D9B4CDC113ECE1145C5525873821398890AE842F4B318BD076095A23E70956' && noffset == 66)  return Q({ amount: 235, base: 4 });
-      if (id == '67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B' && noffset == 176) return Q({ amount: 0,   base: 4 });
-      return Q(null);
-    }
-  }, function (err) {
-    should.exist(err);
-    err.uerr.message.should.equal('Sum of inputs must equal sum of outputs');
-  }));
-
-  it('a block with whose transaction has too high unit bases should fail', test(rules.GLOBAL.checkSourcesAvailability, blocks.BLOCK_WITH_WRONG_TRANSACTION_UNIT_BASES, {
-    getCurrentBlockOrNull: () => Q({ unitbase: 2 }),
-    getSource: (id, noffset) => {
-      if (id == '6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3' && noffset == 4)   return Q({ amount: 0,   base: 4 });
-      if (id == '3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435' && noffset == 10)  return Q({ amount: 0,   base: 3 });
-      if (id == 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd' && noffset == 46)                      return Q({ amount: 0,   base: 4 });
-      if (id == 'A0D9B4CDC113ECE1145C5525873821398890AE842F4B318BD076095A23E70956' && noffset == 66)  return Q({ amount: 235, base: 4 });
-      if (id == '67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B' && noffset == 176) return Q({ amount: 0,   base: 4 });
-      return Q(null);
-    }
-  }, function (err) {
-    should.exist(err);
-    err.uerr.message.should.equal('Wrong unit base for outputs');
-  }));
-
-  it('a block with unavailable UD source should fail', test(rules.GLOBAL.checkSourcesAvailability, blocks.BLOCK_WITH_UNAVAILABLE_UD_SOURCE, {
-    getCurrentBlockOrNull: () => Q({ unitbase: 5 }),
-    getSource: (id, noffset) => {
-      if (id == '6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3' && noffset == 4)   return Q({ amount: 0,   base: 4 });
-      if (id == '3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435' && noffset == 10)  return Q({ amount: 0,   base: 3 });
-      if (id == 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd' && noffset == 46)                      return Q({ amount: 0,   base: 4 });
-      if (id == 'A0D9B4CDC113ECE1145C5525873821398890AE842F4B318BD076095A23E70956' && noffset == 66)  return Q({ amount: 235, base: 4 });
-      if (id == '67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B' && noffset == 176) return Q({ amount: 0,   base: 4 });
-      return Q(null);
-    }
-  }, function (err) {
-    should.exist(err);
-    err.should.have.property('uerr').property('message').equal('Source already consumed');
-  }));
-
-  it('a block with unavailable TX source should fail', test(rules.GLOBAL.checkSourcesAvailability, blocks.BLOCK_WITH_UNAVAILABLE_TX_SOURCE, {
-    getCurrentBlockOrNull: () => Q({ unitbase: 5 }),
-    getSource: (id, noffset) => {
-      if (id == '6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3' && noffset == 4)   return Q({ amount: 0,   base: 4 });
-      if (id == '3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435' && noffset == 10)  return Q({ amount: 0,   base: 3 });
-      if (id == 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd' && noffset == 46)                      return Q({ amount: 0,   base: 4 });
-      if (id == 'A0D9B4CDC113ECE1145C5525873821398890AE842F4B318BD076095A23E70956' && noffset == 66)  return Q({ amount: 235, base: 4 });
-      if (id == '67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B' && noffset == 176) return Q({ amount: 0,   base: 4 });
-      return Q(null);
-    }
-  }, function (err) {
-    should.exist(err);
-    err.should.have.property('uerr').property('message').equal('Source already consumed');
-  }));
-
-  it('a block with a too high unit base should fail', test(rules.GLOBAL.checkSourcesAvailability, blocks.BLOCK_TX_V3_TOO_HIGH_OUTPUT_BASE, {
-    getCurrentBlockOrNull: () => Q({ unitbase: 3 }),
-    getSource: () => Q({ base: 1, amount: 10 })
-  }, function (err) {
-    should.exist(err);
-    err.should.have.property('uerr').property('message').equal('Wrong unit base for outputs');
-  }));
-
-  it('a block with an unknown member revoked should fail', test(rules.GLOBAL.checkRevoked, blocks.BLOCK_UNKNOWN_REVOKED, {
-    getWrittenIdtyByPubkey: () => Q(null)
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('A pubkey who was never a member cannot be revoked');
-  }));
-
-  it('a block with a yet revoked identity should fail', test(rules.GLOBAL.checkRevoked, blocks.BLOCK_WITH_YET_REVOKED, {
-    getWrittenIdtyByPubkey: () => Q({ revoked: true })
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('A revoked identity cannot be revoked again');
-  }));
-
-  it('a block with a wrong revocation signature should fail', test(rules.GLOBAL.checkRevoked, blocks.BLOCK_WITH_WRONG_REVOCATION_SIG, {
-    getWrittenIdtyByPubkey: () => Q({})
-  }, function (err) {
-    should.exist(err);
-    err.message.should.equal('Revocation signature must match');
-  }));
-});
-
-function test (rule, raw, dal, callback) {
-  return function() {
-    return co(function *() {
-      let obj = parser.syncWrite(raw);
-      let block = new Block(obj);
-      if (rule == rules.GLOBAL.checkProofOfWork || rule == rules.GLOBAL.checkVersion) {
-        yield rule(block, dal.bcContext);
-      } else if (rule.length == 2) {
-        yield rule(block, dal);
-      } else {
-        yield rule(block, conf, dal);
-      }
-    })
-      .then(callback).catch(callback);
-  };
-}
-
-function validate (raw, dal, bcContext, callback) {
-  var block;
-  return function() {
-    return Q.Promise(function(resolve, reject){
-      async.waterfall([
-        function (next){
-          block = new Block(parser.syncWrite(raw));
-          rules.CHECK.ASYNC.ALL_GLOBAL(block, conf, dal, bcContext, next);
-        }
-      ], function (err) {
-        err && console.error(err.stack);
-        err ? reject(err) : resolve();
-      });
-    })
-      .then(callback).catch(callback);
-  };
-}
diff --git a/test/fast/v1.0-local-index.js b/test/fast/index/v1.0-local-index.ts
similarity index 78%
rename from test/fast/v1.0-local-index.js
rename to test/fast/index/v1.0-local-index.ts
index 04772abb104223417a4029af2def869b030eed81..acfc7bcc05dba73aca70d214528795e3c42ca9d2 100644
--- a/test/fast/v1.0-local-index.js
+++ b/test/fast/index/v1.0-local-index.ts
@@ -11,14 +11,13 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {BlockDTO} from "../../../app/lib/dto/BlockDTO"
+import {parsers} from "../../../app/lib/common-libs/parsers/index"
+import {CommonConstants} from "../../../app/lib/common-libs/constants"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
+import {IndexEntry, Indexer} from "../../../app/lib/indexer"
 
-const _       = require('underscore');
 const should  = require('should');
-const parsers = require('../../app/lib/common-libs/parsers').parsers
-const indexer = require('../../app/lib/indexer').Indexer
-const constants = require('../../app/lib/common-libs/constants').CommonConstants
-const BlockDTO = require('../../app/lib/dto/BlockDTO').BlockDTO
 
 const raw = "Version: 10\n" +
   "Type: Block\n" +
@@ -94,11 +93,18 @@ const raw = "Version: 10\n" +
 
 describe("v1.0 Local Index", function(){
 
-  let block, index;
+  let block, index:IndexEntry[]
 
   before(() => {
     block = parsers.parseBlock.syncWrite(raw);
-    index = indexer.localIndex(BlockDTO.fromJSONObject(block), { sigValidity: 100, msValidity: 40 });
+    index = Indexer.localIndex(BlockDTO.fromJSONObject(block), {
+      sigValidity: 100,
+      msValidity: 40,
+      // We don't care about these in this test
+      msPeriod: 0,
+      sigPeriod: 0,
+      sigStock: 0
+    });
   });
 
   it('should have 30 index entries', () => {
@@ -110,15 +116,15 @@ describe("v1.0 Local Index", function(){
    ********/
 
   it('should have 4 iindex entries', () => {
-    _(index).where({ index: constants.I_INDEX}).should.have.length(4);
+    Underscore.where(index, { index: CommonConstants.I_INDEX}).should.have.length(4);
   });
 
   it('should have 1 iindex CREATE entries', () => {
-    _(index).where({ index: constants.I_INDEX, op: constants.IDX_CREATE }).should.have.length(1);
+    Underscore.where(index, { index: CommonConstants.I_INDEX, op: CommonConstants.IDX_CREATE }).should.have.length(1);
   });
 
   it('should have 3 iindex UPDATE entries', () => {
-    _(index).where({ index: constants.I_INDEX, op: constants.IDX_UPDATE }).should.have.length(3);
+    Underscore.where(index, { index: CommonConstants.I_INDEX, op: CommonConstants.IDX_UPDATE }).should.have.length(3);
   });
 
   /*********
@@ -126,15 +132,15 @@ describe("v1.0 Local Index", function(){
    ********/
 
   it('should have 5 mindex entries', () => {
-    _(index).where({ index: constants.M_INDEX}).should.have.length(5);
+    Underscore.where(index, { index: CommonConstants.M_INDEX}).should.have.length(5);
   });
 
   it('should have 1 mindex CREATE entries', () => {
-    _(index).where({ index: constants.M_INDEX, op: constants.IDX_CREATE }).should.have.length(1);
+    Underscore.where(index, { index: CommonConstants.M_INDEX, op: CommonConstants.IDX_CREATE }).should.have.length(1);
   });
 
   it('should have 4 mindex UPDATE entries', () => {
-    _(index).where({ index: constants.M_INDEX, op: constants.IDX_UPDATE }).should.have.length(4);
+    Underscore.where(index, { index: CommonConstants.M_INDEX, op: CommonConstants.IDX_UPDATE }).should.have.length(4);
   });
 
   /*********
@@ -142,15 +148,15 @@ describe("v1.0 Local Index", function(){
    ********/
 
   it('should have 5 cindex entries', () => {
-    _(index).where({ index: constants.C_INDEX}).should.have.length(5);
+    Underscore.where(index, { index: CommonConstants.C_INDEX}).should.have.length(5);
   });
 
   it('should have 5 cindex CREATE entries', () => {
-    _(index).where({ index: constants.C_INDEX, op: constants.IDX_CREATE }).should.have.length(5);
+    Underscore.where(index, { index: CommonConstants.C_INDEX, op: CommonConstants.IDX_CREATE }).should.have.length(5);
   });
 
   it('should have 0 cindex UPDATE entries', () => {
-    _(index).where({ index: constants.C_INDEX, op: constants.IDX_UPDATE }).should.have.length(0);
+    Underscore.where(index, { index: CommonConstants.C_INDEX, op: CommonConstants.IDX_UPDATE }).should.have.length(0);
   });
 
   /*********
@@ -158,15 +164,15 @@ describe("v1.0 Local Index", function(){
    ********/
 
   it('should have 16 cindex entries', () => {
-    _(index).where({ index: constants.S_INDEX}).should.have.length(16);
+    Underscore.where(index, { index: CommonConstants.S_INDEX}).should.have.length(16);
   });
 
   it('should have 9 cindex CREATE entries', () => {
-    _(index).where({ index: constants.S_INDEX, op: constants.IDX_CREATE }).should.have.length(9);
+    Underscore.where(index, { index: CommonConstants.S_INDEX, op: CommonConstants.IDX_CREATE }).should.have.length(9);
   });
 
   it('should have 7 cindex UPDATE entries', () => {
-    _(index).where({ index: constants.S_INDEX, op: constants.IDX_UPDATE }).should.have.length(7);
+    Underscore.where(index, { index: CommonConstants.S_INDEX, op: CommonConstants.IDX_UPDATE }).should.have.length(7);
   });
 
 });
diff --git a/test/fast/modules/crawler/block_pulling.ts b/test/fast/modules/crawler/block_pulling.ts
index 0abac92c7567089dd57e9b17bdd75c285c260a37..fcb3a0b0a4449ae10c55b58f1ae66078dd4fdafc 100644
--- a/test/fast/modules/crawler/block_pulling.ts
+++ b/test/fast/modules/crawler/block_pulling.ts
@@ -14,9 +14,9 @@
 import {AbstractDAO} from "../../../../app/modules/crawler/lib/pulling"
 import {BlockDTO} from "../../../../app/lib/dto/BlockDTO"
 import {NewLogger} from "../../../../app/lib/logger"
+import {Underscore} from "../../../../app/lib/common-libs/underscore"
 
 const should = require('should');
-const _ = require('underscore');
 
 let commonConf = {
   switchOnHeadAdvance: 1,
@@ -240,7 +240,7 @@ class mockDao extends AbstractDAO {
     let block = bc[number] || null;
     // Quantum block implementation
     if (block && block.quantum) {
-      bc[number] = _.clone(block);
+      bc[number] = Underscore.clone(block);
       bc[number].hash = 'Q' + block.hash;
     }
     return block;
diff --git a/test/fast/protocol-local-rule-chained-tx-depth.ts b/test/fast/protocol-local-rule-chained-tx-depth.ts
index 398f9a999cb0e0080644653f5496115d3f2d2675..7ae6e642cc8b9913ccc0bce5efd36312e5ec732b 100644
--- a/test/fast/protocol-local-rule-chained-tx-depth.ts
+++ b/test/fast/protocol-local-rule-chained-tx-depth.ts
@@ -13,7 +13,6 @@
 
 import {LOCAL_RULES_HELPERS} from "../../app/lib/rules/local_rules"
 
-const _ = require('underscore')
 const assert = require('assert')
 
 describe("Protocol BR_G110 - chained tx depth", () => {
diff --git a/test/integration/collapse.js b/test/integration/blocks/community-collapse.ts
similarity index 66%
rename from test/integration/collapse.js
rename to test/integration/blocks/community-collapse.ts
index 974790da99cf8170ec0016a0bed76e93721171f5..cb376d803701ef8f6df18eeb8d83721cd73f8ab9 100644
--- a/test/integration/collapse.js
+++ b/test/integration/blocks/community-collapse.ts
@@ -11,16 +11,13 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {TestUser} from "../tools/TestUser"
+import {NewTestingServer, TestingServer} from "../tools/toolbox"
+import {BmaDependency} from "../../../app/modules/bma/index"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
 
-const co        = require('co');
-const _         = require('underscore');
-const duniter     = require('../../index');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const TestUser  = require('./tools/TestUser').TestUser
-const commit    = require('./tools/commit');
-const httpTest  = require('./tools/http');
-const shutDownEngine  = require('./tools/shutDownEngine');
+const httpTest  = require('../tools/http');
+const shutDownEngine  = require('../tools/shutDownEngine');
 const rp        = require('request-promise');
 
 const MEMORY_MODE = true;
@@ -32,18 +29,18 @@ const commonConf = {
   sigQty: 1
 };
 
-let s1, cat, tac
+let s1:TestingServer, cat:TestUser, tac:TestUser
 
 describe("Community collapse", function() {
 
   const now = Math.round(Date.now() / 1000);
 
-  before(function() {
+  before(async () => {
 
-    s1 = duniter(
-      '/bb11',
-      MEMORY_MODE,
-      _.extend({
+    s1 = NewTestingServer(
+      Underscore.extend({
+        name: 'bb11',
+        memory: MEMORY_MODE,
         port: '9340',
         pair: {
           pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
@@ -56,19 +53,17 @@ describe("Community collapse", function() {
     cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
     tac = new TestUser('tac', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
 
-    return co(function *() {
-      yield s1.initWithDAL().then(bma).then((bmapi) => bmapi.openConnections());
-      yield cat.createIdentity();
-      yield tac.createIdentity();
-      yield cat.join();
-      yield tac.join();
-      yield cat.cert(tac);
-      yield tac.cert(cat);
-      yield commit(s1)({ time: now });
-      yield commit(s1)({ time: now + 10 });
-      yield commit(s1)({ time: now + 10 });
-      yield commit(s1)({ time: now + 10 });
-    });
+    await s1.initWithDAL().then(BmaDependency.duniter.methods.bma).then((bmapi) => bmapi.openConnections());
+    await cat.createIdentity();
+    await tac.createIdentity();
+    await cat.join();
+    await tac.join();
+    await cat.cert(tac);
+    await tac.cert(cat);
+    await s1.commit({ time: now });
+    await s1.commit({ time: now + 10 });
+    await s1.commit({ time: now + 10 });
+    await s1.commit({ time: now + 10 });
   });
 
   after(() => {
diff --git a/test/integration/blocks/start-generate-blocks.ts b/test/integration/blocks/start-generate-blocks.ts
new file mode 100644
index 0000000000000000000000000000000000000000..583e9c972cbdff75012a24bc2358c5ac2aa21bc8
--- /dev/null
+++ b/test/integration/blocks/start-generate-blocks.ts
@@ -0,0 +1,143 @@
+// Source file from duniter: Crypto-currency software to manage libre currency such as Äž1
+// Copyright (C) 2018  Cedric Moreau <cem.moreau@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+
+import {PeerDTO} from "../../../app/lib/dto/PeerDTO"
+import {BmaDependency} from "../../../app/modules/bma/index"
+import {CrawlerDependency} from "../../../app/modules/crawler/index"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
+import {NewTestingServer, serverWaitBlock, TestingServer} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
+import {RouterDependency} from "../../../app/modules/router"
+import {ProverDependency} from "../../../app/modules/prover/index"
+
+const rp        = require('request-promise');
+const httpTest  = require('../tools/http');
+const until     = require('../tools/until');
+const sync      = require('../tools/sync');
+const shutDownEngine  = require('../tools/shutDownEngine');
+
+const expectJSON     = httpTest.expectJSON;
+
+const MEMORY_MODE = true;
+const commonConf = {
+  bmaWithCrawler: true,
+  ipv4: '127.0.0.1',
+  remoteipv4: '127.0.0.1',
+  currency: 'bb',
+  httpLogs: true,
+  forksize: 0,
+  sigQty: 1
+};
+
+let s1:TestingServer, s2:TestingServer, cat:TestUser, toc:TestUser, tic:TestUser, tuc:TestUser
+
+let nodeS1;
+let nodeS2;
+
+describe("Generation", function() {
+
+  before(async () => {
+
+    s1 = NewTestingServer(
+      Underscore.extend({
+        name: 'bb7',
+        memory: MEMORY_MODE,
+        port: '7790',
+        pair: {
+          pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
+          sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
+        },
+        powDelay: 1
+      }, commonConf));
+
+    s2 = NewTestingServer(
+      Underscore.extend({
+        name: 'bb7_2',
+        memory: MEMORY_MODE,
+        port: '7791',
+        pair: {
+          pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo',
+          sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'
+        },
+        powDelay: 1
+      }, commonConf));
+
+    cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
+    toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
+    tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
+    tuc = new TestUser('tuc', { pub: '3conGDUXdrTGbQPMQQhEC4Ubu1MCAnFrAYvUaewbUhtk', sec: '5ks7qQ8Fpkin7ycXpxQSxxjVhs8VTzpM3vEBMqM7NfC1ZiFJ93uQryDcoM93Mj77T6hDAABdeHZJDFnkDb35bgiU'}, { server: s1 });
+
+    let servers = [s1, s2];
+    for (const server of servers) {
+      server._server.addEndpointsDefinitions(() => BmaDependency.duniter.methods.getMainEndpoint(server.conf))
+      await server.initWithDAL();
+      server.bma = await BmaDependency.duniter.methods.bma(server._server);
+      await server.bma.openConnections();
+      RouterDependency.duniter.methods.routeToNetwork(server._server);
+      await server.PeeringService.generateSelfPeer(server.conf);
+      const prover = ProverDependency.duniter.methods.prover(server._server)
+      server.startBlockComputation = () => prover.startService();
+      server.stopBlockComputation = () => prover.stopService();
+    }
+    nodeS1 = CrawlerDependency.duniter.methods.contacter('127.0.0.1', s1.conf.port);
+    nodeS2 = CrawlerDependency.duniter.methods.contacter('127.0.0.1', s2.conf.port);
+    // Server 1
+    await cat.createIdentity();
+    await toc.createIdentity();
+    await toc.cert(cat);
+    await cat.cert(toc);
+    await cat.join();
+    await toc.join();
+    await s1.commit();
+    // Server 2 syncs block 0
+    await sync(0, 0, s1, s2);
+    // Let each node know each other
+    let peer1 = await nodeS1.getPeer();
+    await nodeS2.postPeer(PeerDTO.fromJSONObject(peer1).getRawSigned());
+    let peer2 = await nodeS2.getPeer();
+    await nodeS1.postPeer(PeerDTO.fromJSONObject(peer2).getRawSigned());
+    s1.startBlockComputation();
+    await until(s2, 'block', 1);
+    s2.startBlockComputation();
+    s1.conf.powDelay = 2000;
+    s2.conf.powDelay = 2000;
+    await Promise.all([
+      serverWaitBlock(s1._server, 3),
+      serverWaitBlock(s2._server, 3)
+    ])
+    s1.stopBlockComputation();
+    s2.stopBlockComputation();
+  });
+
+  after(() => {
+    return Promise.all([
+      shutDownEngine(s1),
+      shutDownEngine(s2)
+    ])
+  })
+
+  describe("Server 1 /blockchain", function() {
+
+    it('/current should exist', function() {
+      return expectJSON(rp('http://127.0.0.1:7790/blockchain/current', { json: true }), {
+        number: 3
+      });
+    });
+
+    it('/current should exist on other node too', function() {
+      return expectJSON(rp('http://127.0.0.1:7791/blockchain/current', { json: true }), {
+        number: 3
+      });
+    });
+  });
+});
diff --git a/test/integration/branches2.ts b/test/integration/branches/branches2.ts
similarity index 90%
rename from test/integration/branches2.ts
rename to test/integration/branches/branches2.ts
index 5ca0a684cc602bf7a790571614fc59d52673881f..4e12085b10c267e9a62caa6c037c32097102874c 100644
--- a/test/integration/branches2.ts
+++ b/test/integration/branches/branches2.ts
@@ -11,22 +11,23 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-import {OtherConstants} from "../../app/lib/other_constants"
-import {NewLogger} from "../../app/lib/logger"
-import {BmaDependency} from "../../app/modules/bma/index"
-import {CrawlerDependency} from "../../app/modules/crawler/index"
-import {waitForkResolution, waitToHaveBlock} from "./tools/toolbox"
-import {TestUser} from "./tools/TestUser";
+
+import {BmaDependency} from "../../../app/modules/bma/index"
+import {OtherConstants} from "../../../app/lib/other_constants"
+import {NewLogger} from "../../../app/lib/logger"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
+import {waitForkResolution, waitToHaveBlock} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
+import {CrawlerDependency} from "../../../app/modules/crawler/index"
 
 const co        = require('co');
-const _         = require('underscore');
-const duniter     = require('../../index');
+const duniter     = require('../../../index');
 const bma       = BmaDependency.duniter.methods.bma;
 const rp        = require('request-promise');
-const httpTest  = require('./tools/http');
-const commit    = require('./tools/commit');
-const sync      = require('./tools/sync');
-const shutDownEngine  = require('./tools/shutDownEngine');
+const httpTest  = require('../tools/http');
+const commit    = require('../tools/commit');
+const sync      = require('../tools/sync');
+const shutDownEngine  = require('../tools/shutDownEngine');
 
 const expectJSON     = httpTest.expectJSON;
 const expectHttpCode = httpTest.expectHttpCode;
@@ -63,7 +64,7 @@ describe("SelfFork", function() {
     s1 = duniter(
       '/bb4',
       MEMORY_MODE,
-      _.extend({
+      Underscore.extend({
         port: '7781',
         pair: {
           pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
@@ -74,7 +75,7 @@ describe("SelfFork", function() {
     s2 = duniter(
       '/bb5',
       MEMORY_MODE,
-      _.extend({
+      Underscore.extend({
         port: '7782',
         pair: {
           pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo',
diff --git a/test/integration/branches_pending_data.js b/test/integration/branches/branches_pending_data.ts
similarity index 67%
rename from test/integration/branches_pending_data.js
rename to test/integration/branches/branches_pending_data.ts
index e4fe8f9c3d16065f1d83a04c2a3469dcf43ddcef..1b8930d8e004194d3e74697f0d10a70ce5998a0e 100644
--- a/test/integration/branches_pending_data.js
+++ b/test/integration/branches/branches_pending_data.ts
@@ -11,17 +11,14 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {Underscore} from "../../../app/lib/common-libs/underscore"
+import {NewTestingServer, TestingServer} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
+import {BmaDependency} from "../../../app/modules/bma/index"
 
-const co = require('co');
-const _         = require('underscore');
-const duniter   = require('../../index');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const TestUser  = require('./tools/TestUser').TestUser
 const rp        = require('request-promise');
-const httpTest  = require('./tools/http');
-const commit    = require('./tools/commit');
-const shutDownEngine  = require('./tools/shutDownEngine');
+const httpTest  = require('../tools/http');
+const shutDownEngine  = require('../tools/shutDownEngine');
 
 const expectJSON     = httpTest.expectJSON;
 const expectAnswer   = httpTest.expectAnswer;
@@ -35,50 +32,45 @@ const commonConf = {
   sigQty: 1
 };
 
-let s1, cat, toc, tic, tuc
+let s1:TestingServer, cat:TestUser, toc:TestUser, tic:TestUser, tuc:TestUser
 
 describe("Pending data", function() {
 
-  before(function() {
+  before(async () => {
 
-    s1 = duniter(
-      '/bb6',
-      MEMORY_MODE,
-      _.extend({
-        port: '7783',
-        pair: {
-          pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
-          sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
-        }
-      }, commonConf));
+    s1 = NewTestingServer(Underscore.extend({
+      memory: MEMORY_MODE,
+      name: 'bb6',
+      port: '7783',
+      pair: {
+        pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
+        sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
+      }
+    }, commonConf));
 
     cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
     toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
     tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
     tuc = new TestUser('tuc', { pub: '3conGDUXdrTGbQPMQQhEC4Ubu1MCAnFrAYvUaewbUhtk', sec: '5ks7qQ8Fpkin7ycXpxQSxxjVhs8VTzpM3vEBMqM7NfC1ZiFJ93uQryDcoM93Mj77T6hDAABdeHZJDFnkDb35bgiU'}, { server: s1 });
 
-    const commitS1 = commit(s1);
-
-    return co(function *() {
-      yield s1.initWithDAL().then(bma).then((bmapi) => bmapi.openConnections());
-      yield cat.createIdentity();
-      yield toc.createIdentity();
-      yield toc.cert(cat);
-      yield cat.cert(toc);
-      yield cat.join();
-      yield toc.join();
-      yield commitS1();
-      yield commitS1();
-      yield tic.createIdentity();
-      yield cat.cert(tic);
-      yield toc.cert(tic);
-      yield tuc.createIdentity();
-      yield tuc.join();
-      yield commitS1();
-      yield commitS1();
-      yield commitS1();
-      yield commitS1();
-    });
+    await s1.initWithDAL().then(BmaDependency.duniter.methods.bma).then((bmapi) => bmapi.openConnections());
+    await cat.createIdentity();
+    await toc.createIdentity();
+    await toc.cert(cat);
+    await cat.cert(toc);
+    await cat.join();
+    await toc.join();
+    await s1.commit();
+    await s1.commit();
+    await tic.createIdentity();
+    await cat.cert(tic);
+    await toc.cert(tic);
+    await tuc.createIdentity();
+    await tuc.join();
+    await s1.commit();
+    await s1.commit();
+    await s1.commit();
+    await s1.commit();
   });
 
   after(() => {
@@ -96,7 +88,7 @@ describe("Pending data", function() {
     });
 
     it('should have forwarded pending identities + ceritifications of tic', function() {
-      return expectAnswer(rp('http://127.0.0.1:7783/wot/lookup/tic', { json: true }), function(res) {
+      return expectAnswer(rp('http://127.0.0.1:7783/wot/lookup/tic', { json: true }), function(res:any) {
         res.should.have.property('results').length(1);
         res.results[0].should.have.property('uids').length(1);
         res.results[0].uids[0].should.have.property('others').length(2);
@@ -104,7 +96,7 @@ describe("Pending data", function() {
     });
 
     it('should have forwarded pending identities + ceritifications of tuc', function() {
-      return expectAnswer(rp('http://127.0.0.1:7783/wot/lookup/tuc', { json: true }), function(res) {
+      return expectAnswer(rp('http://127.0.0.1:7783/wot/lookup/tuc', { json: true }), function(res:any) {
         res.should.have.property('results').length(1);
         res.results[0].should.have.property('uids').length(1);
         res.results[0].uids[0].should.have.property('others').length(0);
diff --git a/test/integration/branches/branches_revert.ts b/test/integration/branches/branches_revert.ts
new file mode 100644
index 0000000000000000000000000000000000000000..55c284a4358cf44e51d56227564668165321f27b
--- /dev/null
+++ b/test/integration/branches/branches_revert.ts
@@ -0,0 +1,75 @@
+// Source file from duniter: Crypto-currency software to manage libre currency such as Äž1
+// Copyright (C) 2018  Cedric Moreau <cem.moreau@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+
+import {NewTestingServer, TestingServer} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
+
+const commonConf = {
+  ipv4: '127.0.0.1',
+  currency: 'bb',
+  httpLogs: true,
+  forksize: 3,
+  sigQty: 1
+};
+
+let s1:TestingServer, cat, toc
+
+describe("Revert root", function() {
+
+  before(async () => {
+
+    s1 = NewTestingServer(Underscore.extend({
+      pair: {
+        pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
+        sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
+      },
+      rootoffset: 10,
+      sigQty: 1, dt: 1, ud0: 120
+    }, commonConf));
+
+    cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
+    toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
+
+    await s1.initDalBmaConnections();
+    await cat.createIdentity();
+    await toc.createIdentity();
+    await toc.cert(cat);
+    await cat.cert(toc);
+    await cat.join();
+    await toc.join();
+    await s1.commit()
+  })
+
+  it('/block/0 should exist', () => s1.expectJSON('/blockchain/block/0', {
+    number: 0
+  }));
+
+  it('/wot/cat should exist', () => s1.expectThat('/wot/lookup/cat', (res:any) => {
+    res.should.have.property('results').length(1);
+    res.results[0].should.have.property('uids').length(1);
+    res.results[0].uids[0].should.have.property('uid').equal('cat');
+    res.results[0].uids[0].should.have.property('others').length(1);
+  }))
+
+  it('reverting should erase everything', async () => {
+    await s1.revert();
+    await s1.expectError('/blockchain/current', 404, 'No current block');
+    await s1.expectError('/blockchain/block/0', 404, 'Block not found');
+    await s1.expectError('/wot/lookup/cat', 404, 'No matching identity'); // Revert completely removes the identity
+  })
+
+  after(() => {
+    return s1.closeCluster()
+  })
+})
diff --git a/test/integration/branches_revert2.js b/test/integration/branches/branches_revert2.ts
similarity index 80%
rename from test/integration/branches_revert2.js
rename to test/integration/branches/branches_revert2.ts
index cb268cc9113920acc5744c0ed7bf31fae002f1f5..9eb046e4fb8e892eb69d28d1b5d6a0a41186896e 100644
--- a/test/integration/branches_revert2.js
+++ b/test/integration/branches/branches_revert2.ts
@@ -11,20 +11,20 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {TestingServer} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
+import {BmaDependency} from "../../../app/modules/bma/index"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
+import {ProverConstants} from "../../../app/modules/prover/lib/constants"
 
-const co = require('co');
-const _         = require('underscore');
-const duniter     = require('../../index');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const TestUser  = require('./tools/TestUser').TestUser
+const duniter     = require('../../../index');
 const rp        = require('request-promise');
-const httpTest  = require('./tools/http');
-const commit    = require('./tools/commit');
-const shutDownEngine  = require('./tools/shutDownEngine');
+const httpTest  = require('../tools/http');
+const commit    = require('../tools/commit');
+const shutDownEngine  = require('../tools/shutDownEngine');
 
-require('../../app/modules/prover/lib/constants').ProverConstants.CORES_MAXIMUM_USE_IN_PARALLEL = 1
-require('../../app/modules/bma').BmaDependency.duniter.methods.noLimit(); // Disables the HTTP limiter
+ProverConstants.CORES_MAXIMUM_USE_IN_PARALLEL = 1
+BmaDependency.duniter.methods.noLimit(); // Disables the HTTP limiter
 
 const expectJSON     = httpTest.expectJSON;
 const expectHttpCode = httpTest.expectHttpCode;
@@ -42,16 +42,16 @@ const commonConf = {
   sigQty: 1
 };
 
-let s1, cat, toc
+let s1:TestingServer, cat:TestUser, toc:TestUser
 
 describe("Revert two blocks", function() {
 
-  before(function() {
+  before(async () => {
 
     s1 = duniter(
       '/bb11',
       MEMORY_MODE,
-      _.extend({
+      Underscore.extend({
         port: '7712',
         pair: {
           pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
@@ -66,20 +66,18 @@ describe("Revert two blocks", function() {
     cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
     toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
 
-    return co(function *() {
-      yield s1.initWithDAL().then(bma).then((bmapi) => bmapi.openConnections());
-      yield cat.createIdentity();
-      yield toc.createIdentity();
-      yield toc.cert(cat);
-      yield cat.cert(toc);
-      yield cat.join();
-      yield toc.join();
-      yield commit(s1)({ time: now });
-      yield commit(s1)({ time: now + 1 });
-      yield commit(s1)({ time: now + 1 });
-      yield cat.sendP(51, toc);
-      yield commit(s1)({ time: now + 1 });
-    });
+    await s1.initWithDAL().then(BmaDependency.duniter.methods.bma).then((bmapi) => bmapi.openConnections());
+    await cat.createIdentity();
+    await toc.createIdentity();
+    await toc.cert(cat);
+    await cat.cert(toc);
+    await cat.join();
+    await toc.join();
+    await commit(s1)({ time: now });
+    await commit(s1)({ time: now + 1 });
+    await commit(s1)({ time: now + 1 });
+    await cat.sendP(51, toc);
+    await commit(s1)({ time: now + 1 });
   });
 
   after(() => {
@@ -111,14 +109,14 @@ describe("Revert two blocks", function() {
     });
 
     it('/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd should have only UD', function() {
-      return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd'), (body) => {
+      return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd'), (body:string) => {
         let res = JSON.parse(body);
         res.sources.should.have.length(0)
       });
     });
 
     it('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo should have only UD', function() {
-      return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo'), (body) => {
+      return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo'), (body:string) => {
         let res = JSON.parse(body);
         res.sources.should.have.length(2);
         res.sources[0].should.have.property('identifier').equal('DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo');
@@ -133,7 +131,7 @@ describe("Revert two blocks", function() {
     });
 
     it('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV should have only UD', function() {
-      return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV'), (body) => {
+      return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV'), (body:string) => {
         let res = JSON.parse(body);
         res.sources.should.have.length(0);
       });
@@ -142,9 +140,9 @@ describe("Revert two blocks", function() {
 
   describe("after revert", () => {
 
-    before(() => co(function*() {
-      yield s1.revert();
-    }))
+    before(async () => {
+      await s1.revert();
+    })
 
     it('/block/0 should exist', function() {
       return expectJSON(rp('http://127.0.0.1:7712/blockchain/block/0', { json: true }), {
@@ -164,7 +162,7 @@ describe("Revert two blocks", function() {
     });
 
     it('/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd should have only UD', function() {
-      return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd'), (body) => {
+      return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd'), (body:string) => {
         let res = JSON.parse(body);
         res.sources.should.have.length(1);
         res.sources[0].should.have.property('identifier').equal('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
@@ -175,7 +173,7 @@ describe("Revert two blocks", function() {
     });
 
     it('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo should have only UD', function() {
-      return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo'), (body) => {
+      return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo'), (body:string) => {
         let res = JSON.parse(body);
         res.sources.should.have.length(1);
         res.sources[0].should.have.property('identifier').equal('DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo');
@@ -186,7 +184,7 @@ describe("Revert two blocks", function() {
     });
 
     it('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV should have only UD', function() {
-      return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV'), (body) => {
+      return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV'), (body:string) => {
         let res = JSON.parse(body);
         res.sources.should.have.length(0);
       });
@@ -195,12 +193,12 @@ describe("Revert two blocks", function() {
 
   describe("commit again (but send less, to check that the account is not cleaned this time)", () => {
 
-    before(() => co(function*() {
-      yield s1.dal.txsDAL.removeAll()
-      yield cat.sendP(19, toc);
-      yield s1.dal.blockDAL.removeBlock('DELETE FROM block WHERE fork AND number = 3')
-      yield commit(s1)({ time: now + 1 });
-    }))
+    before(async () => {
+      await s1.dal.txsDAL.removeAll()
+      await cat.sendP(19, toc);
+      await s1.dal.blockDAL.removeBlock('DELETE FROM block WHERE fork AND number = 3')
+      await commit(s1)({ time: now + 1 });
+    })
 
     it('/block/0 should exist', function() {
       return expectJSON(rp('http://127.0.0.1:7712/blockchain/block/0', { json: true }), {
@@ -223,7 +221,7 @@ describe("Revert two blocks", function() {
     });
 
     it('/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd should have only UD', function() {
-      return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd'), (body) => {
+      return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd'), (body:string) => {
         let res = JSON.parse(body);
         res.sources.should.have.length(1);
         res.sources[0].should.have.property('identifier').equal('7F951D4B73FB65995A1F343366A8CD3B0C76028120FD590170B251EB109926FB');
@@ -234,7 +232,7 @@ describe("Revert two blocks", function() {
     });
 
     it('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo should have only UD', function() {
-      return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo'), (body) => {
+      return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo'), (body:string) => {
         let res = JSON.parse(body);
         res.sources.should.have.length(2);
         res.sources[0].should.have.property('identifier').equal('DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo');
@@ -249,7 +247,7 @@ describe("Revert two blocks", function() {
     });
 
     it('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV should have only UD', function() {
-      return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV'), (body) => {
+      return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV'), (body:string) => {
         let res = JSON.parse(body);
         res.sources.should.have.length(0);
       });
diff --git a/test/integration/branches_revert_balance.js b/test/integration/branches/branches_revert_balance.ts
similarity index 51%
rename from test/integration/branches_revert_balance.js
rename to test/integration/branches/branches_revert_balance.ts
index b32d329a335c8b55393372cfa992b17cd9d89eba..8839fb3533d72858a7ed38d47451f53765455122 100644
--- a/test/integration/branches_revert_balance.js
+++ b/test/integration/branches/branches_revert_balance.ts
@@ -11,16 +11,15 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict"
+import {simpleNodeWith2Users, TestingServer} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
 
-const co        = require('co')
 const should    = require('should')
-const toolbox = require('./tools/toolbox')
 
 describe("Revert balance", () => {
 
   const now = 1480000000
-  let s1, cat, tac
+  let s1:TestingServer, cat:TestUser, tac:TestUser
 
   const conf = {
     nbCores: 1,
@@ -31,65 +30,65 @@ describe("Revert balance", () => {
     medianTimeBlocks: 1 // The medianTime always equals previous block's medianTime
   }
 
-  before(() => co(function*() {
-    const res1 = yield toolbox.simpleNodeWith2Users(conf)
+  before(async () => {
+    const res1 = await simpleNodeWith2Users(conf)
     s1 = res1.s1
     cat = res1.cat
     tac = res1.tac
-    yield s1.commit({ time: now })
-    yield s1.commit({ time: now + 1 })
-    yield s1.commit({ time: now + 1  })
-  }))
+    await s1.commit({ time: now })
+    await s1.commit({ time: now + 1 })
+    await s1.commit({ time: now + 1  })
+  })
 
-  it('cat and tac should have 200 units', () => co(function*() {
-    yield s1.expect('/tx/sources/' + cat.pub, (res) => {
+  it('cat and tac should have 200 units', async () =>  {
+    await s1.expect('/tx/sources/' + cat.pub, (res:any) => {
       res.sources.should.have.length(2)
     })
-    yield s1.expect('/tx/sources/' + tac.pub, (res) => {
+    await s1.expect('/tx/sources/' + tac.pub, (res:any) => {
       res.sources.should.have.length(2)
     })
-  }))
+  })
 
-  it('cat should be able to send 60 units to tac', () => co(function*() {
-    yield cat.send(60, tac)
-    yield s1.commit({ time: now + 1 })
-    yield s1.expect('/tx/sources/' + cat.pub, (res) => {
+  it('cat should be able to send 60 units to tac', async () =>  {
+    await cat.sendMoney(60, tac)
+    await s1.commit({ time: now + 1 })
+    await s1.expect('/tx/sources/' + cat.pub, (res:any) => {
       res.sources.should.have.length(2)
     })
-    yield s1.expect('/tx/sources/' + tac.pub, (res) => {
+    await s1.expect('/tx/sources/' + tac.pub, (res:any) => {
       res.sources.should.have.length(3)
     })
-    const block = yield s1.dal.blockDAL.getBlock(3)
-    // yield s1.writeBlock(block)
-  }))
+    const block = await s1.dal.blockDAL.getBlock(3)
+    // await s1.writeBlock(block)
+  })
 
-  it('revert: cat and tac should have 100 units', () => co(function*() {
-    yield s1.revert();
-    yield s1.expect('/tx/sources/' + cat.pub, (res) => {
+  it('revert: cat and tac should have 100 units', async () =>  {
+    await s1.revert();
+    await s1.expect('/tx/sources/' + cat.pub, (res:any) => {
       res.sources.should.have.length(2)
     })
-    yield s1.expect('/tx/sources/' + tac.pub, (res) => {
+    await s1.expect('/tx/sources/' + tac.pub, (res:any) => {
       res.sources.should.have.length(2)
     })
-  }))
+  })
 
-  it('cat should be able to RE-send 60 units to tac', () => co(function*() {
-    const txsPending = yield s1.dal.txsDAL.getAllPending(1)
-    yield s1.dal.blockDAL.removeForkBlock(3)
+  it('cat should be able to RE-send 60 units to tac', async () =>  {
+    const txsPending = await s1.dal.txsDAL.getAllPending(1)
+    await s1.dal.blockDAL.removeForkBlock(3)
     txsPending.should.have.length(1)
-    yield s1.commit({ time: now + 1 })
-    yield s1.expect('/tx/sources/' + cat.pub, (res) => {
+    await s1.commit({ time: now + 1 })
+    await s1.expect('/tx/sources/' + cat.pub, (res:any) => {
       // Should have 2 sources:
       // * the 2nd UD = 100
       // * the rest of the 1st UD - the money sent (60) = 40
       res.sources.should.have.length(2)
     })
-    yield s1.expect('/tx/sources/' + tac.pub, (res) => {
+    await s1.expect('/tx/sources/' + tac.pub, (res:any) => {
       res.sources.should.have.length(3)
     })
-    const block = yield s1.dal.blockDAL.getBlock(3)
-    // yield s1.writeBlock(block)
-  }))
+    const block = await s1.dal.blockDAL.getBlock(3)
+    // await s1.writeBlock(block)
+  })
 
   after(() => {
     return s1.closeCluster()
diff --git a/test/integration/branches/branches_revert_memberships.ts b/test/integration/branches/branches_revert_memberships.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fdaa44e50261dbf4fd4b9d5ef889d133b6828f77
--- /dev/null
+++ b/test/integration/branches/branches_revert_memberships.ts
@@ -0,0 +1,254 @@
+// Source file from duniter: Crypto-currency software to manage libre currency such as Äž1
+// Copyright (C) 2018  Cedric Moreau <cem.moreau@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+
+import {NewTestingServer, TestingServer} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
+import {FullIindexEntry} from "../../../app/lib/indexer"
+
+const should    = require('should');
+
+let s1:TestingServer, i1:TestUser, i2:TestUser, i3:TestUser
+
+describe("Revert memberships", function() {
+
+  const now = 1482000000;
+
+  before(async () => {
+
+    s1 = NewTestingServer({
+      memory: true,
+      msValidity: 14,
+      pair: {
+        pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
+        sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
+      }
+    });
+
+    i1 = new TestUser('i1',   { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
+    i2 = new TestUser('i2',   { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
+    i3 = new TestUser('i3',   { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
+
+    await s1.initDalBmaConnections();
+
+    await i1.createIdentity();
+    await i2.createIdentity();
+
+    await i1.cert(i2);
+    await i2.cert(i1);
+
+    await i1.join();
+    await i2.join();
+
+    await s1.commit({ time: now });
+    await s1.expect('/blockchain/current', (res:any) => { res.number.should.equal(0); (res.medianTime - now).should.equal(0); });
+    await s1.commit({ time: now + 15 });
+    await s1.expect('/blockchain/current', (res:any) => { res.number.should.equal(1); (res.medianTime - now).should.equal(0); });
+
+    await shouldHavePendingMS(0);
+    await i3.createIdentity();
+    await i1.cert(i3);
+    await shouldBeFreshlyCreated();
+    await i3.join();
+    await shouldHavePendingMS(1);
+    await shouldBeJoining();
+    await s1.commit({ time: now + 15 });
+    await s1.expect('/blockchain/current', (res:any) => { res.number.should.equal(2); (res.medianTime - now).should.equal(7); });
+    await shouldHaveJoined();
+    await shouldHavePendingMS(0);
+  })
+
+  it('should exist 3 members', async () => s1.expect('/blockchain/current', (res:any) => {
+    res.should.have.property('membersCount').equal(3);
+  }))
+
+  it('should exist a renew', async () => {
+    await i3.join(); // Renew
+    await shouldHavePendingMS(1);
+    await s1.commit({ time: now + 15 });
+    await s1.expect('/blockchain/current', (res:any) => { res.number.should.equal(3); (res.medianTime - now).should.equal(10); });
+    await s1.expect('/blockchain/current', (res:any) => {
+      res.should.have.property('membersCount').equal(3);
+      res.should.have.property('actives').length(1);
+    });
+    await shouldBeRenewed();
+    await shouldHavePendingMS(0);
+  })
+
+  it('should exist 2 other renew', async () => {
+    await s1.commit({ time: now + 15 });
+    // await s1.expect('/blockchain/current', (res) => { res.number.should.equal(4); (res.medianTime - now).should.equal(11); });
+    await i1.join(); // Renew
+    await i2.join(); // Renew
+    await shouldHavePendingMS(2);
+    await s1.commit({ time: now + 15 });
+    // await s1.expect('/blockchain/current', (res) => { res.number.should.equal(5); (res.medianTime - now).should.equal(21); });
+    await s1.expect('/blockchain/current', (res:any) => {
+      res.should.have.property('membersCount').equal(3);
+      res.should.have.property('actives').length(2);
+    });
+    await shouldBeRenewed();
+    await shouldHavePendingMS(0);
+  })
+
+  it('should exist a leaver', async () => {
+    await i3.leave();
+    await s1.commit({ time: now + 80 });
+    await s1.expect('/blockchain/current', (res:any) => {
+      // (res.medianTime - now).should.equal(27);
+      res.should.have.property('membersCount').equal(3);
+      res.should.have.property('leavers').length(1);
+    });
+    await shouldBeLeaving();
+    await shouldHavePendingMS(0);
+  })
+
+  it('should exist a kicked member', async () => {
+    await s1.commit({ time: now + 25 });
+    // await s1.expect('/blockchain/current', (res) => { res.number.should.equal(7); (res.medianTime - now).should.equal(25); });
+    // await s1.commit({ time: now + 30 });
+    // await s1.expect('/blockchain/current', (res) => { res.number.should.equal(8); (res.medianTime - now).should.equal(18); });
+    await shouldBeBeingKicked();
+    await s1.commit({ time: now + 30 });
+    await s1.expect('/blockchain/current', (res:any) => {
+      res.should.have.property('membersCount').equal(2);
+      res.should.have.property('excluded').length(1);
+    });
+    // Should:
+    // * unset "to be kicked"
+    // * not be a member anymore
+    await shouldHaveBeenKicked();
+    await shouldHavePendingMS(0);
+  })
+
+  it('a kicked member should be able to join back', async () => {
+    await i3.join();
+    await s1.commit({ time: now + 30 });
+    await shouldHaveComeBack();
+    await shouldHavePendingMS(0);
+  })
+
+  it('revert the join back', async () => {
+    await s1.revert();
+    await shouldHaveBeenKicked();
+    await shouldHavePendingMS(0); // Undone memberships are lost
+  })
+
+  it('revert excluded member', async () => {
+    await s1.revert();
+    await shouldBeBeingKicked();
+    await shouldHavePendingMS(0); // Undone memberships are lost
+  })
+
+  it('revert being kicked', async () => {
+    await s1.revert();
+    await shouldBeLeaving();
+    await shouldHavePendingMS(0); // Undone memberships are lost
+  })
+
+  it('revert leaving', async () => {
+    await s1.revert();
+    await shouldBeRenewed();
+    await shouldHavePendingMS(0); // Undone memberships are lost
+  })
+
+  it('revert 2 neutral blocks for i3', async () => {
+    await s1.revert();
+    await shouldBeRenewed();
+    await shouldHavePendingMS(0); // Undone memberships are lost
+    await s1.revert();
+    await shouldBeRenewed();
+    await shouldHavePendingMS(0); // Undone memberships are lost
+  })
+
+  it('revert renewal block', async () => {
+    await s1.revert();
+    await shouldHaveJoined();
+    await shouldHavePendingMS(0); // Undone memberships are lost
+  })
+
+  it('revert join block', async () => {
+    await s1.revert();
+    await shouldHavePendingMS(0); // Undone memberships are lost
+  })
+
+  after(async () => {
+    return s1.closeCluster()
+  })
+
+  /*********
+   *
+   * Identity state testing functions
+   *
+   ********/
+
+  async function shouldHavePendingMS(number:number) {
+    const pendingIN = await s1.dal.msDAL.getPendingIN();
+    const pendingOUT = await s1.dal.msDAL.getPendingOUT();
+    pendingIN.concat(pendingOUT).should.have.length(number);
+  }
+
+  async function shouldBeFreshlyCreated() {
+    const idty = (await s1.dal.idtyDAL.searchThoseMatching(i3.pub))[0];
+    idty.should.have.property('wasMember').equal(false);
+    idty.should.have.property('written').equal(false);
+    idty.should.have.property('kick').equal(false);
+    idty.should.have.property('member').equal(false);
+  }
+
+  async function shouldBeJoining() {
+    return shouldBeFreshlyCreated();
+  }
+
+  async function shouldHaveJoined() {
+    const idty = await s1.dal.iindexDAL.getFromPubkey(i3.pub) as FullIindexEntry
+    idty.should.have.property('wasMember').equal(true);
+    idty.should.have.property('kick').equal(false);
+    idty.should.have.property('member').equal(true);
+  }
+
+  async function shouldBeRenewed() {
+    const idty = await s1.dal.iindexDAL.getFromPubkey(i3.pub) as FullIindexEntry
+    idty.should.have.property('wasMember').equal(true);
+    idty.should.have.property('kick').equal(false);
+    idty.should.have.property('member').equal(true);
+  }
+
+  async function shouldBeLeaving() {
+    const idty = await s1.dal.iindexDAL.getFromPubkey(i3.pub) as FullIindexEntry
+    idty.should.have.property('wasMember').equal(true);
+    idty.should.have.property('kick').equal(false);
+    idty.should.have.property('member').equal(true);
+  }
+
+  async function shouldBeBeingKicked() {
+    // Should be set as kicked now
+    const idty = await s1.dal.iindexDAL.getFromPubkey(i3.pub) as FullIindexEntry
+    idty.should.have.property('wasMember').equal(true);
+    idty.should.have.property('kick').equal(true);
+    idty.should.have.property('member').equal(true);
+  }
+
+  async function shouldHaveBeenKicked() {
+    const idty = await s1.dal.iindexDAL.getFromPubkey(i3.pub) as FullIindexEntry
+    idty.should.have.property('wasMember').equal(true);
+    idty.should.have.property('kick').equal(false);
+    idty.should.have.property('member').equal(false);
+  }
+
+  async function shouldHaveComeBack() {
+    let idty = await s1.dal.iindexDAL.getFromPubkey(i3.pub) as FullIindexEntry
+    idty.should.have.property('wasMember').equal(true);
+    idty.should.have.property('kick').equal(false);
+    idty.should.have.property('member').equal(true);
+  }
+});
diff --git a/test/integration/branches_switch.ts b/test/integration/branches/branches_switch.ts
similarity index 85%
rename from test/integration/branches_switch.ts
rename to test/integration/branches/branches_switch.ts
index 08a13ed914bb8fd97550f455e37e44b34ae96a02..b3ebebc4900f8d15f40bfa18bb0cbcecad654a40 100644
--- a/test/integration/branches_switch.ts
+++ b/test/integration/branches/branches_switch.ts
@@ -11,21 +11,20 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
-import {CrawlerDependency} from "../../app/modules/crawler/index"
-import {BmaDependency} from "../../app/modules/bma/index"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
+import {BmaDependency} from "../../../app/modules/bma/index"
+import {CrawlerDependency} from "../../../app/modules/crawler/index"
 
 const co = require('co');
-const _         = require('underscore');
-const duniter     = require('../../index');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const TestUser  = require('./tools/TestUser').TestUser
+const duniter     = require('../../../index');
+const bma       = require('../../../app/modules/bma').BmaDependency.duniter.methods.bma;
+const TestUser  = require('../tools/TestUser').TestUser
 const rp        = require('request-promise');
-const httpTest  = require('./tools/http');
-const commit    = require('./tools/commit');
-const sync      = require('./tools/sync');
+const httpTest  = require('../tools/http');
+const commit    = require('../tools/commit');
+const sync      = require('../tools/sync');
 const cluster   = require('cluster')
-const shutDownEngine  = require('./tools/shutDownEngine');
+const shutDownEngine  = require('../tools/shutDownEngine');
 
 const expectJSON     = httpTest.expectJSON;
 
@@ -50,7 +49,7 @@ describe("Switch", function() {
     s1 = duniter(
       '/bb11',
       MEMORY_MODE,
-      _.extend({
+      Underscore.extend({
         switchOnHeadAdvance: 0,
         port: '7788',
         pair: {
@@ -64,7 +63,7 @@ describe("Switch", function() {
     s2 = duniter(
       '/bb12',
       MEMORY_MODE,
-      _.extend({
+      Underscore.extend({
         switchOnHeadAdvance: 0,
         port: '7789',
         pair: {
diff --git a/test/integration/branches_revert.js b/test/integration/branches_revert.js
deleted file mode 100644
index d606c049da428dbd3b9b6737d0e286fa72621176..0000000000000000000000000000000000000000
--- a/test/integration/branches_revert.js
+++ /dev/null
@@ -1,83 +0,0 @@
-// Source file from duniter: Crypto-currency software to manage libre currency such as Äž1
-// Copyright (C) 2018  Cedric Moreau <cem.moreau@gmail.com>
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU Affero General Public License for more details.
-
-"use strict";
-
-const co = require('co');
-const _         = require('underscore');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const TestUser  = require('./tools/TestUser').TestUser
-const toolbox   = require('./tools/toolbox');
-const commit    = require('./tools/commit');
-
-const commonConf = {
-  ipv4: '127.0.0.1',
-  currency: 'bb',
-  httpLogs: true,
-  forksize: 3,
-  sigQty: 1
-};
-
-let s1, cat, toc
-
-describe("Revert root", function() {
-
-  before(function() {
-
-    return co(function *() {
-
-      s1 = toolbox.server(_.extend({
-        pair: {
-          pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
-          sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
-        },
-        rootoffset: 10,
-        sigQty: 1, dt: 1, ud0: 120
-      }, commonConf));
-
-      cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-      toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
-
-      yield s1.initDalBmaConnections();
-      yield cat.createIdentity();
-      yield toc.createIdentity();
-      yield toc.cert(cat);
-      yield cat.cert(toc);
-      yield cat.join();
-      yield toc.join();
-      yield commit(s1)();
-    });
-  });
-
-  it('/block/0 should exist', () => s1.expectJSON('/blockchain/block/0', {
-    number: 0
-  }));
-
-  it('/wot/cat should exist', () => s1.expectThat('/wot/lookup/cat', (res) => {
-    res.should.have.property('results').length(1);
-    res.results[0].should.have.property('uids').length(1);
-    res.results[0].uids[0].should.have.property('uid').equal('cat');
-    res.results[0].uids[0].should.have.property('others').length(1);
-  }));
-
-  it('reverting should erase everything', () => co(function*() {
-    yield s1.revert();
-    yield s1.expectError('/blockchain/current', 404, 'No current block');
-    yield s1.expectError('/blockchain/block/0', 404, 'Block not found');
-    yield s1.expectError('/wot/lookup/cat', 404, 'No matching identity'); // Revert completely removes the identity
-  }));
-
-  after(() => {
-    return s1.closeCluster()
-  })
-});
diff --git a/test/integration/branches_revert_memberships.js b/test/integration/branches_revert_memberships.js
deleted file mode 100644
index 33446bee4f554b005d67518aa2b328834c612f86..0000000000000000000000000000000000000000
--- a/test/integration/branches_revert_memberships.js
+++ /dev/null
@@ -1,271 +0,0 @@
-// Source file from duniter: Crypto-currency software to manage libre currency such as Äž1
-// Copyright (C) 2018  Cedric Moreau <cem.moreau@gmail.com>
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU Affero General Public License for more details.
-
-"use strict";
-
-const co        = require('co');
-const should    = require('should');
-const TestUser  = require('./tools/TestUser').TestUser
-const toolbox   = require('./tools/toolbox');
-
-let s1, i1, i2, i3
-
-describe("Revert memberships", function() {
-
-  const now = 1482000000;
-
-  before(() => co(function*() {
-
-    s1 = toolbox.server({
-      memory: true,
-      msValidity: 14,
-      pair: {
-        pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
-        sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
-      }
-    });
-
-    i1 = new TestUser('i1',   { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    i2 = new TestUser('i2',   { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
-    i3 = new TestUser('i3',   { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
-
-    yield s1.initDalBmaConnections();
-
-    yield i1.createIdentity();
-    yield i2.createIdentity();
-
-    yield i1.cert(i2);
-    yield i2.cert(i1);
-
-    yield i1.join();
-    yield i2.join();
-
-    yield s1.commit({ time: now });
-    yield s1.expect('/blockchain/current', (res) => { res.number.should.equal(0); (res.medianTime - now).should.equal(0); });
-    yield s1.commit({ time: now + 15 });
-    yield s1.expect('/blockchain/current', (res) => { res.number.should.equal(1); (res.medianTime - now).should.equal(0); });
-
-    yield shouldHavePendingMS(0);
-    yield i3.createIdentity();
-    yield i1.cert(i3);
-    yield shouldBeFreshlyCreated();
-    yield i3.join();
-    yield shouldHavePendingMS(1);
-    yield shouldBeJoining();
-    yield s1.commit({ time: now + 15 });
-    yield s1.expect('/blockchain/current', (res) => { res.number.should.equal(2); (res.medianTime - now).should.equal(7); });
-    yield shouldHaveJoined();
-    yield shouldHavePendingMS(0);
-  }));
-
-  it('should exist 3 members', () => s1.expect('/blockchain/current', (res) => {
-    res.should.have.property('membersCount').equal(3);
-  }));
-
-  it('should exist a renew', () => co(function*() {
-    yield i3.join(); // Renew
-    yield shouldHavePendingMS(1);
-    yield s1.commit({ time: now + 15 });
-    yield s1.expect('/blockchain/current', (res) => { res.number.should.equal(3); (res.medianTime - now).should.equal(10); });
-    yield s1.expect('/blockchain/current', (res) => {
-      res.should.have.property('membersCount').equal(3);
-      res.should.have.property('actives').length(1);
-    });
-    yield shouldBeRenewed();
-    yield shouldHavePendingMS(0);
-  }));
-
-  it('should exist 2 other renew', () => co(function*() {
-    yield s1.commit({ time: now + 15 });
-    // yield s1.expect('/blockchain/current', (res) => { res.number.should.equal(4); (res.medianTime - now).should.equal(11); });
-    yield i1.join(); // Renew
-    yield i2.join(); // Renew
-    yield shouldHavePendingMS(2);
-    yield s1.commit({ time: now + 15 });
-    // yield s1.expect('/blockchain/current', (res) => { res.number.should.equal(5); (res.medianTime - now).should.equal(21); });
-    yield s1.expect('/blockchain/current', (res) => {
-      res.should.have.property('membersCount').equal(3);
-      res.should.have.property('actives').length(2);
-    });
-    yield shouldBeRenewed();
-    yield shouldHavePendingMS(0);
-  }));
-
-  it('should exist a leaver', () => co(function*() {
-    yield i3.leave();
-    yield s1.commit({ time: now + 80 });
-    yield s1.expect('/blockchain/current', (res) => {
-      // (res.medianTime - now).should.equal(27);
-      res.should.have.property('membersCount').equal(3);
-      res.should.have.property('leavers').length(1);
-    });
-    yield shouldBeLeaving();
-    yield shouldHavePendingMS(0);
-  }));
-
-  it('should exist a kicked member', () => co(function*() {
-    yield s1.commit({ time: now + 25 });
-    // yield s1.expect('/blockchain/current', (res) => { res.number.should.equal(7); (res.medianTime - now).should.equal(25); });
-    // yield s1.commit({ time: now + 30 });
-    // yield s1.expect('/blockchain/current', (res) => { res.number.should.equal(8); (res.medianTime - now).should.equal(18); });
-    yield shouldBeBeingKicked();
-    yield s1.commit({ time: now + 30 });
-    yield s1.expect('/blockchain/current', (res) => {
-      res.should.have.property('membersCount').equal(2);
-      res.should.have.property('excluded').length(1);
-    });
-    // Should:
-    // * unset "to be kicked"
-    // * not be a member anymore
-    yield shouldHaveBeenKicked();
-    yield shouldHavePendingMS(0);
-  }));
-
-  it('a kicked member should be able to join back', () => co(function*() {
-    yield i3.join();
-    yield s1.commit({ time: now + 30 });
-    yield shouldHaveComeBack();
-    yield shouldHavePendingMS(0);
-  }));
-
-  it('revert the join back', () => co(function*() {
-    yield s1.revert();
-    yield shouldHaveBeenKicked();
-    yield shouldHavePendingMS(0); // Undone memberships are lost
-  }));
-
-  it('revert excluded member', () => co(function*() {
-    yield s1.revert();
-    yield shouldBeBeingKicked();
-    yield shouldHavePendingMS(0); // Undone memberships are lost
-  }));
-
-  it('revert being kicked', () => co(function*() {
-    yield s1.revert();
-    yield shouldBeLeaving();
-    yield shouldHavePendingMS(0); // Undone memberships are lost
-  }));
-
-  it('revert leaving', () => co(function*() {
-    yield s1.revert();
-    yield shouldBeRenewed();
-    yield shouldHavePendingMS(0); // Undone memberships are lost
-  }));
-
-  it('revert 2 neutral blocks for i3', () => co(function*() {
-    yield s1.revert();
-    yield shouldBeRenewed();
-    yield shouldHavePendingMS(0); // Undone memberships are lost
-    yield s1.revert();
-    yield shouldBeRenewed();
-    yield shouldHavePendingMS(0); // Undone memberships are lost
-  }));
-
-  it('revert renewal block', () => co(function*() {
-    yield s1.revert();
-    yield shouldHaveJoined();
-    yield shouldHavePendingMS(0); // Undone memberships are lost
-  }));
-
-  it('revert join block', () => co(function*() {
-    yield s1.revert();
-    yield shouldHavePendingMS(0); // Undone memberships are lost
-  }));
-
-  after(() => {
-    return s1.closeCluster()
-  })
-
-  /*********
-   *
-   * Identity state testing functions
-   *
-   ********/
-
-  function shouldHavePendingMS(number) {
-    return co(function*() {
-      const pendingIN = yield s1.dal.msDAL.getPendingIN();
-      const pendingOUT = yield s1.dal.msDAL.getPendingOUT();
-      pendingIN.concat(pendingOUT).should.have.length(number);
-    });
-  }
-
-  function shouldBeFreshlyCreated() {
-    return co(function*() {
-      const idty = (yield s1.dal.idtyDAL.searchThoseMatching(i3.pub))[0];
-      idty.should.have.property('wasMember').equal(false);
-      idty.should.have.property('written').equal(false);
-      idty.should.have.property('kick').equal(false);
-      idty.should.have.property('member').equal(false);
-    });
-  }
-
-  function shouldBeJoining() {
-    return shouldBeFreshlyCreated();
-  }
-
-  function shouldHaveJoined() {
-    return co(function*() {
-      const idty = yield s1.dal.iindexDAL.getFromPubkey(i3.pub);
-      idty.should.have.property('wasMember').equal(true);
-      idty.should.have.property('kick').equal(false);
-      idty.should.have.property('member').equal(true);
-    });
-  }
-
-  function shouldBeRenewed() {
-    return co(function*() {
-      const idty = yield s1.dal.iindexDAL.getFromPubkey(i3.pub);
-      idty.should.have.property('wasMember').equal(true);
-      idty.should.have.property('kick').equal(false);
-      idty.should.have.property('member').equal(true);
-    });
-  }
-
-  function shouldBeLeaving() {
-    return co(function*() {
-      const idty = yield s1.dal.iindexDAL.getFromPubkey(i3.pub);
-      idty.should.have.property('wasMember').equal(true);
-      idty.should.have.property('kick').equal(false);
-      idty.should.have.property('member').equal(true);
-    });
-  }
-
-  function shouldBeBeingKicked() {
-    return co(function*() {
-      // Should be set as kicked now
-      const idty = yield s1.dal.iindexDAL.getFromPubkey(i3.pub);
-      idty.should.have.property('wasMember').equal(true);
-      idty.should.have.property('kick').equal(true);
-      idty.should.have.property('member').equal(true);
-    });
-  }
-
-  function shouldHaveBeenKicked() {
-    return co(function*() {
-      const idty = yield s1.dal.iindexDAL.getFromPubkey(i3.pub);
-      idty.should.have.property('wasMember').equal(true);
-      idty.should.have.property('kick').equal(false);
-      idty.should.have.property('member').equal(false);
-    });
-  }
-
-  function shouldHaveComeBack() {
-    return co(function*() {
-      let idty = yield s1.dal.iindexDAL.getFromPubkey(i3.pub);
-      idty.should.have.property('wasMember').equal(true);
-      idty.should.have.property('kick').equal(false);
-      idty.should.have.property('member').equal(true);
-    });
-  }
-});
diff --git a/test/integration/certification_chainability.js b/test/integration/certification/certification_chainability.ts
similarity index 67%
rename from test/integration/certification_chainability.js
rename to test/integration/certification/certification_chainability.ts
index 5ca1cf28343a2e0533827e57969cb1cdab9b9615..ca4955b0495587da4f59b0a921e9d113ee93402b 100644
--- a/test/integration/certification_chainability.js
+++ b/test/integration/certification/certification_chainability.ts
@@ -11,19 +11,16 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {TestUser} from "../tools/TestUser"
+import {BmaDependency} from "../../../app/modules/bma/index"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
+import {NewTestingServer, TestingServer} from "../tools/toolbox"
+import {HttpBlock} from "../../../app/modules/bma/lib/dtos"
 
-const _         = require('underscore');
-const co        = require('co');
 const should    = require('should');
-const duniter     = require('../../index');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const TestUser  = require('./tools/TestUser').TestUser
-const constants = require('../../app/lib/constants');
 const rp        = require('request-promise');
-const httpTest  = require('./tools/http');
-const commit    = require('./tools/commit');
-const shutDownEngine  = require('./tools/shutDownEngine');
+const httpTest  = require('../tools/http');
+const shutDownEngine  = require('../tools/shutDownEngine');
 
 const expectAnswer   = httpTest.expectAnswer;
 
@@ -37,16 +34,16 @@ const commonConf = {
   sigQty: 1
 };
 
-let s1, cat, tac, tic, toc
+let s1:TestingServer, cat:TestUser, tac:TestUser, tic:TestUser, toc:TestUser
 
 describe("Certification chainability", function() {
 
-  before(function() {
+  before(async () => {
 
-    s1 = duniter(
-      '/bb11',
-      MEMORY_MODE,
-      _.extend({
+    s1 = NewTestingServer(
+      Underscore.extend({
+        name: 'bb11',
+        memory: MEMORY_MODE,
         port: '9225',
         pair: {
           pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
@@ -61,41 +58,37 @@ describe("Certification chainability", function() {
 
     const now = 1482220000;
 
-    const commitS1 = commit(s1);
-
-    return co(function *() {
-      /**
-       * tac <===> cat
-       */
-      yield s1.initWithDAL().then(bma).then((bmapi) => bmapi.openConnections());
-      yield cat.createIdentity();
-      yield tac.createIdentity();
-      yield cat.cert(tac);
-      yield tac.cert(cat);
-      yield cat.join();
-      yield tac.join();
-      yield commitS1({ time: now });
-      yield commitS1({
-        time: now + 399
-      });
-
-      // Should not happen on the first commit due to certPeriod
-      yield tic.createIdentity();
-      yield tic.join();
-      yield cat.cert(tic);
-      yield commitS1({ time: now + 199 });
-      yield commitS1({ time: now + 199 });
-      // We still are at +199, and the certPeriod must be OVER (or equal to) current time to allow new certs from cat.
-      // So if we increment +1
-      yield commitS1({
-        time: now + 300
-      });
-      yield commitS1({
-        time: now + 300
-      });
-      // Should be integrated now
-      yield commitS1({ time: now + 300 });
+    /**
+     * tac <===> cat
+     */
+    await s1.initWithDAL().then(BmaDependency.duniter.methods.bma).then((bmapi) => bmapi.openConnections());
+    await cat.createIdentity();
+    await tac.createIdentity();
+    await cat.cert(tac);
+    await tac.cert(cat);
+    await cat.join();
+    await tac.join();
+    await s1.commit({ time: now });
+    await s1.commit({
+      time: now + 399
     });
+
+    // Should not happen on the first commit due to certPeriod
+    await tic.createIdentity();
+    await tic.join();
+    await cat.cert(tic);
+    await s1.commit({ time: now + 199 });
+    await s1.commit({ time: now + 199 });
+    // We still are at +199, and the certPeriod must be OVER (or equal to) current time to allow new certs from cat.
+    // So if we increment +1
+    await s1.commit({
+      time: now + 300
+    });
+    await s1.commit({
+      time: now + 300
+    });
+    // Should be integrated now
+    await s1.commit({ time: now + 300 });
   });
 
   after(() => {
@@ -105,49 +98,49 @@ describe("Certification chainability", function() {
   })
 
   it('block 0 should have 2 certs', function() {
-    return expectAnswer(rp('http://127.0.0.1:9225/blockchain/block/0', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:9225/blockchain/block/0', { json: true }), function(res:HttpBlock) {
       res.should.have.property('number').equal(0);
       res.should.have.property('certifications').length(2);
     });
   });
 
   it('block 1 should have 0 certs', function() {
-    return expectAnswer(rp('http://127.0.0.1:9225/blockchain/block/1', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:9225/blockchain/block/1', { json: true }), function(res:HttpBlock) {
       res.should.have.property('number').equal(1);
       res.should.have.property('certifications').length(0);
     });
   });
 
   it('block 2 should have 0 certs', function() {
-    return expectAnswer(rp('http://127.0.0.1:9225/blockchain/block/2', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:9225/blockchain/block/2', { json: true }), function(res:HttpBlock) {
       res.should.have.property('number').equal(2);
       res.should.have.property('certifications').length(0);
     });
   });
 
   it('block 3 should have 0 certs', function() {
-    return expectAnswer(rp('http://127.0.0.1:9225/blockchain/block/3', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:9225/blockchain/block/3', { json: true }), function(res:HttpBlock) {
       res.should.have.property('number').equal(3);
       res.should.have.property('certifications').length(0);
     });
   });
 
   it('block 4 should have 0 certs', function() {
-    return expectAnswer(rp('http://127.0.0.1:9225/blockchain/block/4', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:9225/blockchain/block/4', { json: true }), function(res:HttpBlock) {
       res.should.have.property('number').equal(4);
       res.should.have.property('certifications').length(0);
     });
   });
 
   it('block 5 should have 0 certs', function() {
-    return expectAnswer(rp('http://127.0.0.1:9225/blockchain/block/5', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:9225/blockchain/block/5', { json: true }), function(res:HttpBlock) {
       res.should.have.property('number').equal(5);
       res.should.have.property('certifications').length(0);
     });
   });
 
   it('block 6 should have 1 certs', function() {
-    return expectAnswer(rp('http://127.0.0.1:9225/blockchain/block/6', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:9225/blockchain/block/6', { json: true }), function(res:HttpBlock) {
       res.should.have.property('number').equal(6);
       res.should.have.property('certifications').length(1);
     });
diff --git a/test/integration/certifier-is-member.js b/test/integration/certification/certifier-is-member.ts
similarity index 51%
rename from test/integration/certifier-is-member.js
rename to test/integration/certification/certifier-is-member.ts
index 6c3bfe4568334e19338050e20cf532ab6ff7c936..3a260faa48acabd79888abf7a168465a31057cd3 100644
--- a/test/integration/certifier-is-member.js
+++ b/test/integration/certification/certifier-is-member.ts
@@ -11,27 +11,22 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {NewTestingServer, TestingServer} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
+import {shouldFail} from "../../unit-tools"
 
-const _         = require('underscore');
-const co        = require('co');
 const assert    = require('assert');
 const should    = require('should');
-const duniter   = require('../../index');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const TestUser  = require('./tools/TestUser').TestUser
-const constants = require('../../app/lib/constants');
-const toolbox   = require('./tools/toolbox');
 
 const now = 1480000000;
 
-let s1, cat, tac, tic
+let s1:TestingServer, cat:TestUser, tac:TestUser, tic:TestUser
 
 describe("Certifier must be a member", function() {
 
-  before(() => co(function *() {
+  before(async () => {
 
-    s1 = toolbox.server({
+    s1 = NewTestingServer({
       pair: {
         pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
         sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
@@ -46,62 +41,62 @@ describe("Certifier must be a member", function() {
     tac = new TestUser('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
     tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
 
-    yield s1.initDalBmaConnections();
-    yield cat.createIdentity();
-    yield tac.createIdentity();
-    yield cat.cert(tac);
-    yield tac.cert(cat);
-    yield cat.join();
-    yield tac.join();
-    yield s1.commit({ time: now });
-    yield s1.commit({ time: now + 8 });
-    yield s1.commit({ time: now + 9 });
-  }));
-
-  it('tic should not be able to certify yet', () => co(function*() {
-    yield tic.createIdentity();
-    yield tic.join();
-    yield cat.cert(tic);
-    yield toolbox.shouldFail(tic.cert(cat), 'Certifier must be a member')
-  }));
-
-  it('block#3 should see tic becoming member', () => co(function*() {
-    yield cat.join();
-    yield tac.join();
-    yield s1.commit({ time: now + 16 });
-    yield s1.expectThat('/blockchain/block/3', (res) => {
+    await s1.initDalBmaConnections();
+    await cat.createIdentity();
+    await tac.createIdentity();
+    await cat.cert(tac);
+    await tac.cert(cat);
+    await cat.join();
+    await tac.join();
+    await s1.commit({ time: now });
+    await s1.commit({ time: now + 8 });
+    await s1.commit({ time: now + 9 });
+  })
+
+  it('tic should not be able to certify yet', async () => {
+    await tic.createIdentity();
+    await tic.join();
+    await cat.cert(tic);
+    await shouldFail(tic.cert(cat), 'Certifier must be a member')
+  })
+
+  it('block#3 should see tic becoming member', async () => {
+    await cat.join();
+    await tac.join();
+    await s1.commit({ time: now + 16 });
+    await s1.expectThat('/blockchain/block/3', (res:any) => {
       res.should.have.property('joiners').length(1);
     })
-  }));
-
-  it('tic is now a member, he should be able to certify', () => co(function*() {
-    yield tic.cert(cat);
-    yield s1.commit({ time: now + 16 });
-    yield cat.join();
-    yield tac.join();
-    yield s1.commit({ time: now + 21 });
-  }));
-
-  it('tic should be excluded', () => co(function*() {
-    yield s1.commit({ time: now + 21 });
-    yield s1.commit({ time: now + 22 });
-    yield s1.expectThat('/blockchain/block/7', (res) => {
+  })
+
+  it('tic is now a member, he should be able to certify', async () => {
+    await tic.cert(cat);
+    await s1.commit({ time: now + 16 });
+    await cat.join();
+    await tac.join();
+    await s1.commit({ time: now + 21 });
+  })
+
+  it('tic should be excluded', async () => {
+    await s1.commit({ time: now + 21 });
+    await s1.commit({ time: now + 22 });
+    await s1.expectThat('/blockchain/block/7', (res:any) => {
       res.should.have.property('excluded').length(1);
       res.excluded[0].should.equal('DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV')
     })
-  }));
+  })
 
-  it('tic should not be able to certify as he is no more a member', () => co(function*() {
-    yield toolbox.shouldFail(tic.cert(tac), 'Certifier must be a member')
-  }));
+  it('tic should not be able to certify as he is no more a member', async () => {
+    await shouldFail(tic.cert(tac), 'Certifier must be a member')
+  })
 
-  it('tic should be able to certify when he joins back', () => co(function*() {
-    yield tic.join();
-    yield s1.commit({ time: now + 23 });
-    yield tic.cert(tac);
-  }));
+  it('tic should be able to certify when he joins back', async () => {
+    await tic.join();
+    await s1.commit({ time: now + 23 });
+    await tic.cert(tac);
+  })
 
   after(() => {
     return s1.closeCluster()
   })
-});
+})
diff --git a/test/integration/identity-expiry.js b/test/integration/identity-expiry.js
deleted file mode 100644
index 597752905a9cbbe63e5c571f0d417991a3d5ed3e..0000000000000000000000000000000000000000
--- a/test/integration/identity-expiry.js
+++ /dev/null
@@ -1,116 +0,0 @@
-// Source file from duniter: Crypto-currency software to manage libre currency such as Äž1
-// Copyright (C) 2018  Cedric Moreau <cem.moreau@gmail.com>
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU Affero General Public License for more details.
-
-"use strict";
-
-const _         = require('underscore');
-const co        = require('co');
-const should    = require('should');
-const duniter   = require('../../index');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const prover    = require('../../app/modules/prover').ProverDependency.duniter.methods;
-const TestUser  = require('./tools/TestUser').TestUser
-const constants = require('../../app/lib/constants');
-const rp        = require('request-promise');
-const httpTest  = require('./tools/http');
-const commit    = require('./tools/commit');
-const shutDownEngine = require('./tools/shutDownEngine');
-
-const expectAnswer = httpTest.expectAnswer;
-const expectError  = httpTest.expectError;
-
-const MEMORY_MODE = true;
-const commonConf = {
-  ipv4: '127.0.0.1',
-  currency: 'bb',
-  httpLogs: true,
-  forksize: 3,
-  xpercent: 0.9,
-  msValidity: 10000,
-  idtyWindow: 1, // 1 second of duration
-  sigQty: 1
-};
-
-let s1, cat, tac, tic, toc
-
-const now = 1482300000;
-const commitS1 = (opts) => commit(s1)(opts)
-
-describe("Identities expiry", function() {
-
-  before(function() {
-
-    return co(function *() {
-
-      s1 = duniter(
-        '/bb11',
-        MEMORY_MODE,
-        _.extend({
-          port: '8560',
-          pair: {
-            pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
-            sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
-          }
-        }, commonConf));
-
-      cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-      tac = new TestUser('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
-      tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
-      toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
-
-      yield s1.initWithDAL().then(bma).then((bmapi) => bmapi.openConnections());
-      prover.hookServer(s1)
-      yield cat.createIdentity();
-      yield tac.createIdentity();
-      yield tic.createIdentity();
-      yield cat.cert(tac);
-      yield tac.cert(cat);
-      yield cat.join();
-      yield tac.join();
-      yield commitS1({
-        time: now
-      });
-      yield toc.createIdentity();
-      yield toc.join();
-      yield commitS1({
-        time: now + 5
-      });
-    });
-  });
-
-  after(() => {
-    return shutDownEngine(s1)
-  })
-
-  it('should have requirements failing for tic', function() {
-    // tic has been cleaned up, since its identity has expired after the root block
-    return expectError(404, 'No identity matching this pubkey or uid', rp('http://127.0.0.1:8560/wot/requirements/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', { json: true }));
-  });
-
-  it('should have requirements failing for toc', function() {
-    return expectAnswer(rp('http://127.0.0.1:8560/wot/requirements/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', { json: true }), (res) => {
-      res.should.have.property('identities').length(1);
-      res.identities[0].should.have.property('pubkey').equal('DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo');
-      res.identities[0].should.have.property('uid').equal('toc');
-      res.identities[0].should.have.property('expired').equal(false);
-    });
-  });
-
-  it('should have requirements failing for toc', () => co(function*() {
-    // tic has been cleaned up after the block#2
-    yield commitS1({
-      time: now + 5
-    });
-    return expectError(404, 'No identity matching this pubkey or uid', rp('http://127.0.0.1:8560/wot/requirements/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', { json: true }));
-  }));
-});
diff --git a/test/integration/identity-implicit-revocation.js b/test/integration/identity-implicit-revocation.js
index 1037ebad4e5c5b8ef4eafc4229948b94b34a8956..d3d98b9f57d2f662f1587ab20c591ca78abd3a3c 100644
--- a/test/integration/identity-implicit-revocation.js
+++ b/test/integration/identity-implicit-revocation.js
@@ -13,7 +13,6 @@
 
 "use strict";
 
-const _         = require('underscore');
 const co        = require('co');
 const assert    = require('assert');
 const should    = require('should');
diff --git a/test/integration/identity-absorption.js b/test/integration/identity/identity-absorption.ts
similarity index 63%
rename from test/integration/identity-absorption.js
rename to test/integration/identity/identity-absorption.ts
index 3335529e5d17b8334e588e120002094becdfd659..bbaf24fffaecdd8d8d8511ae524020b0954b291e 100644
--- a/test/integration/identity-absorption.js
+++ b/test/integration/identity/identity-absorption.ts
@@ -11,17 +11,16 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {TestingServer} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
+import {BmaDependency} from "../../../app/modules/bma/index"
+import {shouldFail} from "../../unit-tools"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
 
-const _         = require('underscore');
-const co        = require('co');
-const duniter     = require('../../index');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const TestUser  = require('./tools/TestUser').TestUser
+const duniter     = require('../../../index');
 const rp        = require('request-promise');
-const httpTest  = require('./tools/http');
-const toolbox   = require('./tools/toolbox');
-const shutDownEngine  = require('./tools/shutDownEngine');
+const httpTest  = require('../tools/http');
+const shutDownEngine  = require('../tools/shutDownEngine');
 
 const expectAnswer   = httpTest.expectAnswer;
 
@@ -36,16 +35,16 @@ const commonConf = {
   sigQty: 1
 };
 
-let s1, s2, cat, tic
+let s1:TestingServer, s2:TestingServer, cat:TestUser, tic:TestUser
 
-describe("Identity absorption", function() {
+describe("Identity absorption", () => {
 
-  before(function() {
+  before(async () => {
 
     s1 = duniter(
       '/bb12',
       MEMORY_MODE,
-      _.extend({
+      Underscore.extend({
         port: '4450',
         pair: {
           pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
@@ -56,7 +55,7 @@ describe("Identity absorption", function() {
     s2 = duniter(
       '/bb12',
       MEMORY_MODE,
-      _.extend({
+      Underscore.extend({
         port: '4451',
         pair: {
           pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV',
@@ -67,12 +66,10 @@ describe("Identity absorption", function() {
     cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
     tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s2 });
 
-    return co(function *() {
-      yield s1.initWithDAL().then(bma).then((bmapi) => bmapi.openConnections());
-      yield s2.initWithDAL().then(bma).then((bmapi) => bmapi.openConnections());
-      yield cat.createIdentity();
-      yield tic.cert(cat, s1);
-    });
+    await s1.initWithDAL().then(BmaDependency.duniter.methods.bma).then((bmapi) => bmapi.openConnections());
+    await s2.initWithDAL().then(BmaDependency.duniter.methods.bma).then((bmapi) => bmapi.openConnections());
+    await cat.createIdentity();
+    await tic.cert(cat, s1);
   });
 
   after(() => {
@@ -82,29 +79,29 @@ describe("Identity absorption", function() {
     ])
   })
 
-  it('cat should exist on server 1', function() {
-    return expectAnswer(rp('http://127.0.0.1:4450/wot/lookup/cat', { json: true }), function(res) {
+  it('cat should exist on server 1', () => {
+    return expectAnswer(rp('http://127.0.0.1:4450/wot/lookup/cat', { json: true }), function(res:any) {
       res.should.have.property('results').length(1);
       res.results[0].should.have.property('uids').length(1);
       res.results[0].uids[0].should.have.property('uid').equal('cat');
     });
   });
 
-  it('cat should exist on server 2', function() {
-    return expectAnswer(rp('http://127.0.0.1:4451/wot/lookup/cat', { json: true }), function(res) {
+  it('cat should exist on server 2', () => {
+    return expectAnswer(rp('http://127.0.0.1:4451/wot/lookup/cat', { json: true }), function(res:any) {
       res.should.have.property('results').length(1);
       res.results[0].should.have.property('uids').length(1);
       res.results[0].uids[0].should.have.property('uid').equal('cat');
     });
   });
 
-  it('should test idty absorption refusal', () => co(function*() {
-    (yield s2.dal.idtyDAL.query('SELECT * FROM idty')).should.have.length(1);
-    yield s2.dal.idtyDAL.exec('DELETE FROM idty');
-    (yield s2.dal.idtyDAL.query('SELECT * FROM idty')).should.have.length(0);
-    yield toolbox.shouldFail(tic.cert(cat, s1), 'Already up-to-date');
-    (yield s2.dal.idtyDAL.query('SELECT * FROM idty')).should.have.length(1);
-    (yield s2.dal.idtyDAL.query('SELECT * FROM idty WHERE removed')).should.have.length(1);
-    (yield s2.dal.idtyDAL.query('SELECT * FROM idty WHERE NOT removed')).should.have.length(0);
-  }));
-});
+  it('should test idty absorption refusal', async () => {
+    (await s2.dal.idtyDAL.query('SELECT * FROM idty')).should.have.length(1);
+    await s2.dal.idtyDAL.exec('DELETE FROM idty');
+    (await s2.dal.idtyDAL.query('SELECT * FROM idty')).should.have.length(0);
+    await shouldFail(tic.cert(cat, s1), 'Already up-to-date');
+    (await s2.dal.idtyDAL.query('SELECT * FROM idty')).should.have.length(1);
+    (await s2.dal.idtyDAL.query('SELECT * FROM idty WHERE removed')).should.have.length(1);
+    (await s2.dal.idtyDAL.query('SELECT * FROM idty WHERE NOT removed')).should.have.length(0);
+  })
+})
diff --git a/test/integration/identity-clean-test.js b/test/integration/identity/identity-clean-test.ts
similarity index 65%
rename from test/integration/identity-clean-test.js
rename to test/integration/identity/identity-clean-test.ts
index a042d79d8dbe8f2a7d87cdef5e936da0fa4f31ba..f311491a2de403185af73cfbab16a30dc07b5ff0 100644
--- a/test/integration/identity-clean-test.js
+++ b/test/integration/identity/identity-clean-test.ts
@@ -11,17 +11,17 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {TestingServer} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
+import {BmaDependency} from "../../../app/modules/bma/index"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
+import {HttpMembers} from "../../../app/modules/bma/lib/dtos"
 
-const _         = require('underscore');
-const co        = require('co');
-const duniter     = require('../../index');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const TestUser  = require('./tools/TestUser').TestUser
+const duniter     = require('../../../index');
 const rp        = require('request-promise');
-const httpTest  = require('./tools/http');
-const commit    = require('./tools/commit');
-const shutDownEngine  = require('./tools/shutDownEngine');
+const httpTest  = require('../tools/http');
+const commit    = require('../tools/commit');
+const shutDownEngine  = require('../tools/shutDownEngine');
 
 const expectAnswer   = httpTest.expectAnswer;
 
@@ -36,16 +36,16 @@ const commonConf = {
   sigQty: 1
 };
 
-let s1, cat, tac, tic, toc
+let s1:TestingServer, cat:TestUser, tac:TestUser, tic:TestUser, toc:TestUser
 
 describe("Identities cleaned", function() {
 
-  before(function() {
+  before(async () => {
 
     s1 = duniter(
       '/bb12',
       MEMORY_MODE,
-      _.extend({
+      Underscore.extend({
         port: '7733',
         pair: {
           pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
@@ -60,31 +60,29 @@ describe("Identities cleaned", function() {
 
     const commitS1 = commit(s1);
 
-    return co(function *() {
-      yield s1.initWithDAL().then(bma).then((bmapi) => bmapi.openConnections());
-      yield cat.createIdentity();
-      yield tic.createIdentity();
-      yield toc.createIdentity();
-
-      yield expectAnswer(rp('http://127.0.0.1:7733/wot/lookup/cat', { json: true }), function(res) {
-        res.should.have.property('results').length(2);
-        res.results[0].should.have.property('uids').length(1);
-        res.results[0].uids[0].should.have.property('uid').equal('cat'); // This is cat
-        res.results[1].uids[0].should.have.property('uid').equal('cat'); // This is toc
-      });
-
-      yield cat.cert(tic);
-      yield tic.cert(cat);
-      yield cat.join();
-      yield tic.join();
-      yield commitS1();
-
-      // We have the following WoT (diameter 1):
-
-      /**
-       *  cat <-> tic
-       */
+    await s1.initWithDAL().then(BmaDependency.duniter.methods.bma).then((bmapi) => bmapi.openConnections());
+    await cat.createIdentity();
+    await tic.createIdentity();
+    await toc.createIdentity();
+
+    await expectAnswer(rp('http://127.0.0.1:7733/wot/lookup/cat', { json: true }), function(res:any) {
+      res.should.have.property('results').length(2);
+      res.results[0].should.have.property('uids').length(1);
+      res.results[0].uids[0].should.have.property('uid').equal('cat'); // This is cat
+      res.results[1].uids[0].should.have.property('uid').equal('cat'); // This is toc
     });
+
+    await cat.cert(tic);
+    await tic.cert(cat);
+    await cat.join();
+    await tic.join();
+    await commitS1();
+
+    // We have the following WoT (diameter 1):
+
+    /**
+     *  cat <-> tic
+     */
   });
 
   after(() => {
@@ -94,14 +92,14 @@ describe("Identities cleaned", function() {
   })
 
   it('should have 2 members', function() {
-    return expectAnswer(rp('http://127.0.0.1:7733/wot/members', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:7733/wot/members', { json: true }), function(res:HttpMembers) {
       res.should.have.property('results').length(2);
-      _.pluck(res.results, 'uid').sort().should.deepEqual(['cat', 'tic']);
+      Underscore.pluck(res.results, 'uid').sort().should.deepEqual(['cat', 'tic']);
     });
   });
 
   it('lookup should give only 1 cat', function() {
-    return expectAnswer(rp('http://127.0.0.1:7733/wot/lookup/cat', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:7733/wot/lookup/cat', { json: true }), function(res:any) {
       res.should.have.property('results').length(1);
       res.results[0].should.have.property('uids').length(1);
       res.results[0].uids[0].should.have.property('uid').equal('cat');
@@ -109,7 +107,7 @@ describe("Identities cleaned", function() {
   });
 
   it('lookup should give only 1 tic', function() {
-    return expectAnswer(rp('http://127.0.0.1:7733/wot/lookup/tic', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:7733/wot/lookup/tic', { json: true }), function(res:any) {
       res.should.have.property('results').length(1);
       res.results[0].should.have.property('uids').length(1);
       res.results[0].uids[0].should.have.property('uid').equal('tic');
diff --git a/test/integration/identity/identity-expiry.ts b/test/integration/identity/identity-expiry.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8b6f9a0e89859b787647d155573199969052699a
--- /dev/null
+++ b/test/integration/identity/identity-expiry.ts
@@ -0,0 +1,109 @@
+// Source file from duniter: Crypto-currency software to manage libre currency such as Äž1
+// Copyright (C) 2018  Cedric Moreau <cem.moreau@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+
+import {BmaDependency} from "../../../app/modules/bma/index"
+import {NewTestingServer, TestingServer} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
+import {HttpRequirements} from "../../../app/modules/bma/lib/dtos"
+import {ProverDependency} from "../../../app/modules/prover/index"
+
+const should    = require('should');
+const rp        = require('request-promise');
+const httpTest  = require('../tools/http');
+const shutDownEngine = require('../tools/shutDownEngine');
+
+const expectAnswer = httpTest.expectAnswer;
+const expectError  = httpTest.expectError;
+
+const MEMORY_MODE = true;
+const commonConf = {
+  ipv4: '127.0.0.1',
+  currency: 'bb',
+  httpLogs: true,
+  forksize: 3,
+  xpercent: 0.9,
+  msValidity: 10000,
+  idtyWindow: 1, // 1 second of duration
+  sigQty: 1
+};
+
+let s1:TestingServer, cat:TestUser, tac:TestUser, tic:TestUser, toc:TestUser
+
+const now = 1482300000;
+
+describe("Identities expiry", function() {
+
+  before(async () => {
+
+    s1 = NewTestingServer(
+      Underscore.extend({
+        name: 'bb11',
+        memory: MEMORY_MODE,
+        port: '8560',
+        pair: {
+          pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
+          sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
+        }
+      }, commonConf));
+
+    cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
+    tac = new TestUser('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
+    tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
+    toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
+
+    await s1.initWithDAL().then(BmaDependency.duniter.methods.bma).then((bmapi) => bmapi.openConnections());
+    ProverDependency.duniter.methods.hookServer(s1._server)
+    await cat.createIdentity();
+    await tac.createIdentity();
+    await tic.createIdentity();
+    await cat.cert(tac);
+    await tac.cert(cat);
+    await cat.join();
+    await tac.join();
+    await s1.commit({
+      time: now
+    });
+    await toc.createIdentity();
+    await toc.join();
+    await s1.commit({
+      time: now + 5
+    })
+  });
+
+  after(() => {
+    return shutDownEngine(s1)
+  })
+
+  it('should have requirements failing for tic', function() {
+    // tic has been cleaned up, since its identity has expired after the root block
+    return expectError(404, 'No identity matching this pubkey or uid', rp('http://127.0.0.1:8560/wot/requirements/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', { json: true }));
+  });
+
+  it('should have requirements failing for toc', function() {
+    return expectAnswer(rp('http://127.0.0.1:8560/wot/requirements/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', { json: true }), (res:HttpRequirements) => {
+      res.should.have.property('identities').length(1);
+      res.identities[0].should.have.property('pubkey').equal('DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo');
+      res.identities[0].should.have.property('uid').equal('toc');
+      res.identities[0].should.have.property('expired').equal(false);
+    });
+  });
+
+  it('should have requirements failing for toc', async () => {
+    // tic has been cleaned up after the block#2
+    await s1.commit({
+      time: now + 5
+    });
+    return expectError(404, 'No identity matching this pubkey or uid', rp('http://127.0.0.1:8560/wot/requirements/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', { json: true }));
+  })
+});
diff --git a/test/integration/identity-kicking.js b/test/integration/identity/identity-kicking.ts
similarity index 53%
rename from test/integration/identity-kicking.js
rename to test/integration/identity/identity-kicking.ts
index 7d1b024b8ce8ffdc149197477f8c4d5b66a09051..aaede1f7e6a092ced0fe0be1ba4942091de9fc03 100644
--- a/test/integration/identity-kicking.js
+++ b/test/integration/identity/identity-kicking.ts
@@ -11,19 +11,17 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {HttpRequirements} from "../../../app/modules/bma/lib/dtos"
+import {BmaDependency} from "../../../app/modules/bma/index"
+import {NewTestingServer, TestingServer} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
+import {ProverDependency} from "../../../app/modules/prover/index"
 
-const _         = require('underscore');
-const co        = require('co');
 const should    = require('should');
-const duniter   = require('../../index');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const TestUser  = require('./tools/TestUser').TestUser
-const constants = require('../../app/lib/constants');
 const rp        = require('request-promise');
-const httpTest  = require('./tools/http');
-const commit    = require('./tools/commit');
-const shutDownEngine  = require('./tools/shutDownEngine');
+const httpTest  = require('../tools/http');
+const shutDownEngine  = require('../tools/shutDownEngine');
 
 const expectAnswer   = httpTest.expectAnswer;
 
@@ -39,70 +37,65 @@ const commonConf = {
   sigQty: 1
 };
 
-let s1, cat, tac, toc
-
-const commitS1 = (opts) => commit(s1)(opts)
+let s1:TestingServer, cat:TestUser, tac:TestUser, toc:TestUser
 
 describe("Identities kicking", function() {
 
-  before(function() {
-
-    return co(function *() {
-
-      s1 = duniter(
-        '/bb11',
-        MEMORY_MODE,
-        _.extend({
-          port: '8561',
-          pair: {
-            pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
-            sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
-          }
-        }, commonConf));
-
-      cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-      tac = new TestUser('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
-      toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
-
-      const now = 1400000000
-      yield s1.initWithDAL().then(bma).then((bmapi) => bmapi.openConnections());
-      require('../../app/modules/prover').ProverDependency.duniter.methods.hookServer(s1);
-      yield cat.createIdentity();
-      yield tac.createIdentity();
-      yield cat.cert(tac);
-      yield tac.cert(cat);
-      yield cat.join();
-      yield tac.join();
-      yield commitS1({
-        time: now
-      });
-      yield commitS1({
-        time: now + 2000
-      });
-      yield commitS1({
-        time: now + 2000
-      });
-      // Update their membership
-      yield cat.join();
-      yield tac.join();
-      // toc joins thereafter
-      yield toc.createIdentity();
-      yield toc.join();
-      yield cat.cert(toc);
-      yield tac.cert(toc);
-      yield commitS1({
-        time: now + 2000
-      });
-      yield toc.cert(cat);
-      yield commitS1({
-        time: now + 5000
-      });
-      yield commitS1({
-        time: now + 5000
-      });
-      yield commitS1({
-        time: now + 5000
-      });
+  before(async () => {
+
+    s1 = NewTestingServer(
+      Underscore.extend({
+        name: 'bb11',
+        memory: MEMORY_MODE,
+        port: '8561',
+        pair: {
+          pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
+          sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
+        }
+      }, commonConf));
+
+    cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
+    tac = new TestUser('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
+    toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
+
+    const now = 1400000000
+    await s1.initWithDAL().then(BmaDependency.duniter.methods.bma).then((bmapi) => bmapi.openConnections());
+    ProverDependency.duniter.methods.hookServer(s1._server)
+    await cat.createIdentity();
+    await tac.createIdentity();
+    await cat.cert(tac);
+    await tac.cert(cat);
+    await cat.join();
+    await tac.join();
+    await s1.commit({
+      time: now
+    });
+    await s1.commit({
+      time: now + 2000
+    });
+    await s1.commit({
+      time: now + 2000
+    });
+    // Update their membership
+    await cat.join();
+    await tac.join();
+    // toc joins thereafter
+    await toc.createIdentity();
+    await toc.join();
+    await cat.cert(toc);
+    await tac.cert(toc);
+    await s1.commit({
+      time: now + 2000
+    });
+    await toc.cert(cat);
+    await s1.commit({
+      time: now + 5000
+    });
+    await s1.commit({
+      time: now + 5000
+    });
+    await s1.commit({
+      time: now + 5000
     });
   });
 
@@ -117,7 +110,7 @@ describe("Identities kicking", function() {
    */
 
   it('membershipExpiresIn should be positive for cat (actualized member)', function() {
-    return expectAnswer(rp('http://127.0.0.1:8561/wot/requirements/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { json: true }), (res) => {
+    return expectAnswer(rp('http://127.0.0.1:8561/wot/requirements/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { json: true }), (res:HttpRequirements) => {
       res.should.have.property('identities').length(1);
       res.identities[0].should.have.property('pubkey').equal('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
       res.identities[0].should.have.property('uid').equal('cat');
@@ -127,7 +120,7 @@ describe("Identities kicking", function() {
   });
 
   it('membershipExpiresIn should be positive for toc (member)', function() {
-    return expectAnswer(rp('http://127.0.0.1:8561/wot/requirements/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', { json: true }), (res) => {
+    return expectAnswer(rp('http://127.0.0.1:8561/wot/requirements/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', { json: true }), (res:HttpRequirements) => {
       res.should.have.property('identities').length(1);
       res.identities[0].should.have.property('pubkey').equal('DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo');
       res.identities[0].should.have.property('uid').equal('toc');
@@ -137,7 +130,7 @@ describe("Identities kicking", function() {
   });
 
   it('membershipExpiresIn should equal 0 for a kicked member', function() {
-    return expectAnswer(rp('http://127.0.0.1:8561/wot/requirements/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { json: true }), (res) => {
+    return expectAnswer(rp('http://127.0.0.1:8561/wot/requirements/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { json: true }), (res:HttpRequirements) => {
       res.should.have.property('identities').length(1);
       res.identities[0].should.have.property('pubkey').equal('2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc');
       res.identities[0].should.have.property('uid').equal('tac');
diff --git a/test/integration/lookup.js b/test/integration/identity/identity-lookup.ts
similarity index 80%
rename from test/integration/lookup.js
rename to test/integration/identity/identity-lookup.ts
index 39d776da2fa8c13a03fbc90ed9c068a326ef9f95..c893fb9f8edffe4eec08fe579e12aadd78ca97e2 100644
--- a/test/integration/lookup.js
+++ b/test/integration/identity/identity-lookup.ts
@@ -11,16 +11,15 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {NewTestingServer, TestingServer} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
+import {BmaDependency} from "../../../app/modules/bma/index"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
+import {HttpLookup, HttpMemberships} from "../../../app/modules/bma/lib/dtos"
 
-const _         = require('underscore');
-const co        = require('co');
-const duniter     = require('../../index');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const TestUser  = require('./tools/TestUser').TestUser
 const rp        = require('request-promise');
-const httpTest  = require('./tools/http');
-const shutDownEngine  = require('./tools/shutDownEngine');
+const httpTest  = require('../tools/http');
+const shutDownEngine  = require('../tools/shutDownEngine');
 
 const MEMORY_MODE = true;
 const commonConf = {
@@ -28,16 +27,16 @@ const commonConf = {
   currency: 'bb'
 };
 
-let s1, cat, tic1, tic2
+let s1:TestingServer, cat:TestUser, tic1:TestUser, tic2:TestUser
 
 describe("Lookup identity grouping", () => {
 
-  before(() => co(function *() {
+  before(async () => {
 
-    s1 = duniter(
-      'bb12',
-      MEMORY_MODE,
-      _.extend({
+    s1 = NewTestingServer(
+      Underscore.extend({
+        name: 'bb12',
+        memory: MEMORY_MODE,
         port: '4452',
         pair: {
           pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
@@ -50,22 +49,22 @@ describe("Lookup identity grouping", () => {
     tic2 = new TestUser('tic2', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
 
     // Server initialization
-    yield s1.initWithDAL().then(bma).then((bmapi) => bmapi.openConnections());
+    await s1.initWithDAL().then(BmaDependency.duniter.methods.bma).then((bmapi) => bmapi.openConnections());
 
     // cat is publishing its identity, no problem
-    yield cat.createIdentity();
+    await cat.createIdentity();
 
     // tic1 is publishing its identity
-    yield tic1.createIdentity();
+    await tic1.createIdentity();
 
     // tic2 is publishing its identity, but he has **the same pubkey as tic1**.
     // This is OK on the protocol side, but the lookup should group the 2 identities
     // under the same pubkey
-    yield tic2.createIdentity();
+    await tic2.createIdentity();
 
-    yield cat.join();
-    yield tic1.join();
-  }));
+    await cat.join();
+    await tic1.join();
+  })
 
   after(() => {
     return Promise.all([
@@ -73,7 +72,7 @@ describe("Lookup identity grouping", () => {
     ])
   })
 
-  it('cat should have only 1 identity in 1 pubkey', () => httpTest.expectAnswer(rp('http://127.0.0.1:4452/wot/lookup/cat', { json: true }), (res) => {
+  it('cat should have only 1 identity in 1 pubkey', () => httpTest.expectAnswer(rp('http://127.0.0.1:4452/wot/lookup/cat', { json: true }), (res:HttpLookup) => {
     res.should.have.property('results').length(1);
     // cat pubkey
     res.results[0].should.have.property('pubkey').equal('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
@@ -83,7 +82,7 @@ describe("Lookup identity grouping", () => {
     res.results[0].uids[0].should.have.property('uid').equal('cat');
   }));
 
-  it('tic should have only 2 identities in 1 pubkey', () => httpTest.expectAnswer(rp('http://127.0.0.1:4452/wot/lookup/tic', { json: true }), (res) => {
+  it('tic should have only 2 identities in 1 pubkey', () => httpTest.expectAnswer(rp('http://127.0.0.1:4452/wot/lookup/tic', { json: true }), (res:HttpLookup) => {
     // We want to have only 1 result for the 2 identities
     res.should.have.property('results').length(1);
     // because they share the same pubkey
@@ -96,7 +95,7 @@ describe("Lookup identity grouping", () => {
     res.results[0].uids[1].should.have.property('uid').equal('tic2');
   }));
 
-  it('should exist 2 pending memberships', () => httpTest.expectAnswer(rp('http://127.0.0.1:4452/wot/pending', { json: true }), (res) => {
+  it('should exist 2 pending memberships', () => httpTest.expectAnswer(rp('http://127.0.0.1:4452/wot/pending', { json: true }), (res:HttpMemberships) => {
     res.should.have.property('memberships').length(2);
     res.memberships[0].should.have.property('pubkey').equal('DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV');
     res.memberships[0].should.have.property('uid').equal('tic1');
diff --git a/test/integration/identity-pulling.js b/test/integration/identity/identity-pulling.ts
similarity index 69%
rename from test/integration/identity-pulling.js
rename to test/integration/identity/identity-pulling.ts
index 8d3058b125856cfadedd0e9eb15eb775f15355bb..6e3640348321b9a034509c8f911ebf6fe44a478d 100644
--- a/test/integration/identity-pulling.js
+++ b/test/integration/identity/identity-pulling.ts
@@ -11,28 +11,27 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {NewTestingServer, TestingServer} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
+import {HttpRequirements} from "../../../app/modules/bma/lib/dtos"
+import {CrawlerDependency} from "../../../app/modules/crawler/index"
 
-const _ = require('underscore');
-const co        = require('co');
 const assert    = require('assert');
-const TestUser  = require('./tools/TestUser').TestUser
-const commit    = require('./tools/commit');
-const toolbox   = require('./tools/toolbox');
 
-let s1, s2, cat1, tac1, toc2, tic2, tuc2
+let s1:TestingServer, s2:TestingServer, cat1:TestUser, tac1:TestUser, toc2:TestUser, tic2:TestUser, tuc2:TestUser
 
 describe("Identity pulling", function() {
 
-  before(() => co(function*() {
+  before(async () => {
 
-    s1 = toolbox.server({
+    s1 = NewTestingServer({
       pair: {
         pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
         sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
       }
     });
-    s2 = toolbox.server({
+    s2 = NewTestingServer({
       pair: {
         pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc',
         sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'
@@ -45,17 +44,17 @@ describe("Identity pulling", function() {
     tic2 = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s2 });
     tuc2 = new TestUser('tuc', { pub: '3conGDUXdrTGbQPMQQhEC4Ubu1MCAnFrAYvUaewbUhtk', sec: '5ks7qQ8Fpkin7ycXpxQSxxjVhs8VTzpM3vEBMqM7NfC1ZiFJ93uQryDcoM93Mj77T6hDAABdeHZJDFnkDb35bgiU'}, { server: s2 });
 
-    yield s1.prepareForNetwork();
-    yield s2.prepareForNetwork();
+    await s1.prepareForNetwork();
+    await s2.prepareForNetwork();
 
     // Publishing identities
-    yield cat1.createIdentity();
-    yield tac1.createIdentity();
-    yield cat1.cert(tac1);
-    yield tac1.cert(cat1);
-    yield cat1.join();
-    yield tac1.join();
-  }));
+    await cat1.createIdentity();
+    await tac1.createIdentity();
+    await cat1.cert(tac1);
+    await tac1.cert(cat1);
+    await cat1.join();
+    await tac1.join();
+  })
 
   after(() => {
     return Promise.all([
@@ -64,48 +63,48 @@ describe("Identity pulling", function() {
     ])
   })
 
-  it('toc, tic and tuc can create their account on s2', () => co(function*() {
-    yield toc2.createIdentity();
-    yield tic2.createIdentity();
-    yield tuc2.createIdentity();
-    yield toc2.join();
-    yield tic2.join();
-    yield tuc2.join();
+  it('toc, tic and tuc can create their account on s2', async () => {
+    await toc2.createIdentity();
+    await tic2.createIdentity();
+    await tuc2.createIdentity();
+    await toc2.join();
+    await tic2.join();
+    await tuc2.join();
     // 2 certs for toc
-    yield cat1.cert(toc2, s2, s2);
-    yield tac1.cert(toc2, s2, s2);
+    await cat1.cert(toc2, s2, s2);
+    await tac1.cert(toc2, s2, s2);
     // 1 certs for tic
-    yield cat1.cert(tic2, s2, s2);
+    await cat1.cert(tic2, s2, s2);
     // 0 certs for tuc
 
     // tic2 also revokes its pending identity
-    yield tic2.revoke()
-  }));
+    await tic2.revoke()
+  })
 
-  it('toc should not be known of s1', () => co(function*() {
-    yield s1.expectError('/wot/lookup/toc', 404)
-  }));
+  it('toc should not be known of s1', async () => {
+    await s1.expectError('/wot/lookup/toc', 404)
+  })
 
-  it('tic should not be known of s1', () => co(function*() {
-    yield s1.expectError('/wot/lookup/tic', 404)
-  }));
+  it('tic should not be known of s1', async () => {
+    await s1.expectError('/wot/lookup/tic', 404)
+  })
 
-  it('tuc should not be known of s1', () => co(function*() {
-    yield s1.expectError('/wot/lookup/tuc', 404)
-  }));
+  it('tuc should not be known of s1', async () => {
+    await s1.expectError('/wot/lookup/tuc', 404)
+  })
 
-  it('toc should have 2 certs on server2', () => co(function*() {
-    yield s2.expectThat('/wot/requirements-of-pending/2', (json) => {
+  it('toc should have 2 certs on server2', async () => {
+    await s2.expectThat('/wot/requirements-of-pending/2', (json:HttpRequirements) => {
       assert.equal(json.identities.length, 1)
       assert.equal(json.identities[0].pubkey, 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo')
       assert.equal(json.identities[0].uid, 'toc')
       assert.equal(json.identities[0].pendingCerts.length, 2)
       assert.equal(json.identities[0].pendingMemberships.length, 1)
     })
-  }));
+  })
 
-  it('tic should have 1 certs on server2', () => co(function*() {
-    yield s2.expectThat('/wot/requirements-of-pending/1', (json) => {
+  it('tic should have 1 certs on server2', async () => {
+    await s2.expectThat('/wot/requirements-of-pending/1', (json:HttpRequirements) => {
       assert.equal(json.identities.length, 2)
 
       assert.equal(json.identities[1].pubkey, 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV')
@@ -118,18 +117,18 @@ describe("Identity pulling", function() {
       assert.equal(json.identities[0].pendingCerts.length, 2)
       assert.equal(json.identities[0].pendingMemberships.length, 1)
     })
-  }));
+  })
 
-  it('s1 should be able to pull sandbox data from s2', () => co(function*() {
+  it('s1 should be able to pull sandbox data from s2', async () => {
 
-    yield s2.sharePeeringWith(s1)
-    const pullSandbox = require('../../app/modules/crawler').CrawlerDependency.duniter.methods.pullSandbox
-    yield pullSandbox(s1)
-    yield pullSandbox(s1)
+    await s2.sharePeeringWith(s1)
+    const pullSandbox = CrawlerDependency.duniter.methods.pullSandbox
+    await pullSandbox(s1._server)
+    await pullSandbox(s1._server)
 
-    yield s1.expectThat('/wot/requirements-of-pending/1', (json) => {
+    await s1.expectThat('/wot/requirements-of-pending/1', (json:HttpRequirements) => {
 
-      json.identities = _.sortBy(json.identities, 'pubkey')
+      json.identities = Underscore.sortBy(json.identities, 'pubkey')
       assert.equal(json.identities.length, 4)
 
       assert.equal(json.identities[3].pubkey, 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd')
@@ -156,6 +155,6 @@ describe("Identity pulling", function() {
       assert.equal(json.identities[1].pendingCerts.length, 2)
       assert.equal(json.identities[1].pendingMemberships.length, 1)
     })
-  }));
+  })
 
-});
+})
diff --git a/test/integration/revocation-test.js b/test/integration/identity/identity-revocation-test.ts
similarity index 55%
rename from test/integration/revocation-test.js
rename to test/integration/identity/identity-revocation-test.ts
index c0a62ae78262f77cabc2ad10da6520267125a316..1a60685f1ca9e2343bb229e07d6d88868350dbb7 100644
--- a/test/integration/revocation-test.js
+++ b/test/integration/identity/identity-revocation-test.ts
@@ -13,20 +13,20 @@
 
 "use strict";
 
-const _         = require('underscore');
-const co        = require('co');
+import {NewTestingServer, TestingServer} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
+import {BmaDependency} from "../../../app/modules/bma/index"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
+import {HttpLookup, HttpMembers} from "../../../app/modules/bma/lib/dtos"
+
 const should    = require('should');
-const duniter   = require('../../index');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const TestUser  = require('./tools/TestUser').TestUser
 const rp        = require('request-promise');
-const httpTest  = require('./tools/http');
-const commit    = require('./tools/commit');
-const shutDownEngine  = require('./tools/shutDownEngine');
+const httpTest  = require('../tools/http');
+const shutDownEngine  = require('../tools/shutDownEngine');
 
 const expectAnswer  = httpTest.expectAnswer;
 
-require('../../app/modules/bma').BmaDependency.duniter.methods.noLimit(); // Disables the HTTP limiter
+BmaDependency.duniter.methods.noLimit(); // Disables the HTTP limiter
 
 const MEMORY_MODE = true;
 const commonConf = {
@@ -40,64 +40,59 @@ const commonConf = {
   avgGenTime: 300
 };
 
-let s1, s2, cat, tic, toc, tacOnS1, tacOnS2
-
-const commitS1 = (opts) => commit(s1)(opts)
+let s1:TestingServer, s2:TestingServer, cat:TestUser, tic:TestUser, toc:TestUser, tacOnS1:TestUser, tacOnS2:TestUser
 
 describe("Revocation", function() {
 
-  before(function() {
-
-    return co(function *() {
-
-      s1 = duniter(
-        '/bb12',
-        MEMORY_MODE,
-        _.extend({
-          port: '9964',
-          pair: {
-            pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo',
-            sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'
-          }
-        }, commonConf));
-
-      s2 = duniter(
-        '/bb13',
-        MEMORY_MODE,
-        _.extend({
-          port: '9965',
-          pair: {
-            pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
-            sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
-          }
-        }, commonConf));
-
-      cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-      tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
-      toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
-      tacOnS1 = new TestUser('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
-      tacOnS2 = new TestUser('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s2 });
-
-      const now = 1400000000
-      yield s1.initWithDAL().then(bma).then((bmapi) => bmapi.openConnections());
-      yield s2.initWithDAL().then(bma).then((bmapi) => bmapi.openConnections());
-      yield cat.createIdentity();
-      yield tic.createIdentity();
-      yield toc.createIdentity();
-      yield cat.cert(tic);
-      yield tic.cert(cat);
-      yield tic.cert(toc);
-      yield toc.cert(tic);
-      yield cat.join();
-      yield tic.join();
-      yield toc.join();
-      yield commitS1({ time: now });
-
-      // We have the following WoT:
-      /**
-       *  cat <-> tic <-> toc
-       */
-    });
+  before(async () => {
+
+    s1 = NewTestingServer(
+      Underscore.extend({
+        name: 'bb12',
+        memory: MEMORY_MODE,
+        port: '9964',
+        pair: {
+          pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo',
+          sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'
+        }
+      }, commonConf));
+
+    s2 = NewTestingServer(
+      Underscore.extend({
+        name: 'bb13',
+        memory: MEMORY_MODE,
+        port: '9965',
+        pair: {
+          pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
+          sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
+        }
+      }, commonConf));
+
+    cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
+    tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
+    toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
+    tacOnS1 = new TestUser('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
+    tacOnS2 = new TestUser('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s2 });
+
+    const now = 1400000000
+    await s1.initWithDAL().then(BmaDependency.duniter.methods.bma).then((bmapi) => bmapi.openConnections());
+    await s2.initWithDAL().then(BmaDependency.duniter.methods.bma).then((bmapi) => bmapi.openConnections());
+    await cat.createIdentity();
+    await tic.createIdentity();
+    await toc.createIdentity();
+    await cat.cert(tic);
+    await tic.cert(cat);
+    await tic.cert(toc);
+    await toc.cert(tic);
+    await cat.join();
+    await tic.join();
+    await toc.join();
+    await s1.commit({ time: now });
+
+    // We have the following WoT:
+    /**
+     *  cat <-> tic <-> toc
+     */
   });
 
   after(() => {
@@ -108,13 +103,13 @@ describe("Revocation", function() {
   })
 
   it('should have 3 members', function() {
-    return expectAnswer(rp('http://127.0.0.1:9964/wot/members', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:9964/wot/members', { json: true }), function(res:HttpMembers) {
       res.should.have.property('results').length(3);
-      _.pluck(res.results, 'uid').sort().should.deepEqual(['cat', 'tic', 'toc']);
+      Underscore.pluck(res.results, 'uid').sort().should.deepEqual(['cat', 'tic', 'toc']);
     });
   });
 
-  it('cat should not be revoked yet', () => expectAnswer(rp('http://127.0.0.1:9964/wot/lookup/cat', { json: true }), function(res) {
+  it('cat should not be revoked yet', () => expectAnswer(rp('http://127.0.0.1:9964/wot/lookup/cat', { json: true }), function(res:HttpLookup) {
     res.should.have.property('results').length(1);
     res.results[0].should.have.property('uids').length(1);
     res.results[0].uids[0].should.have.property('uid').equal('cat');
@@ -123,9 +118,9 @@ describe("Revocation", function() {
     res.results[0].uids[0].should.have.property('revocation_sig').equal(null);
   }));
 
-  it('sending a revocation for cat should be displayed', () => co(function *() {
-    yield cat.revoke();
-    return expectAnswer(rp('http://127.0.0.1:9964/wot/lookup/cat', { json: true }), function(res) {
+  it('sending a revocation for cat should be displayed', async () => {
+    await cat.revoke();
+    return expectAnswer(rp('http://127.0.0.1:9964/wot/lookup/cat', { json: true }), function(res:HttpLookup) {
       res.should.have.property('results').length(1);
       res.results[0].should.have.property('uids').length(1);
       res.results[0].uids[0].should.have.property('uid').equal('cat');
@@ -134,14 +129,14 @@ describe("Revocation", function() {
       res.results[0].uids[0].should.have.property('revocation_sig').not.equal(null);
       res.results[0].uids[0].should.have.property('revocation_sig').not.equal('');
     });
-  }));
+  })
 
-  it('sending a revocation for tac should add an identity', () => co(function *() {
-    yield tacOnS1.createIdentity();
-    const idty = yield tacOnS1.lookup(tacOnS1.pub);
-    yield tacOnS2.revoke(idty);
+  it('sending a revocation for tac should add an identity', async () => {
+    await tacOnS1.createIdentity();
+    const idty = await tacOnS1.lookup(tacOnS1.pub);
+    await tacOnS2.revoke(idty);
     // On S1 server, tac is known as normal identity
-    yield expectAnswer(rp('http://127.0.0.1:9964/wot/lookup/tac', { json: true }), function(res) {
+    await expectAnswer(rp('http://127.0.0.1:9964/wot/lookup/tac', { json: true }), function(res:HttpLookup) {
       res.should.have.property('results').length(1);
       res.results[0].should.have.property('uids').length(1);
       res.results[0].uids[0].should.have.property('uid').equal('tac');
@@ -150,7 +145,7 @@ describe("Revocation", function() {
       res.results[0].uids[0].should.have.property('revocation_sig').equal(null);
     });
     // On S2 server, tac is known as identity with revocation pending (not written! so `revoked` field is false)
-    yield expectAnswer(rp('http://127.0.0.1:9965/wot/lookup/tac', { json: true }), function(res) {
+    await expectAnswer(rp('http://127.0.0.1:9965/wot/lookup/tac', { json: true }), function(res:HttpLookup) {
       res.should.have.property('results').length(1);
       res.results[0].should.have.property('uids').length(1);
       res.results[0].uids[0].should.have.property('uid').equal('tac');
@@ -159,12 +154,12 @@ describe("Revocation", function() {
       res.results[0].uids[0].should.have.property('revocation_sig').not.equal(null);
       res.results[0].uids[0].should.have.property('revocation_sig').not.equal('');
     });
-  }));
+  })
 
-  it('if we commit a revocation, cat should be revoked', () => co(function *() {
-    yield commitS1({ revoked: [], excluded: [] });
-    yield commitS1();
-    return expectAnswer(rp('http://127.0.0.1:9964/wot/lookup/cat', { json: true }), function(res) {
+  it('if we commit a revocation, cat should be revoked', async () => {
+    await s1.commit({ revoked: [], excluded: [] });
+    await s1.commit();
+    return expectAnswer(rp('http://127.0.0.1:9964/wot/lookup/cat', { json: true }), function(res:HttpLookup) {
       res.should.have.property('results').length(1);
       res.results[0].should.have.property('uids').length(1);
       res.results[0].uids[0].should.have.property('uid').equal('cat');
@@ -173,33 +168,33 @@ describe("Revocation", function() {
       res.results[0].uids[0].should.have.property('revocation_sig').not.equal(null);
       res.results[0].uids[0].should.have.property('revocation_sig').not.equal('');
     });
-  }));
+  })
 
   it('should have 2 members', function() {
-    return expectAnswer(rp('http://127.0.0.1:9964/wot/members', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:9964/wot/members', { json: true }), function(res:HttpMembers) {
       res.should.have.property('results').length(2);
-      _.pluck(res.results, 'uid').sort().should.deepEqual(['tic','toc']);
+      Underscore.pluck(res.results, 'uid').sort().should.deepEqual(['tic','toc']);
     });
   });
 
-  it('cat should not be able to join back', () => co(function *() {
+  it('cat should not be able to join back', async () => {
     try {
-      yield cat.join();
+      await cat.join();
     } catch (e) {
       should.exists(e);
     }
-    yield commitS1();
-    return expectAnswer(rp('http://127.0.0.1:9964/wot/members', { json: true }), function(res) {
+    await s1.commit();
+    return expectAnswer(rp('http://127.0.0.1:9964/wot/members', { json: true }), function(res:HttpMembers) {
       res.should.have.property('results').length(2);
-      _.pluck(res.results, 'uid').sort().should.deepEqual(['tic','toc']);
+      Underscore.pluck(res.results, 'uid').sort().should.deepEqual(['tic','toc']);
     });
-  }));
+  })
 
-  it('if we revert the commit, cat should not be revoked', () => co(function *() {
-    yield s1.revert();
-    yield s1.revert();
-    yield s1.dal.blockDAL.removeForkBlockAboveOrEqual(2)
-    return expectAnswer(rp('http://127.0.0.1:9964/wot/lookup/cat', { json: true }), function(res) {
+  it('if we revert the commit, cat should not be revoked', async () => {
+    await s1.revert();
+    await s1.revert();
+    await s1.dal.blockDAL.removeForkBlockAboveOrEqual(2)
+    return expectAnswer(rp('http://127.0.0.1:9964/wot/lookup/cat', { json: true }), function(res:HttpLookup) {
       res.should.have.property('results').length(1);
       res.results[0].should.have.property('uids').length(1);
       res.results[0].uids[0].should.have.property('uid').equal('cat');
@@ -208,11 +203,11 @@ describe("Revocation", function() {
       res.results[0].uids[0].should.have.property('revocation_sig').equal(null); // We loose the revocation
       res.results[0].uids[0].should.have.property('revocation_sig').equal(null);
     });
-  }));
+  })
 
-  it('if we commit again, cat should NOT be revoked (we have lost the revocation)', () => co(function *() {
-    yield commitS1();
-    return expectAnswer(rp('http://127.0.0.1:9964/wot/lookup/cat', { json: true }), function(res) {
+  it('if we commit again, cat should NOT be revoked (we have lost the revocation)', async () => {
+    await s1.commit();
+    return expectAnswer(rp('http://127.0.0.1:9964/wot/lookup/cat', { json: true }), function(res:HttpLookup) {
       res.should.have.property('results').length(1);
       res.results[0].should.have.property('uids').length(1);
       res.results[0].uids[0].should.have.property('uid').equal('cat');
@@ -221,6 +216,6 @@ describe("Revocation", function() {
       res.results[0].uids[0].should.have.property('revocation_sig').equal(null); // We loose the revocation
       res.results[0].uids[0].should.have.property('revocation_sig').equal(null);
     });
-  }));
+  })
 
-});
+})
diff --git a/test/integration/tests.js b/test/integration/identity/identity-several-tests.ts
similarity index 57%
rename from test/integration/tests.js
rename to test/integration/identity/identity-several-tests.ts
index 3632bfefb5776f5ecb6c96de65427e7c3c80e5d7..316be2f478cee34a2b9daa1e91b6990eb362eda2 100644
--- a/test/integration/tests.js
+++ b/test/integration/identity/identity-several-tests.ts
@@ -11,27 +11,26 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {TestUser} from "../tools/TestUser"
+import {BmaDependency} from "../../../app/modules/bma/index"
+import {HttpBlock, HttpLookup, HttpSigned, HttpSummary} from "../../../app/modules/bma/lib/dtos"
+import {NewTestingServer, TestingServer} from "../tools/toolbox"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
 
-const co = require('co');
-const _ = require('underscore');
 const should = require('should');
 const assert = require('assert');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const constants = require('../../app/lib/constants');
-const node   = require('./tools/node');
-const duniter     = require('../../index');
-const TestUser = require('./tools/TestUser').TestUser
-const jspckg = require('../../package');
-const commit    = require('./tools/commit');
-const httpTest  = require('./tools/http');
-const shutDownEngine  = require('./tools/shutDownEngine');
+const request = require('request');
+const constants = require('../../../app/lib/constants');
+const node   = require('../tools/node');
+const jspckg = require('../../../package');
+const httpTest  = require('../tools/http');
+const shutDownEngine  = require('../tools/shutDownEngine');
 const rp        = require('request-promise');
 
 const expectAnswer   = httpTest.expectAnswer;
 const MEMORY_MODE = true;
 
-require('../../app/modules/bma').BmaDependency.duniter.methods.noLimit(); // Disables the HTTP limiter
+BmaDependency.duniter.methods.noLimit(); // Disables the HTTP limiter
 
 describe("Integration", function() {
 
@@ -65,7 +64,7 @@ describe("Integration", function() {
       });
       after(node1.after());
 
-      it('/node/summary should give package.json version', node1.summary(function(summary, done){
+      it('/node/summary should give package.json version', node1.summary(function(summary:HttpSummary, done:any){
         should.exists(summary);
         should.exists(summary.duniter);
         should.exists(summary.duniter.software);
@@ -79,7 +78,39 @@ describe("Integration", function() {
     describe("Testing malformed documents", function(){
 
       before(function(done) {
-        node1.before(require('./scenarios/malformed-documents')(node1))(done);
+        node1.before(function(node1) {
+
+          const malformedTransaction = "Version: 2\n" +
+            "Type: Transaction\n" +
+            "Currency: null\n" +
+            "Issuers:\n" +
+            "G2CBgZBPLe6FSFUgpx2Jf1Aqsgta6iib3vmDRA1yLiqU\n" +
+            "Inputs:\n" +
+            "0:T:1536:539CB0E60CD5F55CF1BE96F067E73BF55C052112:1.0\n" +
+            "Outputs:Comment: mon comments\n";
+
+
+          function sendRaw (raw:string) {
+            return function(done:any) {
+              post('/tx/process', {
+                "transaction": raw
+              }, done);
+            }
+          }
+
+          function post(uri:string, data:any, done:any) {
+            const postReq = request.post({
+              "uri": 'http://' + [node1.server.conf.remoteipv4, node1.server.conf.remoteport].join(':') + uri,
+              "timeout": 1000 * 10
+            }, function (err:any, res:any, body:any) {
+              done(err, res, body);
+            });
+            postReq.form(data);
+          }
+          return [
+            sendRaw(malformedTransaction)
+          ];
+        }(node1))(done);
       });
       after(node1.after());
 
@@ -90,54 +121,53 @@ describe("Integration", function() {
 
     describe("Lookup on", function(){
 
-      before(function() {
-        return co(function *() {
+      before(async () => {
 
-          // Self certifications
-          yield cat.createIdentity();
-          yield tac.createIdentity();
-          yield tic.createIdentity();
-          yield toc.createIdentity();
-          // Certifications
-          yield cat.cert(tac);
-        });
+        // Self certifications
+        await cat.createIdentity();
+        await tac.createIdentity();
+        await tic.createIdentity();
+        await toc.createIdentity();
+        // Certifications
+        await cat.cert(tac);
       });
+
       after(node1.after());
 
       describe("identities collisions", () => {
 
-        it("sending same identity should fail", () => co(function *() {
+        it("sending same identity should fail", async () => {
 
           // We send again the same
           try {
-            yield tic.createIdentity();
+            await tic.createIdentity();
             throw 'Should have thrown an error';
           } catch (e) {
             JSON.parse(e).ucode.should.equal(constants.ERRORS.ALREADY_UP_TO_DATE.uerr.ucode);
           }
-        }));
+        })
 
-        it("sending same identity (again) should fail", () => co(function *() {
+        it("sending same identity (again) should fail", async () => {
 
           // We send again the same
           try {
-            yield tic.createIdentity();
+            await tic.createIdentity();
             throw 'Should have thrown an error';
           } catch (e) {
             JSON.parse(e).ucode.should.equal(constants.ERRORS.ALREADY_UP_TO_DATE.uerr.ucode);
           }
-        }));
+        })
       });
 
       describe("user cat", function(){
 
-        it('should give only 1 result', node1.lookup('cat', function(res, done){
+        it('should give only 1 result', node1.lookup('cat', function(res:HttpLookup, done:any){
           should.exists(res);
           assert.equal(res.results.length, 1);
           done();
         }));
 
-        it('should have sent 1 signature', node1.lookup('cat', function(res, done){
+        it('should have sent 1 signature', node1.lookup('cat', function(res:HttpLookup, done:any){
           should.exists(res);
           assert.equal(res.results[0].signed.length, 1);
           should.exists(res.results[0].signed[0].isMember);
@@ -150,32 +180,32 @@ describe("Integration", function() {
 
       describe("user tac", function(){
 
-        it('should give only 1 result', node1.lookup('tac', function(res, done){
+        it('should give only 1 result', node1.lookup('tac', function(res:HttpLookup, done:any){
           should.exists(res);
           assert.equal(res.results.length, 1);
           done();
         }));
 
-        it('should have 1 signature', node1.lookup('tac', function(res, done){
+        it('should have 1 signature', node1.lookup('tac', function(res:HttpLookup, done:any){
           should.exists(res);
           assert.equal(res.results[0].uids[0].others.length, 1);
           done();
         }));
 
-        it('should have sent 0 signature', node1.lookup('tac', function(res, done){
+        it('should have sent 0 signature', node1.lookup('tac', function(res:HttpLookup, done:any){
           should.exists(res);
           assert.equal(res.results[0].signed.length, 0);
           done();
         }));
       });
 
-      it('toc should give only 1 result', node1.lookup('toc', function(res, done){
+      it('toc should give only 1 result', node1.lookup('toc', function(res:HttpLookup, done:any){
         should.exists(res);
         assert.equal(res.results.length, 1);
         done();
       }));
 
-      it('tic should give only 1 result', node1.lookup('tic', function(res, done){
+      it('tic should give only 1 result', node1.lookup('tic', function(res:HttpLookup, done:any){
         should.exists(res);
         assert.equal(res.results.length, 1);
         done();
@@ -185,69 +215,69 @@ describe("Integration", function() {
 
   describe("Testing leavers", function(){
 
-    let node3, cat, tac, tic, toc
-
-    before(function() {
-      return co(function *() {
-
-        node3 = duniter('/db3', MEMORY_MODE, {
-          currency: 'dd', ipv4: 'localhost', port: 9997, remoteipv4: 'localhost', remoteport: 9997, httplogs: false,
-          rootoffset: 0,
-          sigQty: 1, sigPeriod: 0,
-          pair: {
-            pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
-            sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
-          }
-        });
+    let node3:TestingServer, cat:TestUser, tac:TestUser, tic:TestUser, toc:TestUser
 
-        cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: node3 });
-        tac = new TestUser('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: node3 });
-        tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: node3 });
-        toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: node3 });
+    before(async () => {
 
-        yield node3.initWithDAL().then(bma).then((bmapi) => bmapi.openConnections());
-        const now = 1482220000;
+      node3 = NewTestingServer({
+        name: 'db3',
+        memory: MEMORY_MODE,
+        currency: 'dd', ipv4: 'localhost', port: 9997, remoteipv4: 'localhost', remoteport: 9997, httplogs: false,
+        rootoffset: 0,
+        sigQty: 1, sigPeriod: 0,
+        pair: {
+          pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
+          sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
+        }
+      });
 
-        // Self certifications
-        yield cat.createIdentity();
-        yield tac.createIdentity();
-        yield tic.createIdentity();
-        yield toc.createIdentity();
-        yield cat.cert(tac);
-        yield cat.cert(tic);
-        yield cat.cert(toc);
-        yield tac.cert(cat);
-        yield tac.cert(tic);
-        yield tic.cert(cat);
-        yield tic.cert(tac);
-        yield toc.cert(cat);
-        yield cat.join();
-        yield tac.join();
-        yield tic.join();
-        yield toc.join();
-        yield commit(node3)({
-          time: now
-        });
-        yield commit(node3)({
-          time: now
-        });
-        yield toc.leave();
-        yield commit(node3)({
-          time: now
-        });
-        yield tac.cert(toc);
-        yield tic.cert(toc);
-        yield toc.cert(tic); // Should be taken in 1 block
-        yield toc.cert(tac); // Should be taken in 1 other block
-        yield commit(node3)({
-          time: now + 200
-        });
-        yield commit(node3)({
-          time: now + 200
-        });
-        yield commit(node3)({
-          time: now + 200
-        });
+      cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: node3 });
+      tac = new TestUser('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: node3 });
+      tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: node3 });
+      toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: node3 });
+
+      await node3.initWithDAL().then(BmaDependency.duniter.methods.bma).then((bmapi) => bmapi.openConnections());
+      const now = 1482220000;
+
+      // Self certifications
+      await cat.createIdentity();
+      await tac.createIdentity();
+      await tic.createIdentity();
+      await toc.createIdentity();
+      await cat.cert(tac);
+      await cat.cert(tic);
+      await cat.cert(toc);
+      await tac.cert(cat);
+      await tac.cert(tic);
+      await tic.cert(cat);
+      await tic.cert(tac);
+      await toc.cert(cat);
+      await cat.join();
+      await tac.join();
+      await tic.join();
+      await toc.join();
+      await node3.commit({
+        time: now
+      });
+      await node3.commit({
+        time: now
+      });
+      await toc.leave();
+      await node3.commit({
+        time: now
+      });
+      await tac.cert(toc);
+      await tic.cert(toc);
+      await toc.cert(tic); // Should be taken in 1 block
+      await toc.cert(tac); // Should be taken in 1 other block
+      await node3.commit({
+        time: now + 200
+      });
+      await node3.commit({
+        time: now + 200
+      });
+      await node3.commit({
+        time: now + 200
       });
     });
 
@@ -257,24 +287,24 @@ describe("Integration", function() {
       ])
     })
 
-    it('toc should give only 1 result with 3 certification by others', () => expectAnswer(rp('http://127.0.0.1:9997/wot/lookup/toc', { json: true }), function(res) {
+    it('toc should give only 1 result with 3 certification by others', () => expectAnswer(rp('http://127.0.0.1:9997/wot/lookup/toc', { json: true }), function(res:HttpLookup) {
       should.exists(res);
       assert.equal(res.results.length, 1);
       assert.equal(res.results[0].uids[0].others.length, 3);
     }));
 
-    it('tic should give only 1 results', () => expectAnswer(rp('http://127.0.0.1:9997/wot/lookup/tic', { json: true }), function(res) {
+    it('tic should give only 1 results', () => expectAnswer(rp('http://127.0.0.1:9997/wot/lookup/tic', { json: true }), function(res:HttpLookup) {
       should.exists(res);
-      const uids = _.pluck(res.results[0].signed, 'uid');
+      const uids = Underscore.pluck(res.results[0].signed, 'uid');
       const uidsShould = ["cat", "tac", "toc"];
       uids.sort();
       uidsShould.sort();
       assert.deepEqual(uids, uidsShould);
       assert.equal(res.results.length, 1);
       assert.equal(res.results[0].signed.length, 3);
-      const cat_signed = _.findWhere(res.results[0].signed, { uid: 'cat'});
-      const tac_signed = _.findWhere(res.results[0].signed, { uid: 'tac'});
-      const toc_signed = _.findWhere(res.results[0].signed, { uid: 'toc'});
+      const cat_signed = Underscore.findWhere(res.results[0].signed, { uid: 'cat'}) as HttpSigned
+      const tac_signed = Underscore.findWhere(res.results[0].signed, { uid: 'tac'}) as HttpSigned
+      const toc_signed = Underscore.findWhere(res.results[0].signed, { uid: 'toc'}) as HttpSigned
       assert.equal(cat_signed.uid, "cat");
       assert.equal(cat_signed.isMember, true);
       assert.equal(cat_signed.wasMember, true);
@@ -290,7 +320,7 @@ describe("Integration", function() {
       assert.equal(res.results[0].uids[0].others[0].wasMember, true);
     }));
 
-    it('it should exist block#2 with 4 members', () => expectAnswer(rp('http://127.0.0.1:9997/blockchain/block/2', { json: true }), function(block) {
+    it('it should exist block#2 with 4 members', () => expectAnswer(rp('http://127.0.0.1:9997/blockchain/block/2', { json: true }), function(block:HttpBlock) {
       should.exists(block);
       assert.equal(block.number, 2);
       assert.equal(block.membersCount, 4);
@@ -303,8 +333,8 @@ describe("Integration", function() {
     blockShouldHaveCerts(4, 1);
     blockShouldHaveCerts(5, 0);
 
-    function blockShouldHaveCerts(number, certificationsCount) {
-      it('it should exist block#' + number + ' with ' + certificationsCount + ' certification', () => expectAnswer(rp('http://127.0.0.1:9997/blockchain/block/' + number, { json: true }), function(block) {
+    function blockShouldHaveCerts(number:number, certificationsCount:number) {
+      it('it should exist block#' + number + ' with ' + certificationsCount + ' certification', () => expectAnswer(rp('http://127.0.0.1:9997/blockchain/block/' + number, { json: true }), function(block:HttpBlock) {
         should.exists(block);
         assert.equal(block.number, number);
         assert.equal(block.certifications.length, certificationsCount);
diff --git a/test/integration/identity-test.js b/test/integration/identity/identity-test.ts
similarity index 83%
rename from test/integration/identity-test.js
rename to test/integration/identity/identity-test.ts
index ec434a0d0bccd9e385921f1feaeb918ac42519a4..7580016c48cbc245e3d867688752d9e624f46d6c 100644
--- a/test/integration/identity-test.js
+++ b/test/integration/identity/identity-test.ts
@@ -11,21 +11,26 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {NewTestingServer, TestingServer} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
+import {BmaDependency} from "../../../app/modules/bma/index"
+import {
+  HttpCertifications,
+  HttpIdentity,
+  HttpMembers,
+  HttpMemberships,
+  HttpRequirements
+} from "../../../app/modules/bma/lib/dtos"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
+import {ProverDependency} from "../../../app/modules/prover/index"
 
-const _         = require('underscore');
-const co        = require('co');
 const should    = require('should');
-const duniter     = require('../../index');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const TestUser  = require('./tools/TestUser').TestUser
-const constants = require('../../app/lib/constants');
+const constants = require('../../../app/lib/constants');
 const rp        = require('request-promise');
-const httpTest  = require('./tools/http');
-const commit    = require('./tools/commit');
-const shutDownEngine  = require('./tools/shutDownEngine');
+const httpTest  = require('../tools/http');
+const shutDownEngine  = require('../tools/shutDownEngine');
 
-require('../../app/modules/bma').BmaDependency.duniter.methods.noLimit(); // Disables the HTTP limiter
+BmaDependency.duniter.methods.noLimit(); // Disables the HTTP limiter
 
 const expectAnswer   = httpTest.expectAnswer;
 
@@ -40,16 +45,16 @@ const commonConf = {
   sigQty: 1
 };
 
-let s1, cat, tac, tic, toc, tic2, man1, man2, man3
+let s1:TestingServer, cat:TestUser, tac:TestUser, tic:TestUser, toc:TestUser, tic2:TestUser, man1:TestUser, man2:TestUser, man3:TestUser
 
 describe("Identities collision", function() {
 
-  before(function() {
+  before(async () => {
 
-    s1 = duniter(
-      '/bb11',
-      MEMORY_MODE,
-      _.extend({
+    s1 = NewTestingServer(
+      Underscore.extend({
+        name: 'bb11',
+        memory: MEMORY_MODE,
         port: '7799',
         pair: {
           pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
@@ -66,67 +71,63 @@ describe("Identities collision", function() {
     man2 = new TestUser('man2', { pub: 'E44RxG9jKZQsaPLFSw2ZTJgW7AVRqo1NGy6KGLbKgtNm', sec: 'pJRwpaCWshKZNWsbDxAHFQbVjk6X8gz9eBy9jaLnVY9gUZRqotrZLZPZe68ag4vEX1Y8mX77NhPXV2hj9F1UkX3'}, { server: s1 });
     man3 = new TestUser('man3', { pub: '5bfpAfZJ4xYspUBYseASJrofhRm6e6JMombt43HBaRzW', sec: '2VFQtEcYZRwjoc8Lxwfzcejtw9VP8VAi47WjwDDjCJCXu7g1tXUAbVZN3QmvG6NJqaSuLCuYP7WDHWkFmTrUEMaE'}, { server: s1 });
 
-    const commitS1 = commit(s1);
-
-    return co(function *() {
-      yield s1.initWithDAL().then(bma).then((bmapi) => bmapi.openConnections());
-      require('../../app/modules/prover').ProverDependency.duniter.methods.hookServer(s1);
-      yield cat.createIdentity();
-      yield tac.createIdentity();
-      yield toc.createIdentity();
-      yield tic.createIdentity();
-      yield toc.cert(cat);
-      yield cat.cert(toc);
-      yield cat.cert(tic);
-      yield tic.cert(tac);
-      yield tic.cert(cat);
-      yield cat.join();
-      yield toc.join();
-      yield tic.join();
-      yield tac.join();
-      yield commitS1();
-      yield commitS1();
-
-      // We have the following WoT (diameter 3):
-
-      /**
-       *  toc <=> cat <=> tic -> tac
-       */
-
-      // cat is the sentry
-
-      // Man1 is someone who just needs a commit to join
-      yield man1.createIdentity();
-      yield man1.join();
-      yield tac.cert(man1);
-
-      /**
-       *  toc <=> cat -> tic -> tac -> man1
-       */
-
-      // Man2 is someone who has no certifications yet has sent a JOIN
-      yield man2.createIdentity();
-      yield man2.join();
-
-      // Man3 is someone who has only published its identity
-      yield man3.createIdentity();
-
-      // tic RENEW, but not written
-      yield tic.join();
-
-      try {
-        yield tic.createIdentity();
-        throw 'Should have thrown an error for already used pubkey';
-      } catch (e) {
-        JSON.parse(e).message.should.equal('Pubkey already used in the blockchain');
-      }
-      try {
-        yield tic2.createIdentity();
-        throw 'Should have thrown an error for already used uid';
-      } catch (e) {
-        JSON.parse(e).message.should.equal('UID already used in the blockchain');
-      }
-    });
+    await s1.initWithDAL().then(BmaDependency.duniter.methods.bma).then((bmapi) => bmapi.openConnections());
+    ProverDependency.duniter.methods.hookServer(s1._server)
+    await cat.createIdentity();
+    await tac.createIdentity();
+    await toc.createIdentity();
+    await tic.createIdentity();
+    await toc.cert(cat);
+    await cat.cert(toc);
+    await cat.cert(tic);
+    await tic.cert(tac);
+    await tic.cert(cat);
+    await cat.join();
+    await toc.join();
+    await tic.join();
+    await tac.join();
+    await s1.commit();
+    await s1.commit();
+
+    // We have the following WoT (diameter 3):
+
+    /**
+     *  toc <=> cat <=> tic -> tac
+     */
+
+    // cat is the sentry
+
+    // Man1 is someone who just needs a commit to join
+    await man1.createIdentity();
+    await man1.join();
+    await tac.cert(man1);
+
+    /**
+     *  toc <=> cat -> tic -> tac -> man1
+     */
+
+    // Man2 is someone who has no certifications yet has sent a JOIN
+    await man2.createIdentity();
+    await man2.join();
+
+    // Man3 is someone who has only published its identity
+    await man3.createIdentity();
+
+    // tic RENEW, but not written
+    await tic.join();
+
+    try {
+      await tic.createIdentity();
+      throw 'Should have thrown an error for already used pubkey';
+    } catch (e) {
+      JSON.parse(e).message.should.equal('Pubkey already used in the blockchain');
+    }
+    try {
+      await tic2.createIdentity();
+      throw 'Should have thrown an error for already used uid';
+    } catch (e) {
+      JSON.parse(e).message.should.equal('UID already used in the blockchain');
+    }
   });
 
   after(() => {
@@ -136,14 +137,14 @@ describe("Identities collision", function() {
   })
 
   it('should have 4 members', function() {
-    return expectAnswer(rp('http://127.0.0.1:7799/wot/members', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:7799/wot/members', { json: true }), function(res:HttpMembers) {
       res.should.have.property('results').length(4);
-      _.pluck(res.results, 'uid').sort().should.deepEqual(['cat', 'tac', 'tic', 'toc']);
+      Underscore.pluck(res.results, 'uid').sort().should.deepEqual(['cat', 'tac', 'tic', 'toc']);
     });
   });
 
   it('should have identity-of/cat', function() {
-    return expectAnswer(rp('http://127.0.0.1:7799/wot/identity-of/cat', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:7799/wot/identity-of/cat', { json: true }), function(res:HttpIdentity) {
       res.should.have.property('pubkey').equal('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
       res.should.have.property('uid').equal('cat');
       res.should.have.property('sigDate').be.a.Number;
@@ -151,7 +152,7 @@ describe("Identities collision", function() {
   });
 
   it('should have identity-of/toc', function() {
-    return expectAnswer(rp('http://127.0.0.1:7799/wot/identity-of/toc', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:7799/wot/identity-of/toc', { json: true }), function(res:HttpIdentity) {
       res.should.have.property('pubkey').equal('DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo');
       res.should.have.property('uid').equal('toc');
       res.should.have.property('sigDate').be.a.Number;
@@ -159,7 +160,7 @@ describe("Identities collision", function() {
   });
 
   it('should have identity-of/tic', function() {
-    return expectAnswer(rp('http://127.0.0.1:7799/wot/identity-of/tic', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:7799/wot/identity-of/tic', { json: true }), function(res:HttpIdentity) {
       res.should.have.property('pubkey').equal('DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV');
       res.should.have.property('uid').equal('tic');
       res.should.have.property('sigDate').be.a.Number;
@@ -171,7 +172,7 @@ describe("Identities collision", function() {
   });
 
   it('should have certifiers-of/cat giving results', function() {
-    return expectAnswer(rp('http://127.0.0.1:7799/wot/certifiers-of/cat', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:7799/wot/certifiers-of/cat', { json: true }), function(res:HttpCertifications) {
       res.should.have.property('pubkey').equal('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
       res.should.have.property('uid').equal('cat');
       res.should.have.property('isMember').equal(true);
@@ -194,7 +195,7 @@ describe("Identities collision", function() {
   });
 
   it('should have certifiers-of/tic giving results', function() {
-    return expectAnswer(rp('http://127.0.0.1:7799/wot/certifiers-of/tic', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:7799/wot/certifiers-of/tic', { json: true }), function(res:HttpCertifications) {
       res.should.have.property('pubkey').equal('DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV');
       res.should.have.property('uid').equal('tic');
       res.should.have.property('isMember').equal(true);
@@ -215,7 +216,7 @@ describe("Identities collision", function() {
   });
 
   it('should have certifiers-of/toc giving results', function() {
-    return expectAnswer(rp('http://127.0.0.1:7799/wot/certifiers-of/toc', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:7799/wot/certifiers-of/toc', { json: true }), function(res:HttpCertifications) {
       res.should.have.property('pubkey').equal('DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo');
       res.should.have.property('uid').equal('toc');
       res.should.have.property('isMember').equal(true);
@@ -236,7 +237,7 @@ describe("Identities collision", function() {
   });
 
   it('requirements of cat', function() {
-    return expectAnswer(rp('http://127.0.0.1:7799/wot/requirements/cat', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:7799/wot/requirements/cat', { json: true }), function(res:HttpRequirements) {
       res.should.have.property('identities').be.an.Array;
       res.should.have.property('identities').have.length(1);
       res.identities[0].should.have.property('pubkey').equal('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
@@ -253,7 +254,7 @@ describe("Identities collision", function() {
   });
 
   it('requirements of man1', function() {
-    return expectAnswer(rp('http://127.0.0.1:7799/wot/requirements/man1', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:7799/wot/requirements/man1', { json: true }), function(res:HttpRequirements) {
       res.should.have.property('identities').be.an.Array;
       res.should.have.property('identities').have.length(1);
       res.identities[0].should.have.property('pubkey').equal('12AbjvYY5hxV4v2KrN9pnGzgFxogwrzgYyncYHHsyFDK');
@@ -272,7 +273,7 @@ describe("Identities collision", function() {
   });
 
   it('should have certified-by/tic giving results', function() {
-    return expectAnswer(rp('http://127.0.0.1:7799/wot/certified-by/tic', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:7799/wot/certified-by/tic', { json: true }), function(res:HttpCertifications) {
       res.should.have.property('pubkey').equal('DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV');
       res.should.have.property('uid').equal('tic');
       res.should.have.property('isMember').equal(true);
@@ -300,7 +301,7 @@ describe("Identities collision", function() {
   });
 
   it('should have certified-by/tac giving results', function() {
-    return expectAnswer(rp('http://127.0.0.1:7799/wot/certified-by/tac', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:7799/wot/certified-by/tac', { json: true }), function(res:HttpCertifications) {
       res.should.have.property('pubkey').equal('2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc');
       res.should.have.property('uid').equal('tac');
       res.should.have.property('isMember').equal(true);
@@ -310,7 +311,7 @@ describe("Identities collision", function() {
   });
 
   it('should have certified-by/cat giving results', function() {
-    return expectAnswer(rp('http://127.0.0.1:7799/wot/certified-by/cat', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:7799/wot/certified-by/cat', { json: true }), function(res:HttpCertifications) {
       res.should.have.property('pubkey').equal('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
       res.should.have.property('uid').equal('cat');
       res.should.have.property('isMember').equal(true);
@@ -345,7 +346,7 @@ describe("Identities collision", function() {
   });
 
   it('requirements of man2', function() {
-    return expectAnswer(rp('http://127.0.0.1:7799/wot/requirements/man2', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:7799/wot/requirements/man2', { json: true }), function(res:HttpRequirements) {
       res.should.have.property('identities').be.an.Array;
       res.should.have.property('identities').have.length(1);
       res.identities[0].should.have.property('pubkey').equal('E44RxG9jKZQsaPLFSw2ZTJgW7AVRqo1NGy6KGLbKgtNm');
@@ -361,7 +362,7 @@ describe("Identities collision", function() {
   });
 
   it('requirements of man3', function() {
-    return expectAnswer(rp('http://127.0.0.1:7799/wot/requirements/man3', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:7799/wot/requirements/man3', { json: true }), function(res:HttpRequirements) {
       res.should.have.property('identities').be.an.Array;
       res.should.have.property('identities').have.length(1);
       res.identities[0].should.have.property('pubkey').equal('5bfpAfZJ4xYspUBYseASJrofhRm6e6JMombt43HBaRzW');
@@ -376,9 +377,9 @@ describe("Identities collision", function() {
     });
   });
 
-  it('requirements of man3 after revocation', () => co(function*() {
-    yield man3.revoke();
-    return expectAnswer(rp('http://127.0.0.1:7799/wot/requirements/man3', { json: true }), function(res) {
+  it('requirements of man3 after revocation', async () => {
+    await man3.revoke();
+    return expectAnswer(rp('http://127.0.0.1:7799/wot/requirements/man3', { json: true }), function(res:HttpRequirements) {
       res.should.have.property('identities').be.an.Array;
       res.should.have.property('identities').have.length(1);
       res.identities[0].should.have.property('pubkey').equal('5bfpAfZJ4xYspUBYseASJrofhRm6e6JMombt43HBaRzW');
@@ -394,10 +395,10 @@ describe("Identities collision", function() {
       res.identities[0].should.have.property('revoked_on').equal(null);
       res.identities[0].should.have.property('revocation_sig').not.equal(null);
     });
-  }));
+  })
 
   it('memberships of tic', function() {
-    return expectAnswer(rp('http://127.0.0.1:7799/blockchain/memberships/tic', { json: true }), function(res) {
+    return expectAnswer(rp('http://127.0.0.1:7799/blockchain/memberships/tic', { json: true }), function(res:HttpMemberships) {
       res.should.have.property('pubkey').equal('DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV');
       res.should.have.property('uid').equal('tic');
       res.should.have.property('sigDate').be.a.Number;
@@ -410,7 +411,7 @@ describe("Identities collision", function() {
       res.memberships[0].should.have.property('blockHash').not.equal('E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855');
       res.memberships[0].should.have.property('written').equal(null);
     });
-  });
+  })
 
   // it('memberships of man3', function() {
   //   return httpTest.expectHttpCode(404, rp('http://127.0.0.1:7799/blockchain/memberships/man3'));
@@ -424,4 +425,4 @@ describe("Identities collision", function() {
   //     res.levels[0].should.have.property('level').equal(4);
   //   });
   // });
-});
+})
diff --git a/test/integration/membership_chainability.ts b/test/integration/membership_chainability.ts
index af5da41eff3d084a17e9d6a4cfbd92698d0990b4..95ffc5f94ba1976ac82634dc624e6af18493dcb5 100644
--- a/test/integration/membership_chainability.ts
+++ b/test/integration/membership_chainability.ts
@@ -11,7 +11,7 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-const toolbox = require('./tools/toolbox')
+import {simpleNodeWith2Users} from "./tools/toolbox"
 
 describe("Membership chainability", function() {
 
@@ -31,7 +31,7 @@ describe("Membership chainability", function() {
     }
 
     before(async () => {
-      const res1 = await toolbox.simpleNodeWith2Users(conf)
+      const res1 = await simpleNodeWith2Users(conf)
       s1 = res1.s1
       cat = res1.cat
       await s1.commit({ time: now })
@@ -67,7 +67,7 @@ describe("Membership chainability", function() {
     }
 
     before(async () => {
-      const res1 = await toolbox.simpleNodeWith2Users(conf)
+      const res1 = await simpleNodeWith2Users(conf)
       s1 = res1.s1
       cat = res1.cat
       await s1.commit({ time: now })
diff --git a/test/integration/cli.js b/test/integration/misc/cli.ts
similarity index 52%
rename from test/integration/cli.js
rename to test/integration/misc/cli.ts
index 766835cb5ab532e26ef9201cebd578417b3ada75..8abc8acaffa8200c69ffd04ebd8926ba20a51d85 100644
--- a/test/integration/cli.js
+++ b/test/integration/misc/cli.ts
@@ -11,67 +11,60 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {MerkleDTO} from "../../../app/lib/dto/MerkleDTO"
+import {hashf} from "../../../app/lib/common"
+import {processForURL} from "../../../app/lib/helpers/merkle"
+import {fakeSyncServer} from "../tools/toolbox"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
 
 const spawn     = require('child_process').spawn;
 const path      = require('path');
-const co        = require('co');
 const should    = require('should');
-const _         = require('underscore');
-const toolbox   = require('./tools/toolbox');
-const duniter   = require('../../index');
-const merkleh   = require('../../app/lib/helpers/merkle');
-const hashf     = require('../../app/lib/common-libs').hashf
-const MerkleDTO = require('../../app/lib/dto/MerkleDTO').MerkleDTO
+const duniter   = require('../../../index');
 
 const DB_NAME = "unit_tests";
 
 describe("CLI", function() {
 
-  let farmOfServers = [], fakeServer;
+  let farmOfServers:{ host:string, port:number}[] = [], fakeServer:{ host:string, port:number}
 
-  before(() => co(function*() {
+  before(async () => {
 
-    const blockchain = require('../data/blockchain.json');
-    const peers = [];
-    const peersMap = {};
-    const leaves = [];
+    const blockchain = require('../../data/blockchain.json');
+    const peersMap:any = {};
+    const leaves:string[] = [];
 
     /********
      * HTTP METHODS
      */
-    const onReadBlockchainChunk = (count, from) => Promise.resolve(blockchain.blocks.slice(from, from + count));
-    const onReadParticularBlock = (number) => Promise.resolve(blockchain.blocks[number]);
-    const onPeersRequested = (req) => co(function*() {
+    const onReadBlockchainChunk = (count:number, from:number) => Promise.resolve(blockchain.blocks.slice(from, from + count));
+    const onReadParticularBlock = (number:number) => Promise.resolve(blockchain.blocks[number]);
+    const onPeersRequested = async (req:any) => {
       const merkle = new MerkleDTO();
       merkle.initialize(leaves);
-      merkle.leaf = {
-        "hash": req.params.leaf,
-        "value": peersMap[req.params.leaf] || ""
-      };
-      return merkleh.processForURL(req, merkle, () => co(function*() {
+      return processForURL(req, merkle, async () => {
         return peersMap;
-      }));
-    });
+      })
+    }
 
     /**
      * The fake hash in the blockchain
      */
     const fakeHash = hashf("A wrong content").toUpperCase();
 
-    farmOfServers = yield Array.from({ length: 5 }).map((unused, index) => {
+    farmOfServers = await Promise.all(Array.from({ length: 5 }).map(async (unused, index) => {
       if (index < 2) {
         
         /***************
          * Normal nodes
          */
-        return toolbox.fakeSyncServer(onReadBlockchainChunk, onReadParticularBlock, onPeersRequested);
+        return fakeSyncServer(onReadBlockchainChunk, onReadParticularBlock, onPeersRequested);
       } else if (index == 2) {
         
         /***************
          * Node with wrong chaining between 2 chunks of blocks
          */
-        return toolbox.fakeSyncServer((count, from) => {
+        return fakeSyncServer((count:number, from:number) => {
           // We just need to send the wrong chunk
           from = from - count;
           return Promise.resolve(blockchain.blocks.slice(from, from + count));
@@ -81,30 +74,30 @@ describe("CLI", function() {
         /***************
          * Node with wrong chaining between 2 blocks
          */
-        return toolbox.fakeSyncServer((count, from) => {
+        return fakeSyncServer((count:number, from:number) => {
           // We just need to send the wrong chunk
-          const chunk = blockchain.blocks.slice(from, from + count).map((block, index2) => {
+          const chunk = blockchain.blocks.slice(from, from + count).map((block:any, index2:number) => {
             if (index2 === 10) {
-              const clone = _.clone(block);
+              const clone = Underscore.clone(block);
               clone.hash = fakeHash;
             }
             return block;
           });
           return Promise.resolve(chunk);
         }, onReadParticularBlock, onPeersRequested);
-      } else if (index == 4) {
+      } else {
         
         /***************
          * Node with apparent good chaining, but one of the hashs is WRONG
          */
-        return toolbox.fakeSyncServer((count, from) => {
+        return fakeSyncServer((count:number, from:number) => {
           // We just need to send the wrong chunk
-          const chunk = blockchain.blocks.slice(from, from + count).map((block, index2) => {
+          const chunk = blockchain.blocks.slice(from, from + count).map((block:any, index2:number) => {
             if (index2 === 10) {
-              const clone = _.clone(block);
+              const clone = Underscore.clone(block);
               clone.hash = fakeHash;
             } else if (index2 === 11) {
-              const clone = _.clone(block);
+              const clone = Underscore.clone(block);
               clone.previousHash = fakeHash;
               return clone;
             }
@@ -113,56 +106,55 @@ describe("CLI", function() {
           return Promise.resolve(chunk);
         }, onReadParticularBlock, onPeersRequested);
       }
-    });
+    }))
     farmOfServers.map((server, index) => {
       const peer = {
         endpoints: [['BASIC_MERKLED_API', server.host, server.port].join(' ')],
         pubkey: hashf(index + ""),
         hash: hashf(index + "").toUpperCase()
       };
-      peers.push(peer);
       leaves.push(peer.hash);
       peersMap[peer.hash] = peer;
     });
     fakeServer = farmOfServers[0];
-  }));
+  })
 
-  it('config --autoconf', () => co(function*() {
-    let res = yield execute(['config', '--autoconf', '--noupnp']);
+  it('config --autoconf', async () => {
+    let res = await execute(['config', '--autoconf', '--noupnp']);
     res.should.have.property("pair").property('pub').not.equal("");
     res.should.have.property("pair").property('sec').not.equal("");
-  }));
+  })
 
-  it('reset data', () => co(function*() {
-    yield execute(['reset', 'data']);
-    // const res = yield execute(['export-bc', '--nostdout']);
+  it('reset data', async () => {
+    await execute(['reset', 'data']);
+    // const res = await execute(['export-bc', '--nostdout']);
     // res.slice(0, 1).should.have.length(0);
-  }));
+  })
 
-  it('sync 7 blocks (fast)', () => co(function*() {
-    yield execute(['reset', 'data']);
-    yield execute(['sync', fakeServer.host, fakeServer.port, '7', '--nocautious', '--nointeractive', '--noshuffle']);
-    const res = yield execute(['export-bc', '--nostdout']);
+  it('sync 7 blocks (fast)', async () => {
+    await execute(['reset', 'data']);
+    await execute(['sync', fakeServer.host, String(fakeServer.port), '7', '--nocautious', '--nointeractive', '--noshuffle']);
+    const res = await execute(['export-bc', '--nostdout']);
     res[res.length - 1].should.have.property('number').equal(7);
     res.should.have.length(7 + 1); // blocks #0..#7
-  }));
+  })
 
-  it('sync 4 blocks (cautious)', () => co(function*() {
-    yield execute(['sync', fakeServer.host, fakeServer.port, '11', '--nointeractive']);
-    const res = yield execute(['export-bc', '--nostdout']);
+  it('sync 4 blocks (cautious)', async () => {
+    await execute(['sync', fakeServer.host, String(fakeServer.port), '11', '--nointeractive']);
+    const res = await execute(['export-bc', '--nostdout']);
     res[res.length - 1].should.have.property('number').equal(11);
     res.should.have.length(11 + 1);
-  }));
+  })
 
-  it('[spawn] reset data', () => co(function*() {
-    yield executeSpawn(['reset', 'data']);
-    const res = yield executeSpawn(['export-bc']);
+  it('[spawn] reset data', async () => {
+    await executeSpawn(['reset', 'data']);
+    const res = await executeSpawn(['export-bc']);
     JSON.parse(res).should.have.length(0);
-  }));
+  })
 
-  it('[spawn] sync 10 first blocks --memory', () => co(function*() {
-    yield execute(['sync', fakeServer.host, fakeServer.port, '10', '--memory', '--cautious', '--nointeractive']);
-  }));
+  it('[spawn] sync 10 first blocks --memory', async () => {
+    await execute(['sync', fakeServer.host, String(fakeServer.port), '10', '--memory', '--cautious', '--nointeractive']);
+  })
 });
 
 /**
@@ -170,14 +162,11 @@ describe("CLI", function() {
  * @param args Array of arguments.
  * @returns {*|Promise} Returns the command output.
  */
-function execute(args) {
+async function execute(args:(string)[]) {
   const finalArgs = [process.argv[0], __filename].concat(args).concat(['--mdb', DB_NAME]);
-  return co(function*() {
-
-    const stack = duniter.statics.autoStack();
-    // Executes the command
-    return stack.executeStack(finalArgs);
-  });
+  const stack = duniter.statics.autoStack();
+  // Executes the command
+  return stack.executeStack(finalArgs);
 }
 
 /**
@@ -185,19 +174,17 @@ function execute(args) {
  * @param command Array of arguments.
  * @returns {*|Promise} Returns the command output.
  */
-function executeSpawn(command) {
-  return co(function*() {
-    const finalArgs = [path.join(__dirname, '../../bin/duniter')].concat(command).concat(['--mdb', DB_NAME]);
-    const duniterCmd = spawn(process.argv[0], finalArgs);
-    return new Promise((resolve, reject) => {
-      let res = "";
-      duniterCmd.stdout.on('data', (data) => {
-        res += data.toString('utf8').replace(/\n/, '');
-      });
-      duniterCmd.stderr.on('data', (err) => {
-        console.log(err.toString('utf8').replace(/\n/, ''));
-      });
-      duniterCmd.on('close', (code) => code ? reject(code) : resolve(res) );
+async function executeSpawn(command:string[]): Promise<string> {
+  const finalArgs = [path.join(__dirname, '../../../bin/duniter')].concat(command).concat(['--mdb', DB_NAME]);
+  const duniterCmd = spawn(process.argv[0], finalArgs);
+  return new Promise<string>((resolve, reject) => {
+    let res = "";
+    duniterCmd.stdout.on('data', (data:any) => {
+      res += data.toString('utf8').replace(/\n/, '');
+    });
+    duniterCmd.stderr.on('data', (err:any) => {
+      console.log(err.toString('utf8').replace(/\n/, ''));
     });
+    duniterCmd.on('close', (code:any) => code ? reject(code) : resolve(res) );
   });
 }
diff --git a/test/integration/http_api.js b/test/integration/misc/http-api.ts
similarity index 69%
rename from test/integration/http_api.js
rename to test/integration/misc/http-api.ts
index d793281ec54d1d2034bf464fa16f58d67fb535fe..aeac652483f05e193a4d63c1d11a9dac7fd0af65 100644
--- a/test/integration/http_api.js
+++ b/test/integration/misc/http-api.ts
@@ -13,34 +13,37 @@
 
 "use strict";
 
-const co        = require('co');
-const _         = require('underscore');
+import {ProverConstants} from "../../../app/modules/prover/lib/constants"
+import {NewTestingServer, TestingServer} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
+import {BmaDependency} from "../../../app/modules/bma/index"
+import {PeerDTO} from "../../../app/lib/dto/PeerDTO"
+import {ProverDependency} from "../../../app/modules/prover/index"
+import {HttpBlock, HttpDifficulties} from "../../../app/modules/bma/lib/dtos"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
+import {BlockDTO} from "../../../app/lib/dto/BlockDTO"
+
 const should    = require('should');
 const assert    = require('assert');
-const duniter     = require('../../index');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const PeerDTO   = require('../../app/lib/dto/PeerDTO').PeerDTO
-const TestUser  = require('./tools/TestUser').TestUser
-const http      = require('./tools/http');
-const shutDownEngine  = require('./tools/shutDownEngine');
 const rp        = require('request-promise');
 const ws        = require('ws');
+const http      = require('../tools/http');
+const shutDownEngine  = require('../tools/shutDownEngine');
 
-require('../../app/modules/prover/lib/constants').ProverConstants.CORES_MAXIMUM_USE_IN_PARALLEL = 1
+ProverConstants.CORES_MAXIMUM_USE_IN_PARALLEL = 1
 
-let server, server2, cat, toc
+let server:TestingServer, server2:TestingServer, cat:TestUser, toc:TestUser
 
 describe("HTTP API", function() {
 
   const now = 1500000000
-  let commit
+  let commit:(options:any) => Promise<BlockDTO>
 
-  before(() => co(function*(){
+  before(async () => {
 
-    server = duniter(
-      '/bb11',
-      true,
+    server = NewTestingServer(
       {
+        name: 'bb11',
         ipv4: '127.0.0.1',
         port: '7777',
         currency: 'bb',
@@ -57,10 +60,9 @@ describe("HTTP API", function() {
         }
       });
 
-    server2 = duniter(
-      '/bb12',
-      true,
+    server2 = NewTestingServer(
       {
+        name: 'bb12',
         ipv4: '127.0.0.1',
         port: '30410',
         currency: 'bb',
@@ -82,33 +84,33 @@ describe("HTTP API", function() {
 
     commit = makeBlockAndPost(server);
 
-    let s = yield server.initWithDAL();
-    let bmapi = yield bma(s);
-    yield bmapi.openConnections();
-
-    let s2 = yield server2.initWithDAL();
-    let bmapi2 = yield bma(s2);
-    yield bmapi2.openConnections();
-
-    yield cat.createIdentity();
-    yield toc.createIdentity();
-    yield toc.cert(cat);
-    yield cat.cert(toc);
-    yield cat.join();
-    yield toc.join();
-    const b0 = yield commit({ time: now });
-    const b1 = yield commit({ time: now + 120 });
-    yield server2.writeBlock(b0)
-    yield server2.writeBlock(b1)
-    server.addEndpointsDefinitions(() => Promise.resolve('SOME_FAKE_ENDPOINT_P1'))
-    server2.addEndpointsDefinitions(() => Promise.resolve('SOME_FAKE_ENDPOINT_P2'))
-    const p1 = yield server.PeeringService.generateSelfPeer(server.conf)
-    yield server2.PeeringService.generateSelfPeer(server2.conf)
-    yield server2.writePeer(p1)
-    server2.writeBlock(yield commit({ time: now + 120 * 2 }))
-    server2.writeBlock(yield commit({ time: now + 120 * 3 }))
-    server2.writeBlock(yield commit({ time: now + 120 * 4 }))
-  }));
+    let s = await server.initWithDAL();
+    let bmapi = await BmaDependency.duniter.methods.bma(s);
+    await bmapi.openConnections();
+
+    let s2 = await server2.initWithDAL();
+    let bmapi2 = await BmaDependency.duniter.methods.bma(s2);
+    await bmapi2.openConnections();
+
+    await cat.createIdentity();
+    await toc.createIdentity();
+    await toc.cert(cat);
+    await cat.cert(toc);
+    await cat.join();
+    await toc.join();
+    const b0 = await commit({ time: now });
+    const b1 = await commit({ time: now + 120 });
+    await server2.writeBlock(b0)
+    await server2.writeBlock(b1)
+    server._server.addEndpointsDefinitions(() => Promise.resolve('SOME_FAKE_ENDPOINT_P1'))
+    server2._server.addEndpointsDefinitions(() => Promise.resolve('SOME_FAKE_ENDPOINT_P2'))
+    const p1 = await server.PeeringService.generateSelfPeer(server.conf)
+    await server2.PeeringService.generateSelfPeer(server2.conf)
+    await server2.writePeer(p1)
+    server2.writeBlock(await commit({ time: now + 120 * 2 }))
+    server2.writeBlock(await commit({ time: now + 120 * 3 }))
+    server2.writeBlock(await commit({ time: now + 120 * 4 }))
+  })
 
   after(() => {
     return Promise.all([
@@ -116,14 +118,12 @@ describe("HTTP API", function() {
     ])
   })
 
-  function makeBlockAndPost(theServer) {
-    return function(options) {
-      return co(function*() {
-        const block = yield require('../../app/modules/prover').ProverDependency.duniter.methods.generateAndProveTheNext(theServer, null, null, options)
-        const res = yield postBlock(theServer)(block)
-        return JSON.parse(res)
-      })
-    };
+  function makeBlockAndPost(theServer:TestingServer) {
+    return async function(options:any) {
+      const block = await ProverDependency.duniter.methods.generateAndProveTheNext(theServer._server, null, null, options)
+      const res = await postBlock(theServer)(block)
+      return JSON.parse(res)
+    }
   }
 
   describe("/blockchain", function() {
@@ -227,7 +227,7 @@ describe("HTTP API", function() {
     });
 
     it('/difficulties should have current block number + 1', function() {
-      return http.expectAnswer(rp('http://127.0.0.1:7777/blockchain/difficulties', { json: true }), function(res) {
+      return http.expectAnswer(rp('http://127.0.0.1:7777/blockchain/difficulties', { json: true }), function(res:HttpDifficulties) {
         res.should.have.property('block').equal(5);
         res.should.have.property('levels').have.length(1);
       });
@@ -247,7 +247,7 @@ describe("HTTP API", function() {
     it('/block should send a block', function(done) {
       let completed = false
       const client = new ws('ws://127.0.0.1:7777/ws/block');
-      client.once('message', function message(data) {
+      client.once('message', function message(data:any) {
         const block = JSON.parse(data);
         should(block).have.property('number', 4);
         should(block).have.property('dividend').equal(null)
@@ -260,41 +260,41 @@ describe("HTTP API", function() {
       });
     });
 
-    it('/block (number 5,6,7) should send a block', () => co(function*() {
-      server2.writeBlock(yield commit({ time: now + 120 * 5 }))
+    it('/block (number 5,6,7) should send a block', async () => {
+      server2.writeBlock(await commit({ time: now + 120 * 5 }))
       const client = new ws('ws://127.0.0.1:7777/ws/block');
-      let resolve5, resolve6, resolve7
+      let resolve5:any, resolve6:any, resolve7:any
       const p5 = new Promise(res => resolve5 = res)
       const p6 = new Promise(res => resolve6 = res)
       const p7 = new Promise(res => resolve7 = res)
-      client.on('message', function message(data) {
+      client.on('message', function message(data:string) {
         const block = JSON.parse(data);
         if (block.number === 5) resolve5(block)
         if (block.number === 6) resolve6(block)
         if (block.number === 7) resolve7(block)
       })
-      server2.writeBlock(yield commit({ time: now + 120 * 6 }))
-      server2.writeBlock(yield commit({ time: now + 120 * 7 }))
-      const b5 = yield p5
+      server2.writeBlock(await commit({ time: now + 120 * 6 }))
+      server2.writeBlock(await commit({ time: now + 120 * 7 }))
+      const b5 = await p5
       should(b5).have.property('number', 5);
       should(b5).have.property('dividend').equal(100)
       should(b5).have.property('monetaryMass').equal(600)
       should(b5).have.property('monetaryMass').not.equal("600")
-      const b6 = yield p6
+      const b6 = await p6
       should(b6).have.property('number', 6);
       should(b6).have.property('dividend').equal(null)
       should(b6).have.property('monetaryMass').equal(600)
       should(b6).have.property('monetaryMass').not.equal("600")
-      const b7 = yield p7
+      const b7 = await p7
       should(b7).have.property('number', 7);
       should(b7).have.property('dividend').equal(100)
       should(b7).have.property('monetaryMass').equal(800)
       should(b7).have.property('monetaryMass').not.equal("800")
-    }))
+    })
 
     it('/block should answer to pings', function(done) {
       const client = new ws('ws://127.0.0.1:7777/ws/block');
-      client.on('pong', function message(data, flags) {
+      client.on('pong', function message() {
         client.terminate();
         done();
       });
@@ -303,13 +303,13 @@ describe("HTTP API", function() {
       });
     });
 
-    it('/peer (number 5,6,7) should send a peer document', () => co(function*() {
+    it('/peer (number 5,6,7) should send a peer document', async () => {
       const client = new ws('ws://127.0.0.1:30410/ws/peer');
-      let resolve5, resolve6, resolve7
+      let resolve5:any, resolve6:any
       const p5 = new Promise(res => resolve5 = res)
       const p6 = new Promise(res => resolve6 = res)
-      server.addEndpointsDefinitions(() => Promise.resolve("BASIC_MERKLED_API localhost 7777"))
-      client.on('message', function message(data) {
+      server._server.addEndpointsDefinitions(() => Promise.resolve("BASIC_MERKLED_API localhost 7777"))
+      client.on('message', function message(data:any) {
         const peer = JSON.parse(data);
         if (peer.block.match(/2-/)) {
           server2.PeeringService.generateSelfPeer(server.conf)
@@ -319,57 +319,55 @@ describe("HTTP API", function() {
           return resolve6(peer)
         }
       })
-      const p1 = yield server.PeeringService.generateSelfPeer({
+      const p1 = await server.PeeringService.generateSelfPeer({
         currency: server.conf.currency
       }, 0)
-      yield server2.writeRawPeer(PeerDTO.fromJSONObject(p1).getRawSigned())
-      const b5 = yield p5
+      await server2._server.writeRawPeer(PeerDTO.fromJSONObject(p1).getRawSigned())
+      const b5 = await p5
       should(b5).have.property('version', 10)
-      const b6 = yield p6
+      const b6 = await p6
       should(b6).have.property('version', 10)
-    }))
-  });
-});
-
-function expectJSON(promise, json) {
-  return co(function*(){
-    try {
-      const resJson = yield promise;
-      _.keys(json).forEach(function(key){
-        resJson.should.have.property(key).equal(json[key]);
-      });
-    } catch (err) {
-      if (err.response) {
-        assert.equal(err.response.statusCode, 200);
-      }
-      else throw err;
+    })
+  })
+})
+
+async function expectJSON<T>(promise:Promise<T>, json:any) {
+  try {
+    const resJson = await promise;
+    Underscore.keys(json).forEach(function(key){
+      resJson.should.have.property(key).equal(json[key]);
+    });
+  } catch (err) {
+    if (err.response) {
+      assert.equal(err.response.statusCode, 200);
     }
-  });
+    else throw err;
+  }
 }
 
-function postBlock(server2) {
-  return function(block) {
+function postBlock(server2:TestingServer) {
+  return function(block:any) {
     return post(server2, '/blockchain/block')({
       block: typeof block == 'string' ? block : block.getRawSigned()
     })
-      .then((result) => co(function*() {
+      .then(async (result:HttpBlock) => {
         const numberToReach = block.number
-        yield new Promise((res) => {
-          const interval = setInterval(() => co(function*() {
-            const current = yield server2.dal.getCurrentBlockOrNull()
+        await new Promise((res) => {
+          const interval = setInterval(async () => {
+            const current = await server2.dal.getCurrentBlockOrNull()
             if (current && current.number == numberToReach) {
               res()
               clearInterval(interval)
             }
-          }), 1)
+          }, 1)
         })
         return result
-      }))
+      })
   };
 }
 
-function post(server2, uri) {
-  return function(data) {
+function post(server2:TestingServer, uri:string) {
+  return function(data:any) {
     return rp.post('http://' + [server2.conf.ipv4, server2.conf.port].join(':') + uri, {
       form: data
     });
diff --git a/test/integration/server-import-export.js b/test/integration/misc/server-import-export.ts
similarity index 60%
rename from test/integration/server-import-export.js
rename to test/integration/misc/server-import-export.ts
index daab7a580d0a78aaa44cda10aec5c2283574a04a..2f2e7bd5487336cf1fa3bde24bc46cdbd2fc9ec5 100644
--- a/test/integration/server-import-export.js
+++ b/test/integration/misc/server-import-export.ts
@@ -11,15 +11,11 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
-const _ = require('underscore');
+import {TestUser} from "../tools/TestUser"
+import {NewTestingServer, TestingServer} from "../tools/toolbox"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
+
 const should = require('should');
-const fs = require('fs');
-const co = require('co');
-const unzip = require('unzip');
-const toolbox = require('../integration/tools/toolbox');
-const TestUser = require('../integration/tools/TestUser').TestUser
-const bma     = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
 
 const serverConfig = {
   memory: false,
@@ -29,28 +25,28 @@ const serverConfig = {
   }
 };
 
-let s0, s1;
+let s0:TestingServer, s1:TestingServer
 
 describe('Import/Export', () => {
 
-  before(() => co(function *() {
-    s0 = toolbox.server(_.extend({ homename: 'dev_unit_tests1', powNoSecurity: true }, serverConfig));
-    yield s0.resetHome();
+  before(async () => {
+    s0 = NewTestingServer(Underscore.extend({ homename: 'dev_unit_tests1', powNoSecurity: true }, serverConfig));
+    await s0.resetHome();
 
-    s1 = toolbox.server(_.extend({ homename: 'dev_unit_tests1', powNoSecurity: true }, serverConfig));
+    s1 = NewTestingServer(Underscore.extend({ homename: 'dev_unit_tests1', powNoSecurity: true }, serverConfig));
 
     const cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
     const tac = new TestUser('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
 
-    yield s1.initDalBmaConnections();
-    yield cat.createIdentity();
-    yield tac.createIdentity();
-    yield cat.cert(tac);
-    yield tac.cert(cat);
-    yield cat.join();
-    yield tac.join();
-    yield s1.commit();
-  }));
+    await s1.initDalBmaConnections();
+    await cat.createIdentity();
+    await tac.createIdentity();
+    await cat.cert(tac);
+    await tac.cert(cat);
+    await cat.join();
+    await tac.join();
+    await s1.commit();
+  })
 
   after(() => {
     return Promise.all([
@@ -59,8 +55,8 @@ describe('Import/Export', () => {
     ])
   })
 
-  it('should be able to export data', () => co(function *() {
-    const archive = yield s1.exportAllDataAsZIP();
+  it('should be able to export data', async () => {
+    const archive = await s1.exportAllDataAsZIP();
     const output = require('fs').createWriteStream(s1.home + '/export.zip');
     archive.pipe(output);
     return new Promise((resolve, reject) => {
@@ -69,10 +65,10 @@ describe('Import/Export', () => {
         resolve();
       });
     });
-  }));
+  })
 
-  it('should be able to import data', () => co(function *() {
-    yield s1.unplugFileSystem();
-    yield s1.importAllDataFromZIP(s1.home + '/export.zip');
-  }));
-});
+  it('should be able to import data', async () => {
+    await s1.unplugFileSystem();
+    await s1.importAllDataFromZIP(s1.home + '/export.zip');
+  })
+})
diff --git a/test/integration/network-update.js b/test/integration/network-update.js
deleted file mode 100644
index baae2b7a3ef1527d13cbd8df2d2254dc8959d774..0000000000000000000000000000000000000000
--- a/test/integration/network-update.js
+++ /dev/null
@@ -1,129 +0,0 @@
-// Source file from duniter: Crypto-currency software to manage libre currency such as Äž1
-// Copyright (C) 2018  Cedric Moreau <cem.moreau@gmail.com>
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU Affero General Public License for more details.
-
-"use strict";
-
-const co = require('co');
-const _         = require('underscore');
-const rp        = require('request-promise');
-const httpTest  = require('./tools/http');
-const node      = require('./tools/node');
-const TestUser  = require('./tools/TestUser').TestUser
-const commit    = require('./tools/commit');
-const sync      = require('./tools/sync');
-const until     = require('./tools/until');
-const toolbox   = require('./tools/toolbox');
-const BlockDTO = require("../../app/lib/dto/BlockDTO");
-
-const expectHttpCode = httpTest.expectHttpCode;
-const expectAnswer = httpTest.expectAnswer;
-
-const MEMORY_MODE = true;
-const commonConf = {
-  ipv4: '127.0.0.1',
-  remoteipv4: '127.0.0.1',
-  currency: 'bb',
-  httpLogs: true,
-  forksize: 3,
-  sigQty: 1
-};
-
-const catKeyPair = {
-  pair: {
-    pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
-    sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
-  }
-};
-
-const tocKeyPair = {
-  pair: {
-    pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo',
-    sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'
-  }
-};
-
-let s1, s2, cat, toc
-
-
-describe("Network updating", function() {
-
-  before(function() {
-
-    return co(function *() {
-
-      s1 = toolbox.server(_.clone(catKeyPair));
-      s2 = toolbox.server(_.clone(tocKeyPair));
-
-      cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-      toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
-
-      const commitS1 = commit(s1);
-      const commitS2 = commit(s2);
-
-      yield [s1, s2].reduce((p, server) => co(function*() {
-        yield p;
-        yield server.initDalBmaConnections()
-        require('../../app/modules/router').RouterDependency.duniter.methods.routeToNetwork(server);
-      }), Promise.resolve());
-
-      // Server 1
-      yield cat.createIdentity();
-      yield toc.createIdentity();
-      yield toc.cert(cat);
-      yield cat.cert(toc);
-      yield cat.join();
-      yield toc.join();
-      for (const i in _.range(32)) {
-        yield commitS1(); // block#0
-      }
-      // // s2 syncs from s1
-      yield sync(0, 31, s1, s2);
-
-      const b2 = yield s1.makeNext({});
-      yield s1.postBlock(b2);
-      yield s2.postBlock(b2);
-      yield s1.recomputeSelfPeer(); // peer#1
-      yield s1.sharePeeringWith(s2);
-      const b3 = yield s1.makeNext({});
-      yield s1.postBlock(b3);
-      yield s2.postBlock(b3);
-      yield s2.waitToHaveBlock(b3.number);
-      yield s1.recomputeSelfPeer(); // peer#1
-      yield s1.sharePeeringWith(s2);
-    });
-  });
-
-    describe("Server 1 /network/peering", function() {
-
-      it('/peers?leaf=LEAFDATA', () => co(function*() {
-        const data = yield s1.get('/network/peering/peers?leaves=true');
-        const leaf = data.leaves[0];
-        const res = yield s1.get('/network/peering/peers?leaf=' + leaf);
-        res.leaf.value.should.have.property("pubkey").equal('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
-        res.leaf.value.should.have.property("block").match(new RegExp('^3-'));
-        res.leaf.value.should.have.property("raw").match(new RegExp('.*Block: 3-.*'));
-      }));
-    });
-
-    describe("Server 2 /network/peering", function() {
-
-      it('/peers?leaf=LEAFDATA', () => co(function*() {
-        const data = yield s2.get('/network/peering/peers?leaves=true');
-        const leaf = data.leaves[0];
-        const res = yield s2.get('/network/peering/peers?leaf=' + leaf);
-        res.leaf.value.should.have.property("pubkey").equal('DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo');
-        res.leaf.value.should.have.property("block").match(new RegExp('^0-'));
-        res.leaf.value.should.have.property("raw").match(new RegExp('.*Block: 0-.*'));
-      }));
-    });
-  });
diff --git a/test/integration/network.js b/test/integration/network/network-merkle.ts
similarity index 89%
rename from test/integration/network.js
rename to test/integration/network/network-merkle.ts
index 9f75b690445779c9511a5629e529cf5a63dc2970..7bda67d167e35ad9fe46ddbae6edcff8b19cf622 100644
--- a/test/integration/network.js
+++ b/test/integration/network/network-merkle.ts
@@ -11,18 +11,16 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {Underscore} from "../../../app/lib/common-libs/underscore"
+import {HttpMerkleOfPeers} from "../../../app/modules/bma/lib/dtos"
 
-const co = require('co');
-const _         = require('underscore');
 const rp        = require('request-promise');
-const httpTest  = require('./tools/http');
-const node      = require('./tools/node');
+const httpTest  = require('../tools/http');
+const node      = require('../tools/node');
 
 const expectHttpCode = httpTest.expectHttpCode;
 const expectAnswer = httpTest.expectAnswer;
 
-const MEMORY_MODE = true;
 const commonConf = {
   bmaWithCrawler: true,
   ipv4: '127.0.0.1',
@@ -33,7 +31,7 @@ const commonConf = {
   sigQty: 1
 };
 
-const s1 = node('bb33', _.extend({
+const s1 = node('bb33', Underscore.extend({
   ipv4: '127.0.0.1',
   port: '20501',
   remoteport: '20501',
@@ -46,7 +44,7 @@ const s1 = node('bb33', _.extend({
   sigQty: 1, dt: 0, ud0: 120
 }, commonConf));
 
-const s2 = node('bb12', _.extend({
+const s2 = node('bb12', Underscore.extend({
   port: '20502',
   remoteport: '20502',
   ws2p: { upnp: false },
@@ -58,20 +56,17 @@ const s2 = node('bb12', _.extend({
 
 describe("Network Merkle", function() {
 
-  before(function() {
-
-    return co(function *() {
-      yield s1.startTesting();
-      yield s2.startTesting();
-      let peer1 = yield s1.peeringP();
-      yield s2.submitPeerP(peer1);
-    });
-  });
+  before(async () => {
+    await s1.startTesting();
+    await s2.startTesting();
+    let peer1 = await s1.peeringP();
+    await s2.submitPeerP(peer1);
+  })
 
   describe("Server 1 /network/peering", function() {
 
     it('/peers?leaves=true', function() {
-      return expectAnswer(rp('http://127.0.0.1:20501/network/peering/peers?leaves=true', { json: true }), (res) => {
+      return expectAnswer(rp('http://127.0.0.1:20501/network/peering/peers?leaves=true', { json: true }), (res:HttpMerkleOfPeers) => {
         res.should.have.property('depth').equal(0);
         res.should.have.property('nodesCount').equal(0);
         res.should.have.property('leavesCount').equal(1);
@@ -82,7 +77,7 @@ describe("Network Merkle", function() {
     });
 
     it('/peers?leaf=C3EAB939F0BEF711461A140A1BA2649C75905107FACA3BE9C5F76F7FD1C7BC5E', function() {
-      return expectAnswer(rp('http://127.0.0.1:20501/network/peering/peers?leaf=C3EAB939F0BEF711461A140A1BA2649C75905107FACA3BE9C5F76F7FD1C7BC5E', { json: true }), (res) => {
+      return expectAnswer(rp('http://127.0.0.1:20501/network/peering/peers?leaf=C3EAB939F0BEF711461A140A1BA2649C75905107FACA3BE9C5F76F7FD1C7BC5E', { json: true }), (res:HttpMerkleOfPeers) => {
         res.should.have.property('depth').equal(0);
         res.should.have.property('nodesCount').equal(0);
         res.should.have.property('leavesCount').equal(1);
@@ -104,7 +99,7 @@ describe("Network Merkle", function() {
   describe("Server 2 /network/peering", function() {
 
     it('/peers?leaves=true', function() {
-      return expectAnswer(rp('http://127.0.0.1:20502/network/peering/peers?leaves=true', { json: true }), (res) => {
+      return expectAnswer(rp('http://127.0.0.1:20502/network/peering/peers?leaves=true', { json: true }), (res:HttpMerkleOfPeers) => {
         res.should.have.property('depth').equal(1);
         res.should.have.property('nodesCount').equal(1);
         res.should.have.property('leavesCount').equal(2);
@@ -116,7 +111,7 @@ describe("Network Merkle", function() {
     });
 
     it('/peers?leaf=BDD850441E3CDEB9005345B425CDBDA83E7BC7E5D83E9130C6012084F93CD220', function() {
-      return expectAnswer(rp('http://127.0.0.1:20502/network/peering/peers?leaf=BDD850441E3CDEB9005345B425CDBDA83E7BC7E5D83E9130C6012084F93CD220', { json: true }), (res) => {
+      return expectAnswer(rp('http://127.0.0.1:20502/network/peering/peers?leaf=BDD850441E3CDEB9005345B425CDBDA83E7BC7E5D83E9130C6012084F93CD220', { json: true }), (res:HttpMerkleOfPeers) => {
         res.should.have.property('depth').equal(1);
         res.should.have.property('nodesCount').equal(1);
         res.should.have.property('leavesCount').equal(2);
diff --git a/test/integration/peerings.js b/test/integration/network/network-peerings.ts
similarity index 54%
rename from test/integration/peerings.js
rename to test/integration/network/network-peerings.ts
index f9c42296e841edfd09aacd026c013116a6aed438..2c135f6448e74a15f1788f67a928ef246b5d3ad0 100644
--- a/test/integration/peerings.js
+++ b/test/integration/network/network-peerings.ts
@@ -11,25 +11,21 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {NewTestingServer, TestingServer} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
+import {CrawlerDependency} from "../../../app/modules/crawler/index"
+import {Contacter} from "../../../app/modules/crawler/lib/contacter"
+import {PeerDTO} from "../../../app/lib/dto/PeerDTO"
+import {BmaDependency} from "../../../app/modules/bma/index"
+import {RouterDependency} from "../../../app/modules/router"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
 
-const co        = require('co');
-const _         = require('underscore');
 const should    = require('should');
-const duniter     = require('../../index');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const TestUser  = require('./tools/TestUser').TestUser
-const constants = require('../../app/lib/constants');
 const rp        = require('request-promise');
-const httpTest  = require('./tools/http');
-const commit    = require('./tools/commit');
-const sync      = require('./tools/sync');
-const toolbox   = require('./tools/toolbox');
-const contacter  = require('../../app/modules/crawler').CrawlerDependency.duniter.methods.contacter;
-const until     = require('./tools/until');
-const shutDownEngine  = require('./tools/shutDownEngine');
-const multicaster = require('../../app/lib/streams/multicaster');
-const PeerDTO = require('../../app/lib/dto/PeerDTO').PeerDTO
+const httpTest  = require('../tools/http');
+const sync      = require('../tools/sync');
+const toolbox   = require('../tools/toolbox');
+const shutDownEngine  = require('../tools/shutDownEngine');
 
 const expectJSON     = httpTest.expectJSON;
 
@@ -44,20 +40,20 @@ const commonConf = {
   sigQty: 1
 };
 
-let s1, s2, s3, cat, toc, tic
+let s1:TestingServer, s2:TestingServer, s3:TestingServer, cat:TestUser, toc:TestUser, tic:TestUser
 
-let nodeS1;
-let nodeS2;
-let nodeS3;
+let nodeS1:Contacter
+let nodeS2:Contacter
+let nodeS3:Contacter
 
-describe("Network", function() {
+describe("Network peering", function() {
 
   before(function() {
 
-    s1 = duniter(
-      'bb_net1',
-      MEMORY_MODE,
-      _.extend({
+    s1 = NewTestingServer(
+      Underscore.extend({
+        name: 'bb_net1',
+        memory: MEMORY_MODE,
         port: '7784',
         pair: {
           pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
@@ -65,10 +61,10 @@ describe("Network", function() {
         }
       }, commonConf));
 
-    s2 = duniter(
-      'bb_net2',
-      MEMORY_MODE,
-      _.extend({
+    s2 = NewTestingServer(
+      Underscore.extend({
+        name: 'bb_net2',
+        memory: MEMORY_MODE,
         port: '7785',
         pair: {
           pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo',
@@ -76,10 +72,10 @@ describe("Network", function() {
         }
       }, commonConf));
 
-    s3 = duniter(
-      'bb_net3',
-      MEMORY_MODE,
-      _.extend({
+    s3 = NewTestingServer(
+      Underscore.extend({
+        name: 'bb_net3',
+        memory: MEMORY_MODE,
         port: '7786',
         pair: {
           pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV',
@@ -91,86 +87,77 @@ describe("Network", function() {
     toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
     tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
 
-    const commitS1 = commit(s1);
-    const commitS2 = commit(s2);
-    const commitS3 = commit(s3);
-
     return [s1, s2, s3].reduce(function(p, server) {
-      server.addEndpointsDefinitions(() => require('../../app/modules/bma').BmaDependency.duniter.methods.getMainEndpoint(server.conf))
+      server._server.addEndpointsDefinitions(() => BmaDependency.duniter.methods.getMainEndpoint(server.conf))
       return p
         .then(function(){
           return server
             .initWithDAL()
-            .then(bma)
+            .then(BmaDependency.duniter.methods.bma)
             .then(function(bmaAPI){
               return bmaAPI.openConnections()
                 .then(() => {
                   server.bma = bmaAPI;
-                  require('../../app/modules/router').RouterDependency.duniter.methods.routeToNetwork(server);
+                  RouterDependency.duniter.methods.routeToNetwork(server._server);
                 });
             });
         });
     }, Promise.resolve())
 
-      .then(function(){
-        return co(function *() {
-          nodeS1 = contacter('127.0.0.1', s1.conf.port);
-          nodeS2 = contacter('127.0.0.1', s2.conf.port);
-          nodeS3 = contacter('127.0.0.1', s3.conf.port);
-          // Server 1
-          yield cat.createIdentity();
-          yield toc.createIdentity();
-          yield tic.createIdentity();
-          yield toc.cert(cat);
-          yield cat.cert(toc);
-          yield cat.cert(tic);
-          yield cat.join();
-          yield toc.join();
-          yield tic.join();
-          yield commitS1();
-          // Server 2 syncs block 0
-          yield sync(0, 0, s1, s2);
-          yield toolbox.serverWaitBlock(s1, 0)
-          // Server 3 syncs block 0
-          yield sync(0, 0, s1, s3);
-          yield toolbox.serverWaitBlock(s3, 0)
-          yield nodeS1.getPeer().then((peer) => nodeS2.postPeer(PeerDTO.fromJSONObject(peer).getRawSigned())).catch(e => console.error(e))
-          yield nodeS2.getPeer().then((peer) => nodeS1.postPeer(PeerDTO.fromJSONObject(peer).getRawSigned())).catch(e => console.error(e))
-          yield nodeS3.getPeer().then((peer) => nodeS1.postPeer(PeerDTO.fromJSONObject(peer).getRawSigned())).catch(e => console.error(e))
-          yield commitS1();
-          yield [
-            toolbox.serverWaitBlock(s2, 1),
-            toolbox.serverWaitBlock(s3, 1)
-          ];
-          // A block was successfully spread accross the network
-          yield s2.bma.closeConnections();
-          yield commitS1();
-          yield [
-            toolbox.serverWaitBlock(s3, 2)
-          ];
-          // Server 2 syncs block number 2 (it did not have it)
-          yield sync(2, 2, s1, s2);
-          yield toolbox.serverWaitBlock(s2, 2)
-          yield s2.recomputeSelfPeer();
-          yield s2.bma.openConnections();
-          yield new Promise((resolve) => setTimeout(resolve, 1000));
-          yield [
-            toolbox.serverWaitBlock(s2, 4),
-            toolbox.serverWaitBlock(s3, 4),
-            commitS1()
-              .then(commitS1)
-          ];
-          yield [
-            toolbox.serverWaitBlock(s1, 5),
-            toolbox.serverWaitBlock(s2, 5),
-            commitS3()
-          ];
-          yield [
-            toolbox.serverWaitBlock(s1, 6),
-            toolbox.serverWaitBlock(s3, 6),
-            commitS2()
-          ];
-        });
+      .then(async () => {
+        nodeS1 = CrawlerDependency.duniter.methods.contacter('127.0.0.1', s1.conf.port);
+        nodeS2 = CrawlerDependency.duniter.methods.contacter('127.0.0.1', s2.conf.port);
+        nodeS3 = CrawlerDependency.duniter.methods.contacter('127.0.0.1', s3.conf.port);
+        // Server 1
+        await cat.createIdentity();
+        await toc.createIdentity();
+        await tic.createIdentity();
+        await toc.cert(cat);
+        await cat.cert(toc);
+        await cat.cert(tic);
+        await cat.join();
+        await toc.join();
+        await tic.join();
+        await s1.commit();
+        // Server 2 syncs block 0
+        await sync(0, 0, s1, s2);
+        await toolbox.serverWaitBlock(s1._server, 0)
+        // Server 3 syncs block 0
+        await sync(0, 0, s1, s3);
+        await toolbox.serverWaitBlock(s3._server, 0)
+        await nodeS1.getPeer().then((peer) => nodeS2.postPeer(PeerDTO.fromJSONObject(peer).getRawSigned())).catch(e => console.error(e))
+        await nodeS2.getPeer().then((peer) => nodeS1.postPeer(PeerDTO.fromJSONObject(peer).getRawSigned())).catch(e => console.error(e))
+        await nodeS3.getPeer().then((peer) => nodeS1.postPeer(PeerDTO.fromJSONObject(peer).getRawSigned())).catch(e => console.error(e))
+        await s1.commit();
+        await Promise.all([
+          toolbox.serverWaitBlock(s2._server, 1),
+          toolbox.serverWaitBlock(s3._server, 1)
+        ])
+        // A block was successfully spread accross the network
+        await s2.bma.closeConnections();
+        await s1.commit();
+        await toolbox.serverWaitBlock(s3._server, 2)
+        // Server 2 syncs block number 2 (it did not have it)
+        await sync(2, 2, s1, s2);
+        await toolbox.serverWaitBlock(s2._server, 2)
+        await s2.recomputeSelfPeer();
+        await s2.bma.openConnections();
+        await new Promise((resolve) => setTimeout(resolve, 1000));
+        await Promise.all([
+          toolbox.serverWaitBlock(s2._server, 4),
+          toolbox.serverWaitBlock(s3._server, 4),
+          s1.commit().then(() => s1.commit())
+         ])
+        await Promise.all([
+          toolbox.serverWaitBlock(s1._server, 5),
+          toolbox.serverWaitBlock(s2._server, 5),
+          s3.commit()
+        ])
+        await Promise.all([
+          toolbox.serverWaitBlock(s1._server, 6),
+          toolbox.serverWaitBlock(s3._server, 6),
+          s2.commit()
+        ])
       })
       ;
   });
diff --git a/test/integration/peers-same-pubkey.js b/test/integration/network/network-peers-same-pubkey.ts
similarity index 63%
rename from test/integration/peers-same-pubkey.js
rename to test/integration/network/network-peers-same-pubkey.ts
index 3e85615f607b8cf5e553d7802834d6a10bcca791..389a751bf71ccc7c0fc801671e08549bade58680 100644
--- a/test/integration/peers-same-pubkey.js
+++ b/test/integration/network/network-peers-same-pubkey.ts
@@ -11,17 +11,16 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {TestUser} from "../tools/TestUser"
+import {NewTestingServer, serverWaitBlock, TestingServer} from "../tools/toolbox"
+import {PeerDTO} from "../../../app/lib/dto/PeerDTO"
+import {HttpPeer} from "../../../app/modules/bma/lib/dtos"
+import {RouterDependency} from "../../../app/modules/router"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
 
-const co        = require('co');
-const _         = require('underscore');
 const should    = require('should');
-const TestUser  = require('./tools/TestUser').TestUser
-const commit    = require('./tools/commit');
-const sync      = require('./tools/sync');
-const until     = require('./tools/until');
-const toolbox   = require('./tools/toolbox');
-const PeerDTO   = require('../../app/lib/dto/PeerDTO').PeerDTO
+const sync      = require('../tools/sync');
+const until     = require('../tools/until');
 
 const catKeyPair = {
   pair: {
@@ -30,76 +29,73 @@ const catKeyPair = {
   }
 };
 
-let s1, s2, s3, cat, toc
+let s1:TestingServer, s2:TestingServer, s3:TestingServer, cat:TestUser, toc:TestUser
 
 describe("Peer document", function() {
 
-  before(() => co(function*() {
+  before(async () => {
 
-    s1 = toolbox.server(_.clone(catKeyPair));
-    s2 = toolbox.server(_.clone(catKeyPair));
-    s3 = toolbox.server(_.clone(catKeyPair));
+    s1 = NewTestingServer(Underscore.clone(catKeyPair));
+    s2 = NewTestingServer(Underscore.clone(catKeyPair));
+    s3 = NewTestingServer(Underscore.clone(catKeyPair));
 
     cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
     toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
 
-    const commitS1 = commit(s1);
-    const commitS2 = commit(s2);
-
-    yield [s1, s2, s3].reduce((p, server) => co(function*() {
-      yield p;
-      yield server.initDalBmaConnections()
-      require('../../app/modules/router').RouterDependency.duniter.methods.routeToNetwork(server);
-    }), Promise.resolve());
+    await [s1, s2, s3].reduce(async (p, server) => {
+      await p;
+      await server.initDalBmaConnections()
+      RouterDependency.duniter.methods.routeToNetwork(server._server)
+    }, Promise.resolve())
 
     // Server 1
-    yield cat.createIdentity();
-    yield toc.createIdentity();
-    yield toc.cert(cat);
-    yield cat.cert(toc);
-    yield cat.join();
-    yield toc.join();
-    yield commitS1(); // block#0
-    yield commitS1(); // block#1
-    yield s1.recomputeSelfPeer(); // peer#1
-    yield commitS1(); // block#2
+    await cat.createIdentity();
+    await toc.createIdentity();
+    await toc.cert(cat);
+    await cat.cert(toc);
+    await cat.join();
+    await toc.join();
+    await s1.commit(); // block#0
+    await s1.commit(); // block#1
+    await s1.recomputeSelfPeer(); // peer#1
+    await s1.commit(); // block#2
     // // s2 syncs from s1
-    yield sync(0, 2, s1, s2);
-    yield toolbox.serverWaitBlock(s1, 2)
-    yield [
-      s1.get('/network/peering').then((peer) => s2.post('/network/peering/peers', { peer: PeerDTO.fromJSONObject(peer).getRawSigned() })), // peer#2
+    await sync(0, 2, s1, s2);
+    await serverWaitBlock(s1._server, 2)
+    await Promise.all([
+      s1.get('/network/peering').then((peer:HttpPeer) => s2.post('/network/peering/peers', { peer: PeerDTO.fromJSONObject(peer).getRawSigned() })), // peer#2
       until(s2, 'peer', 1)
-    ];
+    ])
 
-    yield [
-      commitS2(), // block#3
-      toolbox.serverWaitBlock(s1, 3)
-    ];
+    await Promise.all([
+      s2.commit(), // block#3
+      serverWaitBlock(s1._server, 3)
+    ])
 
-    yield sync(0, 3, s1, s3);
-    yield toolbox.serverWaitBlock(s3, 3)
+    await sync(0, 3, s1, s3);
+    await serverWaitBlock(s3._server, 3)
 
-    const peer1 = yield s1.get('/network/peering');
+    const peer1 = await s1.get('/network/peering');
     peer1.should.have.property("block").match(/^2-/);
-    yield [
+    await Promise.all([
       s3.post('/network/peering/peers', { peer: PeerDTO.fromJSONObject(peer1).getRawSigned() }), // peer#3
       until(s3, 'peer', 2)
-    ];
-    const peer3 = yield s3.get('/network/peering');
+    ])
+    const peer3 = await s3.get('/network/peering');
     peer3.should.have.property("block").match(/^3-/);
 
-    yield [
-      commitS2(), // block#4
-      toolbox.serverWaitBlock(s1, 4),
-      toolbox.serverWaitBlock(s3, 4)
-    ];
+    await Promise.all([
+      s2.commit(), // block#4
+      serverWaitBlock(s1._server, 4),
+      serverWaitBlock(s3._server, 4)
+    ])
 
-    yield [
-      commitS1(), // block#5
-      toolbox.serverWaitBlock(s2, 5),
-      toolbox.serverWaitBlock(s3, 5)
-    ];
-  }));
+    await Promise.all([
+      s1.commit(), // block#5
+      serverWaitBlock(s2._server, 5),
+      serverWaitBlock(s3._server, 5)
+    ])
+  })
 
   after(() => {
     return Promise.all([
@@ -115,25 +111,25 @@ describe("Peer document", function() {
       leavesCount: 1
     }));
 
-    it('leaf data', () => co(function*() {
-      const data = yield s1.get('/network/peering/peers?leaves=true');
+    it('leaf data', async () => {
+      const data = await s1.get('/network/peering/peers?leaves=true');
       const leaf = data.leaves[0];
-      const res = yield s1.get('/network/peering/peers?leaf=' + leaf);
+      const res = await s1.get('/network/peering/peers?leaf=' + leaf);
       res.leaf.value.should.have.property("pubkey").equal('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
       res.leaf.value.should.have.property("block").match(new RegExp('^3-'));
       res.leaf.value.should.have.property("raw").match(new RegExp('.*Block: 3-.*'));
       res.leaf.value.should.have.property("endpoints").length(3);
-    }));
+    })
 
 
-    it('peers', () => s1.expectThat('/network/peering', (res) => {
+    it('peers', () => s1.expectThat('/network/peering', (res:HttpPeer) => {
       res.should.have.property("pubkey").equal('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
       res.should.have.property("block").match(new RegExp('^3-'));
       res.should.have.property("endpoints").length(3);
     }));
 
 
-    it('peering should have been updated by node 1', () => s1.expectThat('/network/peering', (res) => {
+    it('peering should have been updated by node 1', () => s1.expectThat('/network/peering', (res:HttpPeer) => {
       res.should.have.property("pubkey").equal('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
       res.should.have.property("block").match(new RegExp('^3-'));
       res.should.have.property("endpoints").length(3);
@@ -152,18 +148,18 @@ describe("Peer document", function() {
     }));
 
 
-    it('leaf data', () => co(function*() {
-      const data = yield s2.get('/network/peering/peers?leaves=true');
+    it('leaf data', async () => {
+      const data = await s2.get('/network/peering/peers?leaves=true');
       const leaf = data.leaves[0];
-      const res = yield s2.get('/network/peering/peers?leaf=' + leaf);
+      const res = await s2.get('/network/peering/peers?leaf=' + leaf);
       res.leaf.value.should.have.property("pubkey").equal('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
       res.leaf.value.should.have.property("block").match(new RegExp('^3-'));
       res.leaf.value.should.have.property("raw").match(new RegExp('.*Block: 3-.*'));
       res.leaf.value.should.have.property("endpoints").length(3);
-    }));
+    })
 
 
-    it('peering should have been updated by node 1', () => s2.expectThat('/network/peering', (res) => {
+    it('peering should have been updated by node 1', () => s2.expectThat('/network/peering', (res:HttpPeer) => {
       res.should.have.property("pubkey").equal('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
       res.should.have.property("block").match(new RegExp('^3-'));
       res.should.have.property("endpoints").length(3);
@@ -181,17 +177,17 @@ describe("Peer document", function() {
       leavesCount: 1
     }));
 
-    it('leaf data', () => co(function*() {
-      const data = yield s3.get('/network/peering/peers?leaves=true');
+    it('leaf data', async () => {
+      const data = await s3.get('/network/peering/peers?leaves=true');
       const leaf = data.leaves[0];
-      const res = yield s3.get('/network/peering/peers?leaf=' + leaf);
+      const res = await s3.get('/network/peering/peers?leaf=' + leaf);
       res.leaf.value.should.have.property("pubkey").equal('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
       res.leaf.value.should.have.property("block").match(new RegExp('^3-'));
       res.leaf.value.should.have.property("raw").match(new RegExp('.*Block: 3-.*'));
       res.leaf.value.should.have.property("endpoints").length(3);
-    }));
+    })
 
-    it('peering should have been updated by node 1', () => s3.expectThat('/network/peering', (res) => {
+    it('peering should have been updated by node 1', () => s3.expectThat('/network/peering', (res:HttpPeer) => {
       res.should.have.property("pubkey").equal('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
       res.should.have.property("block").match(new RegExp('^3-'));
       res.should.have.property("endpoints").length(3);
@@ -200,6 +196,6 @@ describe("Peer document", function() {
     it('current block', () => s3.expectJSON('/blockchain/current', {
       number: 5,
       issuer: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd'
-    }));
-  });
-});
+    }))
+  })
+})
diff --git a/test/integration/network/network-update.ts b/test/integration/network/network-update.ts
new file mode 100644
index 0000000000000000000000000000000000000000..53c5a98700f3242b9c1178296ad091f9aaae95a4
--- /dev/null
+++ b/test/integration/network/network-update.ts
@@ -0,0 +1,105 @@
+// Source file from duniter: Crypto-currency software to manage libre currency such as Äž1
+// Copyright (C) 2018  Cedric Moreau <cem.moreau@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+
+"use strict";
+
+import {TestUser} from "../tools/TestUser"
+import {NewTestingServer, TestingServer} from "../tools/toolbox"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
+import {RouterDependency} from "../../../app/modules/router"
+
+const sync      = require('../tools/sync');
+
+const catKeyPair = {
+  pair: {
+    pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
+    sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
+  }
+};
+
+const tocKeyPair = {
+  pair: {
+    pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo',
+    sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'
+  }
+};
+
+let s1:TestingServer, s2:TestingServer, cat:TestUser, toc:TestUser
+
+
+describe("Network updating", function() {
+
+  before(async () => {
+
+    s1 = NewTestingServer(Underscore.clone(catKeyPair));
+    s2 = NewTestingServer(Underscore.clone(tocKeyPair));
+
+    cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
+    toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
+
+    await [s1, s2].reduce(async (p, server) => {
+      await p;
+      await server.initDalBmaConnections()
+      RouterDependency.duniter.methods.routeToNetwork(server._server);
+    }, Promise.resolve())
+
+    // Server 1
+    await cat.createIdentity();
+    await toc.createIdentity();
+    await toc.cert(cat);
+    await cat.cert(toc);
+    await cat.join();
+    await toc.join();
+    for (const i in Underscore.range(32)) {
+      await s1.commit(); // block#0
+    }
+    // // s2 syncs from s1
+    await sync(0, 31, s1, s2);
+
+    const b2 = await s1.makeNext({});
+    await s1.postBlock(b2);
+    await s2.postBlock(b2);
+    await s1.recomputeSelfPeer(); // peer#1
+    await s1.sharePeeringWith(s2);
+    const b3 = await s1.makeNext({});
+    await s1.postBlock(b3);
+    await s2.postBlock(b3);
+    await s2.waitToHaveBlock(b3.number);
+    await s1.recomputeSelfPeer(); // peer#1
+    await s1.sharePeeringWith(s2);
+  });
+
+    describe("Server 1 /network/peering", function() {
+
+      it('/peers?leaf=LEAFDATA', async () => {
+        const data = await s1.get('/network/peering/peers?leaves=true');
+        const leaf = data.leaves[0];
+        const res = await s1.get('/network/peering/peers?leaf=' + leaf);
+        res.leaf.value.should.have.property("pubkey").equal('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
+        res.leaf.value.should.have.property("block").match(new RegExp('^3-'));
+        res.leaf.value.should.have.property("raw").match(new RegExp('.*Block: 3-.*'));
+      })
+    });
+
+    describe("Server 2 /network/peering", function() {
+
+      it('/peers?leaf=LEAFDATA', async () => {
+        const data = await s2.get('/network/peering/peers?leaves=true');
+        const leaf = data.leaves[0];
+        const res = await s2.get('/network/peering/peers?leaf=' + leaf);
+        res.leaf.value.should.have.property("pubkey").equal('DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo');
+        res.leaf.value.should.have.property("block").match(new RegExp('^0-'));
+        res.leaf.value.should.have.property("raw").match(new RegExp('.*Block: 0-.*'));
+      })
+    })
+  })
diff --git a/test/integration/newcomers-shuffling.js b/test/integration/newcomers-shuffling.js
index 31fb6f1dfcda2d6393712c597e1ec7217f2bdfc4..0a4438d0205274ea1e237fb1db9147b1c22e74ad 100644
--- a/test/integration/newcomers-shuffling.js
+++ b/test/integration/newcomers-shuffling.js
@@ -13,7 +13,6 @@
 
 "use strict";
 
-const _ = require('underscore');
 const co        = require('co');
 const assert    = require('assert');
 const TestUser  = require('./tools/TestUser').TestUser
diff --git a/test/integration/peer-outdated.js b/test/integration/peer-outdated.js
index 79a61acffb5b52c5b85c8528b2ec54791d543ead..d71f0b3cf05915f06f63170e1e819b46dd9782b4 100644
--- a/test/integration/peer-outdated.js
+++ b/test/integration/peer-outdated.js
@@ -16,7 +16,6 @@
 const co        = require('co');
 const should    = require('should');
 const es        = require('event-stream');
-const _         = require('underscore');
 const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
 const TestUser  = require('./tools/TestUser').TestUser
 const commit    = require('./tools/commit');
diff --git a/test/integration/register-fork-blocks.js b/test/integration/register-fork-blocks.js
index e905ed939ec39ec3a2d7bfad99af231a4b780db4..7e7d5d75309205f1ab478bef9e7ca207ff68a083 100644
--- a/test/integration/register-fork-blocks.js
+++ b/test/integration/register-fork-blocks.js
@@ -13,7 +13,6 @@
 
 "use strict";
 
-const _ = require('underscore');
 const co        = require('co');
 const assert    = require('assert');
 const TestUser  = require('./tools/TestUser').TestUser
diff --git a/test/integration/revoked_pubkey_replay.ts b/test/integration/revoked_pubkey_replay.ts
index e0a32f2ede9aa57a05c157262f1762e894cb39a2..39583d8cd7c65fe3cf99acbd5c7c525d2f576886 100644
--- a/test/integration/revoked_pubkey_replay.ts
+++ b/test/integration/revoked_pubkey_replay.ts
@@ -12,8 +12,8 @@
 // GNU Affero General Public License for more details.
 
 import {simpleNodeWith2Users, TestingServer} from "./tools/toolbox"
+import {Underscore} from "../../app/lib/common-libs/underscore"
 
-const _ = require('underscore')
 const TestUser = require('./tools/TestUser').TestUser
 
 describe("Revoked pubkey replay", function() {
@@ -47,7 +47,7 @@ describe("Revoked pubkey replay", function() {
     await s1.commit()
     await s1.expect('/wot/members', (res:any) => {
       res.should.have.property('results').length(3)
-      const ticEntries = _.filter(res.results, (entry:any) => entry.uid === 'tic')
+      const ticEntries = Underscore.filter(res.results, (entry:any) => entry.uid === 'tic')
       ticEntries.should.have.length(1)
     })
   })
@@ -63,7 +63,7 @@ describe("Revoked pubkey replay", function() {
     await s1.commit()
     await s1.expect('/wot/members', (res:any) => {
       res.should.have.property('results').length(2)
-      const ticEntries = _.filter(res.results, (entry:any) => entry.uid === 'tic')
+      const ticEntries = Underscore.filter(res.results, (entry:any) => entry.uid === 'tic')
       ticEntries.should.have.length(0)
     })
   })
diff --git a/test/integration/scenarios/malformed-documents.js b/test/integration/scenarios/malformed-documents.js
deleted file mode 100644
index 8ec1d222447895df14c2cb46e31da14ebd63f5d2..0000000000000000000000000000000000000000
--- a/test/integration/scenarios/malformed-documents.js
+++ /dev/null
@@ -1,50 +0,0 @@
-// Source file from duniter: Crypto-currency software to manage libre currency such as Äž1
-// Copyright (C) 2018  Cedric Moreau <cem.moreau@gmail.com>
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU Affero General Public License for more details.
-
-"use strict";
-
-const request = require('request');
-
-module.exports = function(node1) {
-
-  const malformedTransaction = "Version: 2\n" +
-    "Type: Transaction\n" +
-    "Currency: null\n" +
-    "Issuers:\n" +
-    "G2CBgZBPLe6FSFUgpx2Jf1Aqsgta6iib3vmDRA1yLiqU\n" +
-    "Inputs:\n" +
-    "0:T:1536:539CB0E60CD5F55CF1BE96F067E73BF55C052112:1.0\n" +
-    "Outputs:Comment: mon comments\n";
-
-
-  function sendRaw (raw) {
-    return function(done) {
-      post('/tx/process', {
-        "transaction": raw
-      }, done);
-    }
-  }
-
-  function post(uri, data, done) {
-    const postReq = request.post({
-      "uri": 'http://' + [node1.server.conf.remoteipv4, node1.server.conf.remoteport].join(':') + uri,
-      "timeout": 1000 * 10
-    }, function (err, res, body) {
-      done(err, res, body);
-    });
-    postReq.form(data);
-  }
-  return [
-    sendRaw(malformedTransaction)
-  ];
-};
diff --git a/test/integration/single-document-treatment.js b/test/integration/single-document-treatment.js
index 58aa5229afb2810676af006837910cda605708b1..eeb185128118188b08e3cade44e770c76f8541d5 100644
--- a/test/integration/single-document-treatment.js
+++ b/test/integration/single-document-treatment.js
@@ -13,7 +13,6 @@
 
 "use strict";
 
-const _ = require('underscore');
 const co        = require('co');
 const assert    = require('assert');
 const TestUser  = require('./tools/TestUser').TestUser
diff --git a/test/integration/sources_property.js b/test/integration/sources_property.js
index 89467dc86cb71f98c81b8b9b88288fad89bafddc..737cd5053e8ee5c691acd30c3ddfb4c7f529e9fd 100644
--- a/test/integration/sources_property.js
+++ b/test/integration/sources_property.js
@@ -14,7 +14,6 @@
 "use strict";
 
 const co = require('co');
-const _ = require('underscore');
 const should = require('should');
 const assert = require('assert');
 const constants = require('../../app/lib/constants');
diff --git a/test/integration/start_generate_blocks.js b/test/integration/start_generate_blocks.js
deleted file mode 100644
index 6cef8f45240145f9e5158d3bcec9d406cf108ceb..0000000000000000000000000000000000000000
--- a/test/integration/start_generate_blocks.js
+++ /dev/null
@@ -1,150 +0,0 @@
-// Source file from duniter: Crypto-currency software to manage libre currency such as Äž1
-// Copyright (C) 2018  Cedric Moreau <cem.moreau@gmail.com>
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU Affero General Public License for more details.
-
-"use strict";
-
-const co        = require('co');
-const _         = require('underscore');
-const duniter     = require('../../index');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const TestUser  = require('./tools/TestUser').TestUser
-const rp        = require('request-promise');
-const httpTest  = require('./tools/http');
-const commit    = require('./tools/commit');
-const until     = require('./tools/until');
-const toolbox   = require('./tools/toolbox');
-const PeerDTO   = require('../../app/lib/dto/PeerDTO').PeerDTO
-const contacter  = require('../../app/modules/crawler').CrawlerDependency.duniter.methods.contacter;
-const sync      = require('./tools/sync');
-const shutDownEngine  = require('./tools/shutDownEngine');
-
-const expectJSON     = httpTest.expectJSON;
-
-const MEMORY_MODE = true;
-const commonConf = {
-  bmaWithCrawler: true,
-  ipv4: '127.0.0.1',
-  remoteipv4: '127.0.0.1',
-  currency: 'bb',
-  httpLogs: true,
-  forksize: 0,
-  sigQty: 1
-};
-
-let s1, s2, cat, toc, tic, tuc
-
-let nodeS1;
-let nodeS2;
-
-describe("Generation", function() {
-
-  before(function() {
-
-    return co(function *() {
-
-      s1 = duniter(
-        '/bb7',
-        MEMORY_MODE,
-        _.extend({
-          port: '7790',
-          pair: {
-            pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
-            sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
-          },
-          powDelay: 1
-        }, commonConf));
-
-      s2 = duniter(
-        '/bb7_2',
-        MEMORY_MODE,
-        _.extend({
-          port: '7791',
-          pair: {
-            pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo',
-            sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'
-          },
-          powDelay: 1
-        }, commonConf));
-
-      const commitS1 = commit(s1);
-
-      cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-      toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
-      tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
-      tuc = new TestUser('tuc', { pub: '3conGDUXdrTGbQPMQQhEC4Ubu1MCAnFrAYvUaewbUhtk', sec: '5ks7qQ8Fpkin7ycXpxQSxxjVhs8VTzpM3vEBMqM7NfC1ZiFJ93uQryDcoM93Mj77T6hDAABdeHZJDFnkDb35bgiU'}, { server: s1 });
-
-      let servers = [s1, s2];
-      for (const server of servers) {
-        server.addEndpointsDefinitions(() => require('../../app/modules/bma').BmaDependency.duniter.methods.getMainEndpoint(server.conf))
-        yield server.initWithDAL();
-        server.bma = yield bma(server);
-        yield server.bma.openConnections();
-        require('../../app/modules/router').RouterDependency.duniter.methods.routeToNetwork(server);
-        yield server.PeeringService.generateSelfPeer(server.conf);
-        const prover = require('../../app/modules/prover').ProverDependency.duniter.methods.prover(server);
-        server.startBlockComputation = () => prover.startService();
-        server.stopBlockComputation = () => prover.stopService();
-      }
-      nodeS1 = contacter('127.0.0.1', s1.conf.port);
-      nodeS2 = contacter('127.0.0.1', s2.conf.port);
-      // Server 1
-      yield cat.createIdentity();
-      yield toc.createIdentity();
-      yield toc.cert(cat);
-      yield cat.cert(toc);
-      yield cat.join();
-      yield toc.join();
-      yield commitS1();
-      // Server 2 syncs block 0
-      yield sync(0, 0, s1, s2);
-      // Let each node know each other
-      let peer1 = yield nodeS1.getPeer();
-      yield nodeS2.postPeer(PeerDTO.fromJSONObject(peer1).getRawSigned());
-      let peer2 = yield nodeS2.getPeer();
-      yield nodeS1.postPeer(PeerDTO.fromJSONObject(peer2).getRawSigned());
-      s1.startBlockComputation();
-      yield until(s2, 'block', 1);
-      s2.startBlockComputation();
-      s1.conf.powDelay = 2000;
-      s2.conf.powDelay = 2000;
-      yield [
-        toolbox.serverWaitBlock(s1, 3),
-        toolbox.serverWaitBlock(s2, 3)
-      ];
-      s1.stopBlockComputation();
-      s2.stopBlockComputation();
-    });
-  });
-
-  after(() => {
-    return Promise.all([
-      shutDownEngine(s1),
-      shutDownEngine(s2)
-    ])
-  })
-
-  describe("Server 1 /blockchain", function() {
-
-    it('/current should exist', function() {
-      return expectJSON(rp('http://127.0.0.1:7790/blockchain/current', { json: true }), {
-        number: 3
-      });
-    });
-
-    it('/current should exist on other node too', function() {
-      return expectJSON(rp('http://127.0.0.1:7791/blockchain/current', { json: true }), {
-        number: 3
-      });
-    });
-  });
-});
diff --git a/test/integration/tools/TestUser.ts b/test/integration/tools/TestUser.ts
index edf7b8764d5dd0cd1b7538557e6bf1f0bdc4b126..cf76f7408f7db2e2b7e76637f6fd41ea17616758 100644
--- a/test/integration/tools/TestUser.ts
+++ b/test/integration/tools/TestUser.ts
@@ -24,9 +24,10 @@ import {parsers} from "../../../app/lib/common-libs/parsers/index"
 import {TransactionDTO} from "../../../app/lib/dto/TransactionDTO"
 import {PeerDTO} from "../../../app/lib/dto/PeerDTO"
 import {Contacter} from "../../../app/modules/crawler/lib/contacter"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
+import {HttpLookup} from "../../../app/modules/bma/lib/dtos"
 
 const request	= require('request')
-const _ = require('underscore')
 
 export interface TestInput {
   src:string
@@ -92,7 +93,7 @@ export class TestUser {
   public async makeCert(user:TestUser, fromServer?:TestingServer, overrideProps?:any) {
     const lookup = await this.lookup(user.pub, fromServer)
     const current = await this.node.server.BlockchainService.current()
-    const idty = _.filter(lookup.results[0].uids, (uidEntry:{ uid: string }) => uidEntry.uid === user.uid)[0]
+    const idty = Underscore.filter(lookup.results[0].uids, uidEntry => uidEntry.uid === user.uid)[0]
     let buid = current ? Buid.format.buid(current.number, current.hash) : CommonConstants.SPECIAL_BLOCK
     const cert = {
       "version": CommonConstants.DOCUMENTS_VERSION,
@@ -105,7 +106,7 @@ export class TestUser {
       "buid": buid,
       "sig": ""
     }
-    _.extend(cert, overrideProps || {});
+    Underscore.extend(cert, overrideProps || {});
     const rawCert = CertificationDTO.fromJSONObject(cert).getRawUnSigned()
     cert.sig = KeyGen(this.pub, this.sec).signSync(rawCert)
     return CertificationDTO.fromJSONObject(cert)
@@ -126,9 +127,9 @@ export class TestUser {
     return await this.sendMembership("OUT")
   }
 
-  public async makeRevocation(givenLookupIdty?:any, overrideProps?:any) {
+  public async makeRevocation(givenLookupIdty?:HttpLookup, overrideProps?:any) {
     const res = givenLookupIdty || (await this.lookup(this.pub));
-    const matchingResult = _.filter(res.results[0].uids, (uidEntry: { uid:string }) => uidEntry.uid === this.uid)[0]
+    const matchingResult = Underscore.filter(res.results[0].uids, uidEntry => uidEntry.uid === this.uid)[0]
     const idty = {
       uid: matchingResult.uid,
       buid: matchingResult.meta.timestamp,
@@ -142,7 +143,7 @@ export class TestUser {
       "buid": idty.buid,
       "revocation": ''
     };
-    _.extend(revocation, overrideProps || {});
+    Underscore.extend(revocation, overrideProps || {});
     const rawRevocation = RevocationDTO.fromJSONObject(revocation).getRawUnsigned()
     revocation.revocation = KeyGen(this.pub, this.sec).signSync(rawRevocation);
     return RevocationDTO.fromJSONObject(revocation)
@@ -170,7 +171,7 @@ export class TestUser {
       "certts": idty.meta.timestamp,
       "signature": ""
     };
-    _.extend(join, overrideProps || {});
+    Underscore.extend(join, overrideProps || {});
     const rawJoin = MembershipDTO.fromJSONObject(join).getRaw()
     join.signature = KeyGen(this.pub, this.sec).signSync(rawJoin)
     return MembershipDTO.fromJSONObject(join)
@@ -183,7 +184,7 @@ export class TestUser {
     })
   }
 
-  public send(amount:number, recipient:string, comment?:string) {
+  public send(amount:number, recipient:TestUser|string, comment?:string) {
     const that = this
     return async function(done:(e?:any)=>void) {
       try {
@@ -351,7 +352,7 @@ export class TestUser {
       block: '2-00008DF633FC158F9DB4864ABED696C1AA0FE5D617A7B5F7AB8DE7CA2EFCD4CB',
       endpoints: endpoints
     });
-    _.extend(peer, overrideProps || {});
+    Underscore.extend(peer, overrideProps || {});
     const rawPeer = PeerDTO.fromJSONObject(peer).getRawUnsigned()
     peer.signature = KeyGen(this.pub, this.sec).signSync(rawPeer)
     return PeerDTO.fromJSONObject(peer)
@@ -400,14 +401,14 @@ export class TestUser {
     });
   }
 
-  public async lookup(pubkey:string, fromServer?:TestingServer) {
+  public async lookup(pubkey:string, fromServer?:TestingServer): Promise<HttpLookup> {
     const node2 = await this.getContacter(fromServer)
     return node2.getLookup(pubkey);
   }
 
-  public async sendP(amount:number, userid:string, comment?:string) {
+  public async sendP(amount:number, userid:TestUser|string, comment?:string) {
     return new Promise((res, rej) => {
-      this.send(amount, userid, comment)((err) => {
+      this.send(amount, userid, comment)((err:any) => {
         if (err) return rej(err)
         res()
       })
diff --git a/test/integration/tools/commit.js b/test/integration/tools/commit.js
index bb5804a8ed22526cd12426261b7eb3cd94fe39a7..91e05bccf5b7d4bb3bae5b242aa797a6948ee945 100644
--- a/test/integration/tools/commit.js
+++ b/test/integration/tools/commit.js
@@ -13,7 +13,7 @@
 
 "use strict";
 
-var _  = require('underscore');
+const Underscore = require('../../../app/lib/common-libs/underscore').Underscore;
 var co = require('co');
 var rp = require('request-promise');
 var logger = require('../../../app/lib/logger').NewLogger('test');
@@ -24,7 +24,7 @@ module.exports = function makeBlockAndPost(theServer, extraProps, noWait) {
   return function(manualValues) {
     if (extraProps) {
       manualValues = manualValues || {};
-      manualValues = _.extend(manualValues, extraProps);
+      manualValues = Underscore.extend(manualValues, extraProps);
     }
     return co(function *() {
       if (!theServer._utProver) {
diff --git a/test/integration/tools/http.js b/test/integration/tools/http.js
index a8e13ba87a613af0ac18a5364fd6df868eb8b331..c6f4e0b002737e18b425a87f63a3c39ca3172940 100644
--- a/test/integration/tools/http.js
+++ b/test/integration/tools/http.js
@@ -16,7 +16,7 @@
 const co = require('co');
 const should    = require('should');
 const assert    = require('assert');
-const _         = require('underscore');
+const Underscore = require('../../../app/lib/common-libs/underscore').Underscore;
 
 module.exports = {
 
@@ -66,7 +66,7 @@ module.exports = {
   expectJSON: async function expectJSON(promise, json) {
     try {
       const resJson = await promise;
-      _.keys(json).forEach(function(key){
+      Underscore.keys(json).forEach(function(key){
         resJson.should.have.property(key).equal(json[key]);
       });
     } catch (err) {
diff --git a/test/integration/tools/node.js b/test/integration/tools/node.js
index 57f696cd56ca7cc981e65d6eaf90ace83005d14c..e4df8cda7d598928049f6c5bbaa0b84f8e6770e5 100644
--- a/test/integration/tools/node.js
+++ b/test/integration/tools/node.js
@@ -13,7 +13,7 @@
 
 "use strict";
 var co = require('co');
-var _ = require('underscore');
+const Underscore = require('../../../app/lib/common-libs/underscore').Underscore;
 var async  = require('async');
 var request  = require('request');
 var contacter = require('../../../app/modules/crawler').CrawlerDependency.duniter.methods.contacter;
@@ -166,11 +166,11 @@ function Node (dbName, options) {
           config: {
             onLoading: (conf, program) => co(function*() {
               const overConf = ConfDTO.complete(options);
-              _.extend(conf, overConf);
+              Underscore.extend(conf, overConf);
             })
           },
           service: {
-            process: (server) => _.extend(server, {
+            process: (server) => Underscore.extend(server, {
               startService: () => {
                 logger.debug('Server Servie Started!');
               }
diff --git a/test/integration/tools/sync.js b/test/integration/tools/sync.js
index b453100665f011266382cd45bf2b33c1bd3192ed..de088fb0020c66db1dc939b8071ed2c37796dbf3 100644
--- a/test/integration/tools/sync.js
+++ b/test/integration/tools/sync.js
@@ -14,12 +14,12 @@
 "use strict";
 
 const co = require('co');
-const _  = require('underscore');
+const Underscore = require('../../../app/lib/common-libs/underscore').Underscore;
 const rp = require('request-promise');
 
 module.exports = function makeBlockAndPost(fromBlock, toBlock, fromServer, toServer) {
   // Sync blocks
-  return _.range(fromBlock, toBlock + 1).reduce((p, number) => co(function*(){
+  return Underscore.range(fromBlock, toBlock + 1).reduce((p, number) => co(function*(){
     yield p;
     const json = yield rp('http://' + fromServer.conf.ipv4 + ':' + fromServer.conf.port + '/blockchain/block/' + number, { json: true });
     yield toServer.writeBlock(json)
diff --git a/test/integration/tools/toolbox.ts b/test/integration/tools/toolbox.ts
index 3edfff9c970f4e766548285b9d888b0cedce984a..e2ed9285c4d367f1ebfa2a65f0ba49728fc26d41 100644
--- a/test/integration/tools/toolbox.ts
+++ b/test/integration/tools/toolbox.ts
@@ -19,7 +19,7 @@ import * as stream from "stream"
 import {RevocationDTO} from "../../../app/lib/dto/RevocationDTO"
 import {IdentityDTO} from "../../../app/lib/dto/IdentityDTO"
 import {PeerDTO} from "../../../app/lib/dto/PeerDTO"
-import {Network} from "../../../app/modules/bma/lib/network"
+import {BmaApi, Network} from "../../../app/modules/bma/lib/network"
 import {DBIdentity} from "../../../app/lib/dal/sqliteDAL/IdentityDAL"
 import {CertificationDTO} from "../../../app/lib/dto/CertificationDTO"
 import {BlockchainService} from "../../../app/service/BlockchainService"
@@ -39,11 +39,11 @@ import {TestUser} from "./TestUser"
 import {RouterDependency} from "../../../app/modules/router"
 import {ProverDependency} from "../../../app/modules/prover/index"
 import {WS2PClient} from "../../../app/modules/ws2p/lib/WS2PClient"
-import {DBPeer} from "../../../app/lib/dal/sqliteDAL/PeerDAL"
 import {DBBlock} from "../../../app/lib/db/DBBlock"
+import {DBPeer} from "../../../app/lib/db/DBPeer"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
 
 const assert      = require('assert');
-const _           = require('underscore');
 const rp          = require('request-promise');
 const es          = require('event-stream');
 const WebSocketServer = require('ws').Server
@@ -65,30 +65,6 @@ export const getNewTestingPort = () => {
   return PORT++
 }
 
-export const shouldFail = async (promise:Promise<any>, message:string|null = null) => {
-  try {
-    await promise;
-    throw '{ "message": "Should have thrown an error" }'
-  } catch(e) {
-    let err = e
-    if (typeof e === "string") {
-      err = JSON.parse(e)
-    }
-    err.should.have.property('message').equal(message);
-  }
-}
-export const assertThrows = async (promise:Promise<any>, message:string|null = null) => {
-  try {
-    await promise;
-    throw "Should have thrown"
-  } catch(e) {
-    if (e === "Should have thrown") {
-      throw e
-    }
-    assert.equal(e, message)
-  }
-}
-
 export const simpleUser = (uid:string, keyring:{ pub:string, sec:string }, server:TestingServer) => {
   return new TestUser(uid, keyring, { server });
 }
@@ -97,8 +73,8 @@ export const simpleNetworkOf2NodesAnd2Users = async (options:any) => {
   const catKeyring = { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'};
   const tacKeyring = { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'};
 
-  const s1 = NewTestingServer(_.extend({ pair: catKeyring }, options || {}));
-  const s2 = NewTestingServer(_.extend({ pair: tacKeyring }, options || {}));
+  const s1 = NewTestingServer(Underscore.extend({ pair: catKeyring }, options || {}));
+  const s2 = NewTestingServer(Underscore.extend({ pair: tacKeyring }, options || {}));
 
   const cat = new TestUser('cat', catKeyring, { server: s1 });
   const tac = new TestUser('tac', tacKeyring, { server: s1 });
@@ -129,7 +105,7 @@ export const simpleNodeWith2Users = async (options:any) => {
   const catKeyring = { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'};
   const tacKeyring = { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'};
 
-  const s1 = NewTestingServer(_.extend({ pair: catKeyring }, options || {}));
+  const s1 = NewTestingServer(Underscore.extend({ pair: catKeyring }, options || {}));
 
   const cat = new TestUser('cat', catKeyring, { server: s1 });
   const tac = new TestUser('tac', tacKeyring, { server: s1 });
@@ -151,7 +127,7 @@ export const simpleNodeWith2otherUsers = async (options:any) => {
   const ticKeyring = { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'};
   const tocKeyring = { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'};
 
-  const s1 = NewTestingServer(_.extend({ pair: ticKeyring }, options || {}));
+  const s1 = NewTestingServer(Underscore.extend({ pair: ticKeyring }, options || {}));
 
   const tic = new TestUser('cat', ticKeyring, { server: s1 });
   const toc = new TestUser('tac', tocKeyring, { server: s1 });
@@ -262,7 +238,7 @@ export const NewTestingServer = (conf:any) => {
   const server = new Server(
     '~/.config/duniter/' + (conf.homename || 'dev_unit_tests'),
     conf.memory !== undefined ? conf.memory : MEMORY_MODE,
-    _.extend(conf, commonConf));
+    Underscore.extend(conf, commonConf));
 
   return new TestingServer(port, server)
 }
@@ -336,7 +312,7 @@ export class TestingServer {
 
   private prover:Prover
   private permaProver:PermanentProver
-  private bma:any
+  public bma:BmaApi
 
   constructor(
     private port:number,
@@ -377,6 +353,10 @@ export class TestingServer {
     return this.server.home
   }
 
+  initWithDAL() {
+    return this.server.initWithDAL()
+  }
+
   revert(): Promise<DBBlock> {
     return this.server.revert()
   }
@@ -482,7 +462,7 @@ export class TestingServer {
     return httpTest.expectJSON(rp(this.url(uri), { json: true }), expectations);
   }
 
-  expectError(uri:string, code:number, message:string) {
+  expectError(uri:string, code:number, message = '') {
     return httpTest.expectError(code, message, rp(this.url(uri), { json: true }));
   }
 
diff --git a/test/integration/crosschain-test.js b/test/integration/transactions/transaction-crosschain.ts
similarity index 57%
rename from test/integration/crosschain-test.js
rename to test/integration/transactions/transaction-crosschain.ts
index 22c436238f7400100e78be9b5a5a9b7c082031cd..463e77f4ef9550439e0176808a567c966bb72d48 100644
--- a/test/integration/crosschain-test.js
+++ b/test/integration/transactions/transaction-crosschain.ts
@@ -11,19 +11,16 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {NewTestingServer, TestingServer} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
+import {HttpSources} from "../../../app/modules/bma/lib/dtos"
 
-const co = require('co');
-const _ = require('underscore');
 const assert = require('assert');
 const should = require('should');
 const rp        = require('request-promise');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const commit    = require('./tools/commit');
-const toolbox = require('./tools/toolbox');
-const TestUser = require('./tools/TestUser').TestUser
-const unit   = require('./tools/unit');
-const httpTest  = require('./tools/http');
+const unit   = require('../tools/unit');
+const httpTest  = require('../tools/http');
 
 /**
  * Test Crosschain algorithm described at https://en.bitcoin.it/wiki/Atomic_cross-chain_trading
@@ -44,12 +41,11 @@ describe("Crosschain transactions", function() {
 
   describe('Successfull transaction', () => {
 
-    let sB, sM, tocB, tocM, ticB, ticM, btx0, mtx0; // Source transactions for coins
+    let sB:TestingServer, sM:TestingServer, tocB:TestUser, tocM:TestUser, ticB:TestUser, ticM:TestUser, btx0:string, mtx0:string; // Source transactions for coins
 
-    before(() => co(function *() {
+    before(async () => {
 
-
-      sB = toolbox.server(_.extend({
+      sB = NewTestingServer(Underscore.extend({
         memory: MEMORY_MODE,
         name: 'bb11',
         currency: 'BETA_BROUZOUF',
@@ -59,7 +55,7 @@ describe("Crosschain transactions", function() {
         }
       }, commonConf));
 
-      sM = toolbox.server(_.extend({
+      sM = NewTestingServer(Underscore.extend({
         memory: MEMORY_MODE,
         name: 'bb12',
         currency: 'META_BROUZOUF',
@@ -76,44 +72,43 @@ describe("Crosschain transactions", function() {
       ticB = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: sB });
       ticM = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: sM });
 
-        yield sB.initDalBmaConnections();
-        yield sM.initDalBmaConnections();
-
-        // Initialize BETA
-        yield ticB.createIdentity();
-        yield tocB.createIdentity();
-        yield tocB.cert(ticB);
-        yield ticB.cert(tocB);
-        yield ticB.join();
-        yield tocB.join();
-        yield commit(sB)({ time: now });
-        yield commit(sB)({ time: now + 10 });
-        yield commit(sB)({ time: now + 10 });
-        // Preparation: we create a source transaction for our transfer
-        btx0 = yield tocB.prepareITX(120, tocB);
-        // We submit it to the network
-        yield tocB.sendTX(btx0);
-        // Written
-        yield commit(sB)({ time: now + 10 });
-
-        // Initialize META
-        yield ticM.createIdentity();
-        yield tocM.createIdentity();
-        yield tocM.cert(ticM);
-        yield ticM.cert(tocM);
-        yield ticM.join();
-        yield tocM.join();
-        yield commit(sM)({ time: now });
-        yield commit(sM)({ time: now + 10 });
-        yield commit(sM)({ time: now + 10 });
-        // Preparation: we create a source transaction for our transfer
-        mtx0 = yield ticM.prepareITX(120, ticM);
-        // We submit it to the network
-        yield ticM.sendTX(mtx0);
-        // Written
-        yield commit(sM)({ time: now + 10 });
-      })
-    );
+      await sB.initDalBmaConnections();
+      await sM.initDalBmaConnections();
+
+      // Initialize BETA
+      await ticB.createIdentity();
+      await tocB.createIdentity();
+      await tocB.cert(ticB);
+      await ticB.cert(tocB);
+      await ticB.join();
+      await tocB.join();
+      await sB.commit({ time: now });
+      await sB.commit({ time: now + 10 });
+      await sB.commit({ time: now + 10 });
+      // Preparation: we create a source transaction for our transfer
+      btx0 = await tocB.prepareITX(120, tocB);
+      // We submit it to the network
+      await tocB.sendTX(btx0);
+      // Written
+      await sB.commit({ time: now + 10 });
+
+      // Initialize META
+      await ticM.createIdentity();
+      await tocM.createIdentity();
+      await tocM.cert(ticM);
+      await ticM.cert(tocM);
+      await ticM.join();
+      await tocM.join();
+      await sM.commit({ time: now });
+      await sM.commit({ time: now + 10 });
+      await sM.commit({ time: now + 10 });
+      // Preparation: we create a source transaction for our transfer
+      mtx0 = await ticM.prepareITX(120, ticM);
+      // We submit it to the network
+      await ticM.sendTX(mtx0);
+      // Written
+      await sM.commit({ time: now + 10 });
+    })
 
     after(() => {
       return Promise.all([
@@ -131,35 +126,35 @@ describe("Crosschain transactions", function() {
 
     describe('Transfering', () => {
 
-      it("commit", () => co(function *() {
+      it("commit", async () => {
 
-        const currentB = yield sB.get('/blockchain/current');
+        const currentB = await sB.get('/blockchain/current');
         const blockstampB = [currentB.number, currentB.hash].join('-');
 
-        const currentM = yield sM.get('/blockchain/current');
+        const currentM = await sM.get('/blockchain/current');
         const blockstampM = [currentM.number, currentM.hash].join('-');
 
         // TOCB side (BETA)
         // 1. toc secretely chooses X password
-        let btx1 = yield tocB.prepareUTX(btx0, ['SIG(0)'], [{ qty: 120, base: 0, lock: '(XHX(8AFC8DF633FC158F9DB4864ABED696C1AA0FE5D617A7B5F7AB8DE7CA2EFCD4CB) && SIG(' + ticB.pub + ')) || (SIG(' + tocB.pub + ') && SIG(' + ticB.pub + '))'  }], { comment: 'BETA toc to tic', blockstamp: blockstampB });
+        let btx1 = await tocB.prepareUTX(btx0, ['SIG(0)'], [{ qty: 120, base: 0, lock: '(XHX(8AFC8DF633FC158F9DB4864ABED696C1AA0FE5D617A7B5F7AB8DE7CA2EFCD4CB) && SIG(' + ticB.pub + ')) || (SIG(' + tocB.pub + ') && SIG(' + ticB.pub + '))'  }], { comment: 'BETA toc to tic', blockstamp: blockstampB });
         // 2. toc makes a rollback transaction from tx1, signed by both parties (through internet): toc and tic
-        let btx2 = yield tocB.prepareMTX(btx1, ticB, ['XHX(0) SIG(1) SIG(0) SIG(1)'], [{ qty: 120, base: 0, lock: 'SIG(' + tocB.pub + ')' }], { comment: 'money back to tocB in 48h', locktime: 3600 * 48, blockstamp: blockstampB }); // N.B.: locktime should be like 48h in real world
+        let btx2 = await tocB.prepareMTX(btx1, ticB, ['XHX(0) SIG(1) SIG(0) SIG(1)'], [{ qty: 120, base: 0, lock: 'SIG(' + tocB.pub + ')' }], { comment: 'money back to tocB in 48h', locktime: 3600 * 48, blockstamp: blockstampB }); // N.B.: locktime should be like 48h in real world
 
         // TICM side (META)
         // 3. tic generates a transaction based on H(X) given by toc (through internet)
-        let mtx3 = yield ticM.prepareUTX(mtx0, ['SIG(0)'], [{ qty: 120, base: 0, lock: '(XHX(8AFC8DF633FC158F9DB4864ABED696C1AA0FE5D617A7B5F7AB8DE7CA2EFCD4CB) && SIG(' + tocM.pub + ')) || (SIG(' + ticM.pub + ') && SIG(' + tocM.pub + '))'  }], { comment: 'META tic to toc', blockstamp: blockstampM });
+        let mtx3 = await ticM.prepareUTX(mtx0, ['SIG(0)'], [{ qty: 120, base: 0, lock: '(XHX(8AFC8DF633FC158F9DB4864ABED696C1AA0FE5D617A7B5F7AB8DE7CA2EFCD4CB) && SIG(' + tocM.pub + ')) || (SIG(' + ticM.pub + ') && SIG(' + tocM.pub + '))'  }], { comment: 'META tic to toc', blockstamp: blockstampM });
         // 4. tic makes a rollback transaction from tx1, signed by both parties: toc and tic
-        let mtx4 = yield ticM.prepareMTX(mtx3, tocM, ['XHX(0) SIG(1) SIG(0) SIG(1)'], [{ qty: 120, base: 0, lock: 'SIG(' + ticM.pub + ')' }], { comment: 'money back to ticM', locktime: 3600 * 24, blockstamp: blockstampM }); // N.B.: locktime should be like 24h in real world
+        let mtx4 = await ticM.prepareMTX(mtx3, tocM, ['XHX(0) SIG(1) SIG(0) SIG(1)'], [{ qty: 120, base: 0, lock: 'SIG(' + ticM.pub + ')' }], { comment: 'money back to ticM', locktime: 3600 * 24, blockstamp: blockstampM }); // N.B.: locktime should be like 24h in real world
 
         // We submit TX1 to the network & write it
-        yield tocB.sendTX(btx1);
+        await tocB.sendTX(btx1);
         // Written
-        yield commit(sB)({ time: now + 10 });
+        await sB.commit({ time: now + 10 });
 
         // We submit TX3 to the network & write it
-        yield ticM.sendTX(mtx3);
+        await ticM.sendTX(mtx3);
         // Written
-        yield commit(sM)({ time: now + 10 });
+        await sM.commit({ time: now + 10 });
 
         /**
          * So now ... parties can either COMMIT or ROLLBACK. It's UP to the initiator: TOC.
@@ -168,58 +163,58 @@ describe("Crosschain transactions", function() {
         /**
          * Note: the ROLLBACK transactions have a locktime, and cannot be used before that delay.
          */
-        yield unit.shouldFail(ticM.sendTX(mtx4), 'Locktime not elapsed yet');
-        yield unit.shouldFail(tocB.sendTX(btx2), 'Locktime not elapsed yet');
+        await unit.shouldFail(ticM.sendTX(mtx4), 'Locktime not elapsed yet');
+        await unit.shouldFail(tocB.sendTX(btx2), 'Locktime not elapsed yet');
 
         /**
          * Let's say TOC agrees & and start COMMIT.
          */
 
         // TOCM consumes TICM's offered money by revealing the password + signing
-        let mtx5 = yield tocM.prepareUTX(mtx3, ['XHX(1872767826647264) SIG(0)'], [{ qty: 120, base: 0, lock: 'SIG(' + tocM.pub + ')' }], { comment: 'toc takes money on META_BROUZOUF', blockstamp: blockstampM });
-        yield tocM.sendTX(mtx5);
+        let mtx5 = await tocM.prepareUTX(mtx3, ['XHX(1872767826647264) SIG(0)'], [{ qty: 120, base: 0, lock: 'SIG(' + tocM.pub + ')' }], { comment: 'toc takes money on META_BROUZOUF', blockstamp: blockstampM });
+        await tocM.sendTX(mtx5);
         // Written
-        yield commit(sM)();
+        await sM.commit();
 
         // But now X is revealed: TAC can takes the money offered in TX1 by TOCB
-        let btx6 = yield ticB.prepareUTX(btx1, ['XHX(1872767826647264) SIG(0)'], [{ qty: 120, base: 0, lock: 'SIG(' + ticB.pub + ')' }], { comment: 'tic takes money on BETA_BROUZOUF', blockstamp: blockstampB });
-        yield ticB.sendTX(btx6);
+        let btx6 = await ticB.prepareUTX(btx1, ['XHX(1872767826647264) SIG(0)'], [{ qty: 120, base: 0, lock: 'SIG(' + ticB.pub + ')' }], { comment: 'tic takes money on BETA_BROUZOUF', blockstamp: blockstampB });
+        await ticB.sendTX(btx6);
         // Written
-        yield commit(sB)();
+        await sB.commit();
 
         /**
          * Now the transaction is fully COMMITTED! Look at rollback transactions: they will fail.
          */
 
-        yield unit.shouldFail(tocB.sendTX(btx2), 'Source already consumed');
-        yield unit.shouldFail(ticM.sendTX(mtx4), 'Source already consumed');
-      }));
+        await unit.shouldFail(tocB.sendTX(btx2), 'Source already consumed');
+        await unit.shouldFail(ticM.sendTX(mtx4), 'Source already consumed');
+      })
 
       it('toc should now have 0 BETA_BROUZOUF from Transaction sources due to COMMIT', () => {
-        return sB.expect('/tx/sources/' + tocB.pub, (res) => {
-          const txRes = _.filter(res.sources, { type: 'T' });
+        return sB.expect('/tx/sources/' + tocB.pub, (res:HttpSources) => {
+          const txRes = Underscore.where(res.sources, { type: 'T' });
           txRes.should.have.length(0);
         });
       });
 
       it('toc should now have 120 META_BROUZOUF from Transaction sources due to COMMIT', () => {
-        return sM.expect('/tx/sources/' + tocB.pub, (res) => {
-          const txRes = _.filter(res.sources, { type: 'T' });
+        return sM.expect('/tx/sources/' + tocB.pub, (res:HttpSources) => {
+          const txRes = Underscore.where(res.sources, { type: 'T' });
           txRes.should.have.length(1);
           assert.equal(txRes[0].amount, 120);
         });
       });
 
       it('tic should now have 0 META_BROUZOUF from Transaction sources due to COMMMIT', () => {
-        return sM.expect('/tx/sources/' + ticM.pub, (res) => {
-          const txRes = _.filter(res.sources, { type: 'T' });
+        return sM.expect('/tx/sources/' + ticM.pub, (res:HttpSources) => {
+          const txRes = Underscore.where(res.sources, { type: 'T' });
           txRes.should.have.length(0);
         });
       });
 
       it('tic should have 120 BETA_BROUZOUF from Transaction sources due to COMMIT', () => {
-        return sB.expect('/tx/sources/' + ticM.pub, (res) => {
-          const txRes = _.filter(res.sources, { type: 'T' });
+        return sB.expect('/tx/sources/' + ticM.pub, (res:HttpSources) => {
+          const txRes = Underscore.where(res.sources, { type: 'T' });
           txRes.should.have.length(1);
           assert.equal(txRes[0].amount, 120);
         });
@@ -229,76 +224,73 @@ describe("Crosschain transactions", function() {
 
   describe('Rollbacked transaction', () => {
 
-    let sB, sM, tocB, tocM, ticB, ticM, btx0, mtx0; // Source transactions for coins
-
-    before(function() {
-
-      return co(function *() {
-
-        sB = toolbox.server(_.extend({
-          memory: MEMORY_MODE,
-          name: 'bb11',
-          currency: 'BETA_BROUZOUF2',
-          pair: {
-            pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo',
-            sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'
-          }
-        }, commonConf));
-
-        sM = toolbox.server(_.extend({
-          memory: MEMORY_MODE,
-          name: 'bb12',
-          currency: 'META_BROUZOUF2',
-          pair: {
-            pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV',
-            sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'
-          }
-        }, commonConf));
-
-        // toc is on 2 currencies
-        tocB = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: sB });
-        tocM = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: sM });
-        // tic is on 2 currencies
-        ticB = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: sB });
-        ticM = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: sM });
-
-        yield sB.initDalBmaConnections();
-        yield sM.initDalBmaConnections()
-
-        // Initialize BETA
-        yield ticB.createIdentity();
-        yield tocB.createIdentity();
-        yield tocB.cert(ticB);
-        yield ticB.cert(tocB);
-        yield ticB.join();
-        yield tocB.join();
-        yield commit(sB)({ time: now });
-        yield commit(sB)({ time: now + 10 });
-        yield commit(sB)({ time: now + 10 });
-        // Preparation: we create a source transaction for our transfer
-        btx0 = yield tocB.prepareITX(120, tocB);
-        // We submit it to the network
-        yield tocB.sendTX(btx0);
-        // Written
-        yield commit(sB)({ time: now + 10 });
-
-        // Initialize META
-        yield ticM.createIdentity();
-        yield tocM.createIdentity();
-        yield tocM.cert(ticM);
-        yield ticM.cert(tocM);
-        yield ticM.join();
-        yield tocM.join();
-        yield commit(sM)({ time: now });
-        yield commit(sM)({ time: now + 10 });
-        yield commit(sM)({ time: now + 10 });
-        // Preparation: we create a source transaction for our transfer
-        mtx0 = yield ticM.prepareITX(120, ticM);
-        // We submit it to the network
-        yield ticM.sendTX(mtx0);
-        // Written
-        yield commit(sM)({ time: now + 10 });
-      });
+    let sB:TestingServer, sM:TestingServer, tocB:TestUser, tocM:TestUser, ticB:TestUser, ticM:TestUser, btx0:string, mtx0:string; // Source transactions for coins
+
+    before(async () => {
+
+      sB = NewTestingServer(Underscore.extend({
+        memory: MEMORY_MODE,
+        name: 'bb11',
+        currency: 'BETA_BROUZOUF2',
+        pair: {
+          pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo',
+          sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'
+        }
+      }, commonConf))
+
+      sM = NewTestingServer(Underscore.extend({
+        memory: MEMORY_MODE,
+        name: 'bb12',
+        currency: 'META_BROUZOUF2',
+        pair: {
+          pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV',
+          sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'
+        }
+      }, commonConf));
+
+      // toc is on 2 currencies
+      tocB = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: sB });
+      tocM = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: sM });
+      // tic is on 2 currencies
+      ticB = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: sB });
+      ticM = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: sM });
+
+      await sB.initDalBmaConnections();
+      await sM.initDalBmaConnections()
+
+      // Initialize BETA
+      await ticB.createIdentity();
+      await tocB.createIdentity();
+      await tocB.cert(ticB);
+      await ticB.cert(tocB);
+      await ticB.join();
+      await tocB.join();
+      await sB.commit({ time: now });
+      await sB.commit({ time: now + 10 });
+      await sB.commit({ time: now + 10 });
+      // Preparation: we create a source transaction for our transfer
+      btx0 = await tocB.prepareITX(120, tocB);
+      // We submit it to the network
+      await tocB.sendTX(btx0);
+      // Written
+      await sB.commit({ time: now + 10 });
+
+      // Initialize META
+      await ticM.createIdentity();
+      await tocM.createIdentity();
+      await tocM.cert(ticM);
+      await ticM.cert(tocM);
+      await ticM.join();
+      await tocM.join();
+      await sM.commit({ time: now });
+      await sM.commit({ time: now + 10 });
+      await sM.commit({ time: now + 10 });
+      // Preparation: we create a source transaction for our transfer
+      mtx0 = await ticM.prepareITX(120, ticM);
+      // We submit it to the network
+      await ticM.sendTX(mtx0);
+      // Written
+      await sM.commit({ time: now + 10 });
     });
 
     after(() => {
@@ -317,35 +309,35 @@ describe("Crosschain transactions", function() {
 
     describe('Transfering', () => {
 
-      it("commit", () => co(function *() {
+      it("commit", async () => {
 
-        const currentB = yield sB.get('/blockchain/current');
+        const currentB = await sB.get('/blockchain/current');
         const blockstampB = [currentB.number, currentB.hash].join('-');
 
-        const currentM = yield sM.get('/blockchain/current');
+        const currentM = await sM.get('/blockchain/current');
         const blockstampM = [currentM.number, currentM.hash].join('-');
 
         // TOCB side (BETA)
         // 1. toc secretely chooses X password
-        let btx1 = yield tocB.prepareUTX(btx0, ['SIG(0)'], [{ qty: 120, base: 0, lock: '(XHX(8AFC8DF633FC158F9DB4864ABED696C1AA0FE5D617A7B5F7AB8DE7CA2EFCD4CB) && SIG(' + ticB.pub + ')) || (SIG(' + tocB.pub + ') && SIG(' + ticB.pub + '))'  }], { comment: 'BETA toc to tic', blockstamp: blockstampB });
+        let btx1 = await tocB.prepareUTX(btx0, ['SIG(0)'], [{ qty: 120, base: 0, lock: '(XHX(8AFC8DF633FC158F9DB4864ABED696C1AA0FE5D617A7B5F7AB8DE7CA2EFCD4CB) && SIG(' + ticB.pub + ')) || (SIG(' + tocB.pub + ') && SIG(' + ticB.pub + '))'  }], { comment: 'BETA toc to tic', blockstamp: blockstampB });
         // 2. toc makes a rollback transaction from tx1, signed by both parties (through internet): toc and tic
-        let btx2 = yield tocB.prepareMTX(btx1, ticB, ['SIG(0) SIG(1)'], [{ qty: 120, base: 0, lock: 'SIG(' + tocB.pub + ')' }], { comment: 'money back to tocB in 48h', locktime: 3, blockstamp: blockstampB }); // N.B.: locktime should be like 48h in real world
+        let btx2 = await tocB.prepareMTX(btx1, ticB, ['SIG(0) SIG(1)'], [{ qty: 120, base: 0, lock: 'SIG(' + tocB.pub + ')' }], { comment: 'money back to tocB in 48h', locktime: 3, blockstamp: blockstampB }); // N.B.: locktime should be like 48h in real world
 
         // TICM side (META)
         // 3. tic generates a transaction based on H(X) given by toc (through internet)
-        let mtx3 = yield ticM.prepareUTX(mtx0, ['SIG(0)'], [{ qty: 120, base: 0, lock: '(XHX(8AFC8DF633FC158F9DB4864ABED696C1AA0FE5D617A7B5F7AB8DE7CA2EFCD4CB) && SIG(' + tocM.pub + ')) || (SIG(' + ticM.pub + ') && SIG(' + tocM.pub + '))'  }], { comment: 'META tic to toc', blockstamp: blockstampM });
+        let mtx3 = await ticM.prepareUTX(mtx0, ['SIG(0)'], [{ qty: 120, base: 0, lock: '(XHX(8AFC8DF633FC158F9DB4864ABED696C1AA0FE5D617A7B5F7AB8DE7CA2EFCD4CB) && SIG(' + tocM.pub + ')) || (SIG(' + ticM.pub + ') && SIG(' + tocM.pub + '))'  }], { comment: 'META tic to toc', blockstamp: blockstampM });
         // 4. tic makes a rollback transaction from tx1, signed by both parties: toc and tic
-        let mtx4 = yield ticM.prepareMTX(mtx3, tocM, ['SIG(0) SIG(1)'], [{ qty: 120, base: 0, lock: 'SIG(' + ticM.pub + ')' }], { comment: 'money back to ticM', locktime: 2, blockstamp: blockstampM }); // N.B.: locktime should be like 24h in real world
+        let mtx4 = await ticM.prepareMTX(mtx3, tocM, ['SIG(0) SIG(1)'], [{ qty: 120, base: 0, lock: 'SIG(' + ticM.pub + ')' }], { comment: 'money back to ticM', locktime: 2, blockstamp: blockstampM }); // N.B.: locktime should be like 24h in real world
 
         // We submit TX1 to the network & write it
-        yield tocB.sendTX(btx1);
+        await tocB.sendTX(btx1);
         // Written
-        yield commit(sB)({ time: now + 12 });
+        await sB.commit({ time: now + 12 });
 
         // We submit TX3 to the network & write it
-        yield ticM.sendTX(mtx3);
+        await ticM.sendTX(mtx3);
         // Written
-        yield commit(sM)({ time: now + 12 });
+        await sM.commit({ time: now + 12 });
 
         /**
          * So now ... parties can either COMMIT or ROLLBACK. It's UP to the initiator: TOC.
@@ -356,50 +348,50 @@ describe("Crosschain transactions", function() {
         /**
          * Note: the ROLLBACK transactions have a locktime, and cannot be used before that delay.
          */
-        yield unit.shouldFail(ticM.sendTX(mtx4), 'Locktime not elapsed yet');
-        yield unit.shouldFail(tocB.sendTX(btx2), 'Locktime not elapsed yet');
+        await unit.shouldFail(ticM.sendTX(mtx4), 'Locktime not elapsed yet');
+        await unit.shouldFail(tocB.sendTX(btx2), 'Locktime not elapsed yet');
 
         // Increment the medianTime by 1
-        yield commit(sM)({ time: now + 12 });
-        yield commit(sB)({ time: now + 14 });
+        await sM.commit({ time: now + 12 });
+        await sB.commit({ time: now + 14 });
 
-        yield unit.shouldNotFail(ticM.sendTX(mtx4)); // tic can rollback early (24h in real case) if toc does not reveal X
-        yield unit.shouldFail(tocB.sendTX(btx2), 'Locktime not elapsed yet'); // This one has a longer locktime (48h in real case)
+        await unit.shouldNotFail(ticM.sendTX(mtx4)); // tic can rollback early (24h in real case) if toc does not reveal X
+        await unit.shouldFail(tocB.sendTX(btx2), 'Locktime not elapsed yet'); // This one has a longer locktime (48h in real case)
 
         // Rollback for TIC(M) should be done
-        yield commit(sM)({ time: now + 12 });
+        await sM.commit({ time: now + 12 });
 
         // Make the medianTime increment by 1
-        yield commit(sB)({ time: now + 14 });
+        await sB.commit({ time: now + 14 });
 
-        yield unit.shouldNotFail(tocB.sendTX(btx2)); // toc can rollback now (48h has passed). He has not revealed X, so he is safe.
-        yield commit(sB)({ time: now + 14 });
+        await unit.shouldNotFail(tocB.sendTX(btx2)); // toc can rollback now (48h has passed). He has not revealed X, so he is safe.
+        await sB.commit({ time: now + 14 });
 
         /**
          * Now the transaction is fully COMMITTED! Look at rollback transactions: they will fail.
          */
 
         // TOCM consumes TICM's offered money by revealing the password + signing
-        let mtx5 = yield tocM.prepareUTX(mtx3, ['XHX(1872767826647264) SIG(0)'], [{ qty: 120, base: 0, lock: 'SIG(' + tocM.pub + ')' }], { comment: 'toc takes money on META_BROUZOUF', blockstamp: blockstampM });
+        let mtx5 = await tocM.prepareUTX(mtx3, ['XHX(1872767826647264) SIG(0)'], [{ qty: 120, base: 0, lock: 'SIG(' + tocM.pub + ')' }], { comment: 'toc takes money on META_BROUZOUF', blockstamp: blockstampM });
 
         // Assuming X was revealed ... but actually it is not since TOCM did succeed to send the TX
-        let btx6 = yield ticB.prepareUTX(btx1, ['XHX(1872767826647264) SIG(0)'], [{ qty: 120, base: 0, lock: 'SIG(' + ticB.pub + ')' }], { comment: 'tic takes money on BETA_BROUZOUF', blockstamp: blockstampB });
+        let btx6 = await ticB.prepareUTX(btx1, ['XHX(1872767826647264) SIG(0)'], [{ qty: 120, base: 0, lock: 'SIG(' + ticB.pub + ')' }], { comment: 'tic takes money on BETA_BROUZOUF', blockstamp: blockstampB });
 
-        yield unit.shouldFail(tocB.sendTX(btx6), 'Source already consumed');
-        yield unit.shouldFail(ticM.sendTX(mtx5), 'Source already consumed');
-      }));
+        await unit.shouldFail(tocB.sendTX(btx6), 'Source already consumed');
+        await unit.shouldFail(ticM.sendTX(mtx5), 'Source already consumed');
+      })
 
       it('toc should now have 120 BETA_BROUZOUF from Transaction sources due to rollback TX', () => checkHaveSources(tocB, 1, 120));
       it('tic should now have 120 META_BROUZOUF from Transaction sources due to rollback TX', () => checkHaveSources(ticM, 1, 120));
       it('toc should now have 0 META_BROUZOUF from Transaction sources', () => checkHaveSources(tocM, 0, 0));
       it('tic should now have 0 BETA_BROUZOUF from Transaction sources', () => checkHaveSources(ticB, 0, 0));
-    });
+    })
   });
 });
 
-function checkHaveSources(theUser, sourcesCount, sourcesTotalAmount) {
-  return httpTest.expectAnswer(rp('http://' + theUser.node.server.conf.ipv4 + ':' + theUser.node.server.conf.port + '/tx/sources/' + theUser.pub, { json: true }), (res) => {
-    const txRes = _.filter(res.sources, { type: 'T' });
+function checkHaveSources(theUser:TestUser, sourcesCount:number, sourcesTotalAmount:number) {
+  return httpTest.expectAnswer(rp('http://' + theUser.node.server.conf.ipv4 + ':' + theUser.node.server.conf.port + '/tx/sources/' + theUser.pub, { json: true }), (res:HttpSources) => {
+    const txRes = Underscore.where(res.sources, { type: 'T' })
     txRes.should.have.length(sourcesCount);
     let sum = 0;
     for (const result of txRes) {
diff --git a/test/integration/transactions-cltv.js b/test/integration/transactions/transactions-cltv.ts
similarity index 50%
rename from test/integration/transactions-cltv.js
rename to test/integration/transactions/transactions-cltv.ts
index 4722ef30b60416835d0ddd2e56451a0c6fdec288..4e5515d33d84a270a19a1a1816d58ddcb44fa506 100644
--- a/test/integration/transactions-cltv.js
+++ b/test/integration/transactions/transactions-cltv.ts
@@ -11,18 +11,12 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {simpleNodeWith2Users, TestingServer} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
+import {shouldFail, shouldNotFail} from "../../unit-tools"
 
-const co = require('co');
-const _ = require('underscore');
 const should = require('should');
 const assert = require('assert');
-const constants = require('../../app/lib/constants');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const toolbox   = require('./tools/toolbox');
-const node   = require('./tools/node');
-const unit   = require('./tools/unit');
-const http   = require('./tools/http');
 
 const now = 1480000000;
 
@@ -33,18 +27,18 @@ const conf = {
   medianTimeBlocks: 1 // Easy: medianTime(b) = time(b-1)
 };
 
-let s1, cat, tac
+let s1:TestingServer, cat:TestUser, tac:TestUser
 
-describe("Transactions: CLTV", function() {
+describe("Transactions: CLTV", () => {
 
-  before(() => co(function*() {
-    const res = yield toolbox.simpleNodeWith2Users(conf);
+  before(async () => {
+    const res = await simpleNodeWith2Users(conf);
     s1 = res.s1;
     cat = res.cat;
     tac = res.tac;
-    yield s1.commit({ time: now });
-    yield s1.commit({ time: now + 1 });
-  }));
+    await s1.commit({ time: now });
+    await s1.commit({ time: now + 1 });
+  })
 
   after(() => {
     return Promise.all([
@@ -52,27 +46,27 @@ describe("Transactions: CLTV", function() {
     ])
   })
 
-  it('it should exist block#1 with UD of 200', () => s1.expect('/blockchain/block/1', (block) => {
+  it('it should exist block#1 with UD of 200', () => s1.expect('/blockchain/block/1', (block:any) => {
     should.exists(block);
     assert.equal(block.number, 1);
     assert.equal(block.dividend, 200);
   }));
 
-  it('with SIG and CLTV', () => co(function *() {
-    let tx1 = yield cat.prepareITX(200, tac);
-    yield unit.shouldNotFail(cat.sendTX(tx1));
-    yield s1.commit({ time: now + 19 }); // TODO: why not in the same block?
-    let current = yield s1.get('/blockchain/current');
-    let tx2 = yield tac.prepareUTX(tx1, ['SIG(0)'], [{ qty: 200, base: 0, lock: 'SIG(' + cat.pub + ') && CLTV(1480000022)' }], {
+  it('with SIG and CLTV', async () => {
+    let tx1 = await cat.prepareITX(200, tac);
+    await shouldNotFail(cat.sendTX(tx1));
+    await s1.commit({ time: now + 19 }); // TODO: why not in the same block?
+    let current = await s1.get('/blockchain/current');
+    let tx2 = await tac.prepareUTX(tx1, ['SIG(0)'], [{ qty: 200, base: 0, lock: 'SIG(' + cat.pub + ') && CLTV(1480000022)' }], {
       comment: 'must wait until time 1480000022',
       blockstamp: [current.number, current.hash].join('-')
     });
-    yield unit.shouldNotFail(cat.sendTX(tx2));
-    yield s1.commit({ time: now + 21 }); // TODO: why not in the same block?
-    let tx3 = yield cat.prepareITX(200, tac);
-    yield unit.shouldFail(cat.sendTX(tx3), 'Wrong unlocker in transaction');
-    yield s1.commit({ time: now + 22 });
-    yield unit.shouldNotFail(cat.sendTX(tx3)); // Because next block will have medianTime = 22
-    yield s1.commit({ time: now + 22 });
-  }));
-});
+    await shouldNotFail(cat.sendTX(tx2));
+    await s1.commit({ time: now + 21 }); // TODO: why not in the same block?
+    let tx3 = await cat.prepareITX(200, tac);
+    await shouldFail(cat.sendTX(tx3), 'Wrong unlocker in transaction');
+    await s1.commit({ time: now + 22 });
+    await shouldNotFail(cat.sendTX(tx3)); // Because next block will have medianTime = 22
+    await s1.commit({ time: now + 22 });
+  })
+})
diff --git a/test/integration/transactions-csv.js b/test/integration/transactions/transactions-csv.ts
similarity index 50%
rename from test/integration/transactions-csv.js
rename to test/integration/transactions/transactions-csv.ts
index 31d5e912703daf1ed970d10d761b35e49c65edf8..2b3783e157bc2a2fad5bb01bb7cf70be74af0313 100644
--- a/test/integration/transactions-csv.js
+++ b/test/integration/transactions/transactions-csv.ts
@@ -11,18 +11,12 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {simpleNodeWith2Users, TestingServer} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
+import {shouldFail, shouldNotFail} from "../../unit-tools"
 
-const co = require('co');
-const _ = require('underscore');
 const should = require('should');
 const assert = require('assert');
-const constants = require('../../app/lib/constants');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const toolbox   = require('./tools/toolbox');
-const node   = require('./tools/node');
-const unit   = require('./tools/unit');
-const http   = require('./tools/http');
 
 const now = 1480000000;
 
@@ -33,18 +27,18 @@ const conf = {
   medianTimeBlocks: 1 // Easy: medianTime(b) = time(b-1)
 };
 
-let s1, cat, tac
+let s1:TestingServer, cat:TestUser, tac:TestUser
 
-describe("Transactions: CSV", function() {
+describe("Transactions: CSV", () => {
 
-  before(() => co(function*() {
-    const res = yield toolbox.simpleNodeWith2Users(conf);
+  before(async () => {
+    const res = await simpleNodeWith2Users(conf);
     s1 = res.s1;
     cat = res.cat;
     tac = res.tac;
-    yield s1.commit({ time: now });
-    yield s1.commit({ time: now + 1 });
-  }));
+    await s1.commit({ time: now });
+    await s1.commit({ time: now + 1 });
+  })
 
   after(() => {
     return Promise.all([
@@ -52,27 +46,27 @@ describe("Transactions: CSV", function() {
     ])
   })
 
-  it('it should exist block#1 with UD of 200', () => s1.expect('/blockchain/block/1', (block) => {
+  it('it should exist block#1 with UD of 200', () => s1.expect('/blockchain/block/1', (block:any) => {
     should.exists(block);
     assert.equal(block.number, 1);
     assert.equal(block.dividend, 200);
   }));
 
-  it('with SIG and CSV', () => co(function *() {
-    let tx1 = yield cat.prepareITX(200, tac);
-    yield unit.shouldNotFail(cat.sendTX(tx1));
-    yield s1.commit({ time: now + 19 }); // TODO: why not in the same block?
-    let current = yield s1.get('/blockchain/current');
-    let tx2 = yield tac.prepareUTX(tx1, ['SIG(0)'], [{ qty: 200, base: 0, lock: 'SIG(' + cat.pub + ') && CSV(20)' }], {
+  it('with SIG and CSV', async () => {
+    let tx1 = await cat.prepareITX(200, tac);
+    await shouldNotFail(cat.sendTX(tx1));
+    await s1.commit({ time: now + 19 }); // TODO: why not in the same block?
+    let current = await s1.get('/blockchain/current');
+    let tx2 = await tac.prepareUTX(tx1, ['SIG(0)'], [{ qty: 200, base: 0, lock: 'SIG(' + cat.pub + ') && CSV(20)' }], {
       comment: 'must wait 20 seconds',
       blockstamp: [current.number, current.hash].join('-')
     });
-    yield unit.shouldNotFail(cat.sendTX(tx2));
-    yield s1.commit({ time: now + 38 }); // TODO: why not in the same block?
-    let tx3 = yield cat.prepareITX(200, tac);
-    yield unit.shouldFail(cat.sendTX(tx3), 'Wrong unlocker in transaction');
-    yield s1.commit({ time: now + 39 });
-    yield unit.shouldNotFail(cat.sendTX(tx3)); // Because next block will have medianTime = 39
-    yield s1.commit({ time: now + 39 });
-  }));
-});
+    await shouldNotFail(cat.sendTX(tx2));
+    await s1.commit({ time: now + 38 }); // TODO: why not in the same block?
+    let tx3 = await cat.prepareITX(200, tac);
+    await shouldFail(cat.sendTX(tx3), 'Wrong unlocker in transaction');
+    await s1.commit({ time: now + 39 });
+    await shouldNotFail(cat.sendTX(tx3)); // Because next block will have medianTime = 39
+    await s1.commit({ time: now + 39 });
+  })
+})
diff --git a/test/integration/transactions-test.js b/test/integration/transactions/transactions-test.ts
similarity index 58%
rename from test/integration/transactions-test.js
rename to test/integration/transactions/transactions-test.ts
index 3860f0f8ecd9bc790b39000954582241ea09dab8..fe470cffad02073cb24cd8465154be0528c4b1b4 100644
--- a/test/integration/transactions-test.js
+++ b/test/integration/transactions/transactions-test.ts
@@ -11,30 +11,23 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {TestUser} from "../tools/TestUser"
+import {NewTestingServer, TestingServer} from "../tools/toolbox"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
+import {shouldFail, shouldNotFail} from "../../unit-tools"
 
-const co = require('co');
-const _ = require('underscore');
 const should = require('should');
 const assert = require('assert');
-const constants = require('../../app/lib/constants');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const toolbox   = require('./tools/toolbox');
-const node   = require('./tools/node');
-const TestUser = require('./tools/TestUser').TestUser
-const unit   = require('./tools/unit');
-const http   = require('./tools/http');
-
 
 describe("Testing transactions", function() {
 
   const now = 1490000000;
 
-  let s1, tic, toc
+  let s1:TestingServer, tic:TestUser, toc:TestUser
 
-  before(() => co(function*() {
+  before(async () => {
 
-    s1 = toolbox.server({
+    s1 = NewTestingServer({
       pair: {
         pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV',
         sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'
@@ -51,32 +44,32 @@ describe("Testing transactions", function() {
     tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
     toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
 
-    yield s1.initDalBmaConnections();
+    await s1.initDalBmaConnections();
     // Self certifications
-    yield tic.createIdentity();
-    yield toc.createIdentity();
+    await tic.createIdentity();
+    await toc.createIdentity();
     // Certification;
-    yield tic.cert(toc);
-    yield toc.cert(tic);
-    yield tic.join();
-    yield toc.join();
-    yield s1.commit({ time: now });
-    yield s1.commit({
+    await tic.cert(toc);
+    await toc.cert(tic);
+    await tic.join();
+    await toc.join();
+    await s1.commit({ time: now });
+    await s1.commit({
       time: now + 7210
     });
-    yield s1.commit({
+    await s1.commit({
       time: now + 7210
     });
-    yield tic.sendP(510, toc);
-    yield s1.expect('/tx/history/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', (res) => {
+    await tic.sendP(510, toc);
+    await s1.expect('/tx/history/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', (res:any) => {
       res.should.have.property('pubkey').equal('DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo');
       res.should.have.property('history').property('pending').length(1);
       res.history.pending[0].should.have.property('received').be.a.Number;
     });
-    yield s1.commit({
+    await s1.commit({
       time: now + 7220
     });
-  }));
+  })
 
   after(() => {
     return Promise.all([
@@ -86,21 +79,21 @@ describe("Testing transactions", function() {
 
   describe("Sources", function(){
 
-    it('it should exist block#2 with UD of 1200', () => s1.expect('/blockchain/block/2', (block) => {
+    it('it should exist block#2 with UD of 1200', () => s1.expect('/blockchain/block/2', (block:any) => {
       should.exists(block);
       assert.equal(block.number, 2);
       assert.equal(block.dividend, 1200);
     }));
 
-    it('tic should be able to send 510 to toc', () => co(function*() {
-      yield s1.expect('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', (res) => {
+    it('tic should be able to send 510 to toc', async () => {
+      await s1.expect('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', (res:any) => {
         should.exists(res);
         assert.equal(res.sources.length, 1);
         assert.equal(res.sources[0].conditions, 'SIG(DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV)')
-        const txSrc = _.findWhere(res.sources, { type: 'T' });
+        const txSrc = (Underscore.findWhere(res.sources, { type: 'T' }) as any)
         assert.equal(txSrc.amount, 690);
       })
-      const tx = yield s1.get('/tx/hash/B6DCADFB841AC05A902741A8772A70B4086D5AEAB147AD48987DDC3887DD55C8')
+      const tx = await s1.get('/tx/hash/B6DCADFB841AC05A902741A8772A70B4086D5AEAB147AD48987DDC3887DD55C8')
       assert.notEqual(tx, null)
       assert.deepEqual(tx, {
         "comment": "",
@@ -127,94 +120,94 @@ describe("Testing transactions", function() {
         "version": 10,
         "written_block": 3
       })
-    }));
+    })
 
-    it('toc should have 1510 of sources', () => s1.expect('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', (res) => {
+    it('toc should have 1510 of sources', () => s1.expect('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', (res:any) => {
       should.exists(res);
       assert.equal(res.sources.length, 2);
-      const txRes = _.findWhere(res.sources, { type: 'T' });
-      const duRes = _.filter(res.sources, { type: 'D' });
+      const txRes = (Underscore.findWhere(res.sources, { type: 'T' }) as any)
+      const duRes = (Underscore.where(res.sources, { type: 'D' }) as any)
       assert.equal(txRes.type, 'T');
       assert.equal(txRes.amount, 510);
       assert.equal(duRes[0].type, 'D');
       assert.equal(duRes[0].amount, 1200);
     }));
 
-    it('toc should be able to send 800 to tic', () => co(function *() {
-      let tx1 = yield toc.prepareITX(1710, tic);
-      yield toc.sendTX(tx1);
-      yield s1.commit({ time: now + 15000 });
-      (yield s1.get('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo')).should.have.property('sources').length(0);
-    }));
+    it('toc should be able to send 800 to tic', async () => {
+      let tx1 = await toc.prepareITX(1710, tic);
+      await toc.sendTX(tx1);
+      await s1.commit({ time: now + 15000 });
+      (await s1.get('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo')).should.have.property('sources').length(0);
+    })
   });
 
   describe("Chaining", function(){
 
-    it('with SIG and XHX', () => co(function *() {
+    it('with SIG and XHX', async () => {
       // Current state
-      (yield s1.get('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo')).should.have.property('sources').length(0);
-      (yield s1.get('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV')).should.have.property('sources').length(2);
-      (yield s1.get('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo')).should.have.property('sources').length(0);
-      (yield s1.get('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV')).should.have.property('sources').length(2);
+      (await s1.get('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo')).should.have.property('sources').length(0);
+      (await s1.get('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV')).should.have.property('sources').length(2);
+      (await s1.get('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo')).should.have.property('sources').length(0);
+      (await s1.get('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV')).should.have.property('sources').length(2);
       // Make the time go so another UD is available
-      yield s1.commit({ time: now + 15000 });
-      (yield s1.get('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo')).should.have.property('sources').length(1);
-      (yield s1.get('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV')).should.have.property('sources').length(3);
-      let tx1 = yield toc.prepareITX(1200, tic);
-      yield toc.sendTX(tx1);
-      yield s1.commit({ time: now + 15000 });
-      (yield s1.get('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo')).should.have.property('sources').length(0);
-      (yield s1.get('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV')).should.have.property('sources').length(4);
+      await s1.commit({ time: now + 15000 });
+      (await s1.get('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo')).should.have.property('sources').length(1);
+      (await s1.get('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV')).should.have.property('sources').length(3);
+      let tx1 = await toc.prepareITX(1200, tic);
+      await toc.sendTX(tx1);
+      await s1.commit({ time: now + 15000 });
+      (await s1.get('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo')).should.have.property('sources').length(0);
+      (await s1.get('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV')).should.have.property('sources').length(4);
       // Now cat has all the money...
-      let current = yield s1.get('/blockchain/current');
-      let tx2 = yield tic.prepareUTX(tx1, ['SIG(2)'], [{ qty: 1200, base: 0, lock: 'SIG(' + toc.pub + ')' }], { comment: 'wrong', blockstamp: [current.number, current.hash].join('-') });
-      let tx3 = yield tic.prepareUTX(tx1, ['SIG(1)'], [{ qty: 1200, base: 0, lock: 'SIG(' + toc.pub + ')' }], { comment: 'wrong', blockstamp: [current.number, current.hash].join('-') });
-      let tx4 = yield tic.prepareUTX(tx1, ['SIG(0)'], [{ qty: 1200, base: 0, lock: 'XHX(8AFC8DF633FC158F9DB4864ABED696C1AA0FE5D617A7B5F7AB8DE7CA2EFCD4CB)' }], { comment: 'ok', blockstamp: [current.number, current.hash].join('-') });
-      let tx5 = yield tic.prepareUTX(tx1, ['XHX(2)'], [{ qty: 1200, base: 0, lock: 'SIG(' + toc.pub + ')' }], { comment: 'wrong', blockstamp: [current.number, current.hash].join('-') });
-      let tx6 = yield tic.prepareUTX(tx1, ['XHX(4)'], [{ qty: 1200, base: 0, lock: 'SIG(' + toc.pub + ')' }], { comment: 'wrong', blockstamp: [current.number, current.hash].join('-') });
-      yield unit.shouldFail(toc.sendTX(tx2), 'Wrong unlocker in transaction');
-      yield unit.shouldFail(toc.sendTX(tx3), 'Wrong unlocker in transaction');
-      yield unit.shouldNotFail(toc.sendTX(tx4));
-      yield unit.shouldFail(toc.sendTX(tx5), 'Wrong unlocker in transaction');
-      yield unit.shouldFail(toc.sendTX(tx6), 'Wrong unlocker in transaction');
-      yield s1.commit({ time: now + 19840 }); // TX4 commited
-      (yield s1.get('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo')).should.have.property('sources').length(0); // The tx was not sent to someone, but with an XHX! So toc has nothing more than before.
-      (yield s1.get('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV')).should.have.property('sources').length(3);
-      let tx7 = yield tic.prepareUTX(tx4, ['XHX(2872767826647264)'], [{ qty: 1200, base: 0, lock: 'SIG(' + toc.pub + ')' }], { comment: 'wrong1', blockstamp: [current.number, current.hash].join('-') });
-      let tx8 = yield tic.prepareUTX(tx4, ['XHX(1872767826647264)'], [{ qty: 1200, base: 0, lock: 'SIG(' + toc.pub + ')' }], { comment: 'okk', blockstamp: [current.number, current.hash].join('-') }); // tic unlocks the XHX locked amount, and gives it to toc!
-      yield unit.shouldFail(toc.sendTX(tx7), 'Wrong unlocker in transaction');
-      yield unit.shouldNotFail(toc.sendTX(tx8));
-      yield s1.commit({ time: now + 19840 }); // TX8 commited
-      (yield s1.get('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo')).should.have.property('sources').length(1); // That's why toc now has 1 more source...
-      (yield s1.get('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV')).should.have.property('sources').length(3); // ...and why tic's number of sources hasn't changed
-    }));
-
-    it('with MULTISIG', () => co(function *() {
-      (yield s1.get('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo')).should.have.property('sources').length(1);
-      (yield s1.get('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV')).should.have.property('sources').length(3);
-      let tx1 = yield toc.prepareITX(1200, tic);
-      yield toc.sendTX(tx1);
-      yield s1.commit({ time: now + 19840 });
-      let current = yield s1.get('/blockchain/current');
-      (yield s1.get('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo')).should.have.property('sources').length(0);
-      (yield s1.get('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV')).should.have.property('sources').length(4);
+      let current = await s1.get('/blockchain/current');
+      let tx2 = await tic.prepareUTX(tx1, ['SIG(2)'], [{ qty: 1200, base: 0, lock: 'SIG(' + toc.pub + ')' }], { comment: 'wrong', blockstamp: [current.number, current.hash].join('-') });
+      let tx3 = await tic.prepareUTX(tx1, ['SIG(1)'], [{ qty: 1200, base: 0, lock: 'SIG(' + toc.pub + ')' }], { comment: 'wrong', blockstamp: [current.number, current.hash].join('-') });
+      let tx4 = await tic.prepareUTX(tx1, ['SIG(0)'], [{ qty: 1200, base: 0, lock: 'XHX(8AFC8DF633FC158F9DB4864ABED696C1AA0FE5D617A7B5F7AB8DE7CA2EFCD4CB)' }], { comment: 'ok', blockstamp: [current.number, current.hash].join('-') });
+      let tx5 = await tic.prepareUTX(tx1, ['XHX(2)'], [{ qty: 1200, base: 0, lock: 'SIG(' + toc.pub + ')' }], { comment: 'wrong', blockstamp: [current.number, current.hash].join('-') });
+      let tx6 = await tic.prepareUTX(tx1, ['XHX(4)'], [{ qty: 1200, base: 0, lock: 'SIG(' + toc.pub + ')' }], { comment: 'wrong', blockstamp: [current.number, current.hash].join('-') });
+      await shouldFail(toc.sendTX(tx2), 'Wrong unlocker in transaction');
+      await shouldFail(toc.sendTX(tx3), 'Wrong unlocker in transaction');
+      await shouldNotFail(toc.sendTX(tx4));
+      await shouldFail(toc.sendTX(tx5), 'Wrong unlocker in transaction');
+      await shouldFail(toc.sendTX(tx6), 'Wrong unlocker in transaction');
+      await s1.commit({ time: now + 19840 }); // TX4 commited
+      (await s1.get('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo')).should.have.property('sources').length(0); // The tx was not sent to someone, but with an XHX! So toc has nothing more than before.
+      (await s1.get('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV')).should.have.property('sources').length(3);
+      let tx7 = await tic.prepareUTX(tx4, ['XHX(2872767826647264)'], [{ qty: 1200, base: 0, lock: 'SIG(' + toc.pub + ')' }], { comment: 'wrong1', blockstamp: [current.number, current.hash].join('-') });
+      let tx8 = await tic.prepareUTX(tx4, ['XHX(1872767826647264)'], [{ qty: 1200, base: 0, lock: 'SIG(' + toc.pub + ')' }], { comment: 'okk', blockstamp: [current.number, current.hash].join('-') }); // tic unlocks the XHX locked amount, and gives it to toc!
+      await shouldFail(toc.sendTX(tx7), 'Wrong unlocker in transaction');
+      await shouldNotFail(toc.sendTX(tx8));
+      await s1.commit({ time: now + 19840 }); // TX8 commited
+      (await s1.get('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo')).should.have.property('sources').length(1); // That's why toc now has 1 more source...
+      (await s1.get('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV')).should.have.property('sources').length(3); // ...and why tic's number of sources hasn't changed
+    })
+
+    it('with MULTISIG', async () => {
+      (await s1.get('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo')).should.have.property('sources').length(1);
+      (await s1.get('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV')).should.have.property('sources').length(3);
+      let tx1 = await toc.prepareITX(1200, tic);
+      await toc.sendTX(tx1);
+      await s1.commit({ time: now + 19840 });
+      let current = await s1.get('/blockchain/current');
+      (await s1.get('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo')).should.have.property('sources').length(0);
+      (await s1.get('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV')).should.have.property('sources').length(4);
       // The funding transaction that can be reverted by its issuer (tic here) or consumed by toc if he knowns X for H(X)
-      let tx2 = yield tic.prepareUTX(tx1, ['SIG(0)'], [{ qty: 1200, base: 0, lock: '(XHX(8AFC8DF633FC158F9DB4864ABED696C1AA0FE5D617A7B5F7AB8DE7CA2EFCD4CB) && SIG(' + toc.pub + ')) || (SIG(' + tic.pub + ') && SIG(' + toc.pub + '))'  }], { comment: 'cross1', blockstamp: [current.number, current.hash].join('-') });
-      yield unit.shouldNotFail(toc.sendTX(tx2));
-      yield s1.commit({ time: now + 19840 }); // TX2 commited
-      (yield s1.get('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo')).should.have.property('sources').length(1); // toc is also present in the target of tx2
-      (yield s1.get('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV')).should.have.property('sources').length(4); // As well as tic
-      let tx3 = yield tic.prepareUTX(tx2, ['XHX(1872767826647264) SIG(0)'], [{ qty: 1200, base: 0, lock: 'SIG(' + toc.pub + ')' }], { comment: 'wrong', blockstamp: [current.number, current.hash].join('-') });
-      let tx4 = yield toc.prepareUTX(tx2, ['XHX(1872767826647264) SIG(0)'], [{ qty: 1200, base: 0, lock: 'SIG(' + toc.pub + ')' }], { comment: 'ok', blockstamp: [current.number, current.hash].join('-') });
-      let tx5 = yield tic.prepareMTX(tx2, toc, ['XHX(1872767826647264) SIG(1) SIG(0)'], [{ qty: 1200, base: 0, lock: 'SIG(' + toc.pub + ')' }], { comment: 'multi OK', blockstamp: [current.number, current.hash].join('-') });
-      let tx6 = yield toc.prepareMTX(tx2, tic, ['XHX(1872767826647264) SIG(1) SIG(0) SIG(0) SIG(0)'], [{ qty: 1200, base: 0, lock: 'SIG(' + toc.pub + ')' }], { comment: 'multi WRONG', blockstamp: [current.number, current.hash].join('-') });
+      let tx2 = await tic.prepareUTX(tx1, ['SIG(0)'], [{ qty: 1200, base: 0, lock: '(XHX(8AFC8DF633FC158F9DB4864ABED696C1AA0FE5D617A7B5F7AB8DE7CA2EFCD4CB) && SIG(' + toc.pub + ')) || (SIG(' + tic.pub + ') && SIG(' + toc.pub + '))'  }], { comment: 'cross1', blockstamp: [current.number, current.hash].join('-') });
+      await shouldNotFail(toc.sendTX(tx2));
+      await s1.commit({ time: now + 19840 }); // TX2 commited
+      (await s1.get('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo')).should.have.property('sources').length(1); // toc is also present in the target of tx2
+      (await s1.get('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV')).should.have.property('sources').length(4); // As well as tic
+      let tx3 = await tic.prepareUTX(tx2, ['XHX(1872767826647264) SIG(0)'], [{ qty: 1200, base: 0, lock: 'SIG(' + toc.pub + ')' }], { comment: 'wrong', blockstamp: [current.number, current.hash].join('-') });
+      let tx4 = await toc.prepareUTX(tx2, ['XHX(1872767826647264) SIG(0)'], [{ qty: 1200, base: 0, lock: 'SIG(' + toc.pub + ')' }], { comment: 'ok', blockstamp: [current.number, current.hash].join('-') });
+      let tx5 = await tic.prepareMTX(tx2, toc, ['XHX(1872767826647264) SIG(1) SIG(0)'], [{ qty: 1200, base: 0, lock: 'SIG(' + toc.pub + ')' }], { comment: 'multi OK', blockstamp: [current.number, current.hash].join('-') });
+      let tx6 = await toc.prepareMTX(tx2, tic, ['XHX(1872767826647264) SIG(1) SIG(0) SIG(0) SIG(0)'], [{ qty: 1200, base: 0, lock: 'SIG(' + toc.pub + ')' }], { comment: 'multi WRONG', blockstamp: [current.number, current.hash].join('-') });
       // nLocktime
-      let tx7 = yield tic.prepareMTX(tx2, toc, ['XHX(1872767826647264) SIG(1) SIG(0)'], [{ qty: 1200, base: 0, lock: 'SIG(' + toc.pub + ')' }], { comment: 'wrong locktime', locktime: 100, blockstamp: [current.number, current.hash].join('-') });
-      yield unit.shouldFail(toc.sendTX(tx3), 'Wrong unlocker in transaction');
-      yield unit.shouldNotFail(toc.sendTX(tx4));
-      yield unit.shouldNotFail(toc.sendTX(tx5));
-      yield unit.shouldFail(toc.sendTX(tx6), 'Wrong unlocker in transaction');
-      yield unit.shouldFail(toc.sendTX(tx7), 'Locktime not elapsed yet');
-    }));
-  });
-});
+      let tx7 = await tic.prepareMTX(tx2, toc, ['XHX(1872767826647264) SIG(1) SIG(0)'], [{ qty: 1200, base: 0, lock: 'SIG(' + toc.pub + ')' }], { comment: 'wrong locktime', locktime: 100, blockstamp: [current.number, current.hash].join('-') });
+      await shouldFail(toc.sendTX(tx3), 'Wrong unlocker in transaction');
+      await shouldNotFail(toc.sendTX(tx4));
+      await shouldNotFail(toc.sendTX(tx5));
+      await shouldFail(toc.sendTX(tx6), 'Wrong unlocker in transaction');
+      await shouldFail(toc.sendTX(tx7), 'Locktime not elapsed yet');
+    })
+  })
+})
diff --git a/test/integration/v1.0-modules-api.js b/test/integration/v1.0-modules-api.js
index 1cee0379a3398af691f82645dab85ed04b423797..e884aa75caf0a106a1d16c6d4e1eeca163bdbbf1 100644
--- a/test/integration/v1.0-modules-api.js
+++ b/test/integration/v1.0-modules-api.js
@@ -14,7 +14,6 @@
 "use strict";
 
 const co      = require('co');
-const _       = require('underscore');
 const should  = require('should');
 const util    = require('util');
 const path    = require('path');
diff --git a/test/integration/v1.0-source-garbaging.disabled b/test/integration/v1.0-source-garbaging.disabled
deleted file mode 100644
index e667749603216bdd6a0348f5b30e73f426b86a9a..0000000000000000000000000000000000000000
--- a/test/integration/v1.0-source-garbaging.disabled
+++ /dev/null
@@ -1,206 +0,0 @@
-"use strict";
-
-const co        = require('co');
-const should    = require('should');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const constants = require('../../app/lib/constants');
-const toolbox   = require('./tools/toolbox');
-
-const now = 1480000000;
-
-const conf = {
-  ud0: 9995,
-  c: .99,
-  dt: 300,
-  udTime0: now + 300,
-  udReevalTime0: now + 300,
-  avgGenTime: 5000,
-  medianTimeBlocks: 1 // The medianTime always equals previous block's medianTime
-};
-
-constants.NB_DIGITS_UD = 4;
-
-let s1, cat, tac;
-
-describe("Protocol 1.0 Source Garbaging", function() {
-
-  /*****
-   * DESCRIPTION
-   * -----------
-   *
-   * All accounts having less than 100 units of money (current base) must see their money garbaged, i.e. destroyed.
-   *
-   * This measure is here to avoid a metastasizing of the database because of users who would spend very little amounts
-   * of money to random addresses, or to finally destroy very old money (dozens of years).
-   */
-
-  before(() => co(function*() {
-
-    const res1 = yield toolbox.simpleNodeWith2Users(conf);
-    s1 = res1.s1;
-    cat = res1.cat; // HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd
-    tac = res1.tac; // 2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc
-    yield s1.commit({ time: now });
-    yield s1.commit({ time: now + 300 });
-  }));
-
-  it('cat should have no source initially', () => co(function*() {
-    yield s1.expectThat('/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', (json) => {
-      json.sources.should.have.length(0);
-    });
-  }));
-
-  it('cat should have a Dividend, as well as tac', () => co(function*() {
-    yield s1.commit({ time: now + 300 });
-    yield s1.expectThat('/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', (json) => {
-      json.sources.should.deepEqual([
-        { type: 'D', noffset: 2, identifier: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', amount: 9995, base: 0 }
-      ]);
-    });
-  }));
-
-  it('should be able to send money to tac with no losses', () => co(function*() {
-    yield cat.sendP(2999, tac);
-    yield s1.commit({ time: now + 300 });
-    yield cat.sendP(1, tac);
-    yield s1.commit({ time: now + 300 });
-    yield s1.expectThat('/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', (json) => {
-      json.sources.should.deepEqual([
-        { type: 'T', noffset: 1, identifier: '50844926EC611BF6BBF9918A657F87E0AA0DE5A5D8DB3D476289BF64C6ED8C25', amount: 6995, base: 0 }
-      ]);
-    });
-    yield s1.expectThat('/tx/sources/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', (json) => {
-      json.sources.should.deepEqual([
-        { type: 'D', noffset: 2, identifier: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', amount: 9995, base: 0 },
-        { type: 'T', noffset: 0, identifier: 'E84C72FBE788F6F52B293676A8314A6F227F14B0A8FD0168E1C4F08E85D1F8E9', amount: 2999, base: 0 },
-        { type: 'T', noffset: 0, identifier: '50844926EC611BF6BBF9918A657F87E0AA0DE5A5D8DB3D476289BF64C6ED8C25', amount: 1, base: 0 }
-      ]);
-    });
-  }));
-
-  it('should be able to send money to tac with still no losses', () => co(function*() {
-    yield cat.sendP(5495, tac);
-    yield s1.commit({ time: now + 300 });
-    yield s1.expectThat('/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', (json) => {
-      json.sources.should.deepEqual([
-        { type: 'T', noffset: 1, identifier: 'DA453C8B6300F06AC538D7EFB154DA9AE51F30D525236B9D4AD13944E18AA1B0', amount: 1500, base: 0 }
-      ]);
-    });
-    yield s1.expectThat('/tx/sources/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', (json) => {
-      json.sources.should.deepEqual([
-        { type: 'D', noffset: 2, identifier: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', amount: 9995, base: 0 },
-        { type: 'T', noffset: 0, identifier: 'E84C72FBE788F6F52B293676A8314A6F227F14B0A8FD0168E1C4F08E85D1F8E9', amount: 2999, base: 0 },
-        { type: 'T', noffset: 0, identifier: '50844926EC611BF6BBF9918A657F87E0AA0DE5A5D8DB3D476289BF64C6ED8C25', amount: 1, base: 0 },
-        { type: 'T', noffset: 0, identifier: 'DA453C8B6300F06AC538D7EFB154DA9AE51F30D525236B9D4AD13944E18AA1B0', amount: 5495, base: 0 }
-      ]);
-    });
-  }));
-
-  it('should be able to lose money by sending 1,99,100,999,1000,300+700 units to random accounts', () => co(function*() {
-    yield s1.expectThat('/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', (json) => {
-      json.sources.should.deepEqual([
-        { type: 'T', noffset: 1, identifier: 'DA453C8B6300F06AC538D7EFB154DA9AE51F30D525236B9D4AD13944E18AA1B0', amount: 1500, base: 0 }
-      ]);
-    });
-    yield cat.sendP(1, '6EQoFVnFf2xpaRzieNTXmAKU6XkDHYrvgorJ8ppMFa8b');
-    yield s1.commit({ time: now + 300 });
-    yield s1.expectThat('/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', (json) => {
-      json.sources.should.deepEqual([
-        { type: 'T', noffset: 1, identifier: 'A6F2C3DFF8EFEBE226F103E86193A8F22A51D25DD63C2BB9BF86D9A5F3DC55B8', amount: 1499, base: 0 }
-      ]);
-    });
-    yield cat.sendP(99, '2EvWF9XM6TY3zUDjwi3qfGRW5zhN11TXcUDXdgK2XK41');
-    yield s1.commit({ time: now + 300 });
-    yield s1.expectThat('/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', (json) => {
-      json.sources.should.deepEqual([
-        { type: 'T', noffset: 1, identifier: 'F1C86F38F33B2D37561EE927801D8B630BCADA62336E4BBC718BA06B1101584C', amount: 1400, base: 0 }
-      ]);
-    });
-    yield cat.sendP(100, 'DPFgnVSB14QnYFjKNhbFRYLxroSmaXZ53TzgFZBcCxbF');
-    yield s1.commit({ time: now + 300 });
-    yield s1.expectThat('/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', (json) => {
-      json.sources.should.deepEqual([
-        { type: 'T', noffset: 1, identifier: '0FAD3D25899C789C1C2B12FE3D90BF26E5794FB31ECF5072A881DF9B83E7CA00', amount: 1300, base: 0 }
-      ]);
-    });
-    yield tac.sendP(4, 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
-    yield cat.sendP(999, '4WmQWq4NuJtu6mzFDKkmmu6Cm6BZvgoY4b4MMDMwVvu7');
-    yield s1.commit({ time: now + 300 });
-    yield s1.expectThat('/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', (json) => {
-      json.sources.should.deepEqual([
-        { type: 'T', noffset: 0, identifier: '3B12EEC97704A8CCA31AFD7B60BA09555744703E22A6A47EE4ECBE6DA20B27E5', amount: 4, base: 0 },
-        { type: 'T', noffset: 1, identifier: '9B18E2C2CBF9C856560E76F8684665C8677DD0506AAD5195960E30CC37A5706C', amount: 301, base: 0 }
-      ]);
-    });
-    yield cat.sendP(300, '7kMAi8wttYKPK5QSfCwoDriNTcCTWKzTbuSjsLsjGJX2');
-    yield tac.sendP(700, '7kMAi8wttYKPK5QSfCwoDriNTcCTWKzTbuSjsLsjGJX2');
-    yield s1.commit({ time: now + 900 });
-    // Has spent all its money, + 1 unit destroyed
-    yield s1.expectThat('/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', (json) => {
-      json.sources.should.deepEqual([]);
-    });
-    // Has seen 1 unit destroyed
-    yield s1.expectThat('/tx/sources/6EQoFVnFf2xpaRzieNTXmAKU6XkDHYrvgorJ8ppMFa8b', (json) => {
-      json.sources.should.deepEqual([]);
-    });
-    // Has seen 99 unit destroyed
-    yield s1.expectThat('/tx/sources/2EvWF9XM6TY3zUDjwi3qfGRW5zhN11TXcUDXdgK2XK41', (json) => {
-      json.sources.should.deepEqual([]);
-    });
-    // Has just enough on the account (100 units)
-    yield s1.expectThat('/tx/sources/DPFgnVSB14QnYFjKNhbFRYLxroSmaXZ53TzgFZBcCxbF', (json) => {
-      json.sources.should.deepEqual([
-        { type: 'T', noffset: 0, identifier: '0FAD3D25899C789C1C2B12FE3D90BF26E5794FB31ECF5072A881DF9B83E7CA00', amount: 100, base: 0 }
-      ]);
-    });
-    // Has way enough on the account (999 units)
-    yield s1.expectThat('/tx/sources/4WmQWq4NuJtu6mzFDKkmmu6Cm6BZvgoY4b4MMDMwVvu7', (json) => {
-      json.sources.should.deepEqual([
-        { type: 'T', noffset: 0, identifier: '9B18E2C2CBF9C856560E76F8684665C8677DD0506AAD5195960E30CC37A5706C', amount: 999, base: 0 }
-      ]);
-    });
-    // Has way enough on the account (300 + 700 units)
-    yield s1.expectThat('/tx/sources/7kMAi8wttYKPK5QSfCwoDriNTcCTWKzTbuSjsLsjGJX2', (json) => {
-      json.sources.should.deepEqual([
-        { type: 'T', noffset: 0, identifier: '37CD105D17182155978798C773C70950470EBFB27B082F888B3423670F956F35', amount: 300, base: 0 },
-        { type: 'T', noffset: 0, identifier: '6EF384807D1100D51BCCB9ED6E6FF4CA12CC1F4F30392CFD43746D4D1C4BC22E', amount: 700, base: 0 }
-      ]);
-    });
-  }));
-
-  it('should have lost some money with unitBase bumped from 0 to 1', () => co(function*() {
-    yield s1.commit({ time: now + 900 });
-    yield s1.commit({ time: now + 900 });
-    // Has no more enough on the account (100x10^0 < 100x10^1)
-    yield s1.expectThat('/tx/sources/DPFgnVSB14QnYFjKNhbFRYLxroSmaXZ53TzgFZBcCxbF', (json) => {
-      json.sources.should.deepEqual([]);
-    });
-    // Has NOT enough on the account (999x10^0 = 99.9x10^1 < 100x10^1)
-    yield s1.expectThat('/tx/sources/4WmQWq4NuJtu6mzFDKkmmu6Cm6BZvgoY4b4MMDMwVvu7', (json) => {
-      json.sources.should.deepEqual([]);
-    });
-    // Has enough on the account (300x10^0 + 700x10^0 = 1000x10^0 = 100x10^1)
-    yield s1.expectThat('/tx/sources/7kMAi8wttYKPK5QSfCwoDriNTcCTWKzTbuSjsLsjGJX2', (json) => {
-      json.sources.should.deepEqual([
-        { type: 'T', noffset: 0, identifier: '37CD105D17182155978798C773C70950470EBFB27B082F888B3423670F956F35', amount: 300, base: 0 },
-        { type: 'T', noffset: 0, identifier: '6EF384807D1100D51BCCB9ED6E6FF4CA12CC1F4F30392CFD43746D4D1C4BC22E', amount: 700, base: 0 }
-      ]);
-    });
-    yield s1.commit({ time: now + 1800 });
-    // Has enough on the account (300x10^0 + 700x10^0 = 1000x10^0 = 100x10^1)
-    yield s1.expectThat('/tx/sources/7kMAi8wttYKPK5QSfCwoDriNTcCTWKzTbuSjsLsjGJX2', (json) => {
-      json.sources.should.deepEqual([
-        { type: 'T', noffset: 0, identifier: '37CD105D17182155978798C773C70950470EBFB27B082F888B3423670F956F35', amount: 300, base: 0 },
-        { type: 'T', noffset: 0, identifier: '6EF384807D1100D51BCCB9ED6E6FF4CA12CC1F4F30392CFD43746D4D1C4BC22E', amount: 700, base: 0 }
-      ]);
-    });
-    yield s1.commit({ time: now + 3600 });
-    yield s1.expectThat('/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', (json) => {
-      json.sources.should.deepEqual([
-        { type: 'D', noffset: 11, identifier: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', amount: 9995, base: 0 },
-        { type: 'D', noffset: 12, identifier: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', amount: 1980, base: 1 },
-        { type: 'D', noffset: 14, identifier: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', amount: 3940, base: 1 }
-      ]);
-    });
-  }));
-});
diff --git a/test/integration/wot/wotb.ts b/test/integration/wot/wotb.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7ea0074d4c5907c1acbc39465fa17bee9aba3ea9
--- /dev/null
+++ b/test/integration/wot/wotb.ts
@@ -0,0 +1,452 @@
+// Source file from duniter: Crypto-currency software to manage libre currency such as Äž1
+// Copyright (C) 2018  Cedric Moreau <cem.moreau@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+
+import {TestUser} from "../tools/TestUser"
+import {TestingServer} from "../tools/toolbox"
+import {BmaDependency} from "../../../app/modules/bma/index"
+import {WoTBInstance} from "../../../app/lib/wot"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
+
+const should    = require('should');
+const duniter     = require('../../../index');
+const commit    = require('../tools/commit');
+const shutDownEngine  = require('../tools/shutDownEngine');
+
+const MEMORY_MODE = true;
+const commonConf = {
+  ipv4: '127.0.0.1',
+  currency: 'bb',
+  httpLogs: true,
+  forksize: 3,
+  sigQty: 1
+};
+
+let s1:TestingServer,
+  s2:TestingServer,
+  s3:TestingServer,
+  cat:TestUser,
+  toc:TestUser,
+  tic:TestUser,
+  cat2:TestUser,
+  toc2:TestUser,
+  tic2:TestUser,
+  cat3:TestUser,
+  toc3:TestUser,
+  tic3:TestUser
+
+const now = 1482000000;
+const _100_PERCENT = 1.0;
+const MAX_DISTANCE_1 = 1;
+const MAX_DISTANCE_2 = 2;
+const FROM_1_LINK_SENTRIES = 1;
+const __OUTDISTANCED__ = true;
+const __OK__ = false;
+
+describe("WOTB module", () => {
+
+  describe("Server 1", () => {
+
+    let wotb:WoTBInstance
+
+    before(async () => {
+      s1 = duniter(
+        '/bb11',
+        MEMORY_MODE,
+        Underscore.extend({
+          port: '9337',
+          pair: {
+            pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
+            sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
+          },
+          rootoffset: 10,
+          sigQty: 1, dt: 1, ud0: 120
+        }, commonConf));
+
+      s2 = duniter(
+        '/bb41',
+        MEMORY_MODE,
+        Underscore.extend({
+          port: '9338',
+          pair: {
+            pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
+            sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
+          },
+          rootoffset: 10,
+          sigQty: 1, dt: 1, ud0: 120,
+          msValidity: 400 // Memberships expire after 400 second delay
+        }, commonConf));
+
+      s3 = duniter(
+        '/bb11',
+        MEMORY_MODE,
+        Underscore.extend({
+          port: '9339',
+          pair: {
+            pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV',
+            sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'
+          },
+          rootoffset: 10,
+          sigQty: 1, dt: 1, ud0: 120,
+          sigValidity: 1400, sigPeriod: 0
+        }, commonConf));
+
+      cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
+      toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
+      tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
+
+      cat2 = new TestUser('cat2', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s2 });
+      toc2 = new TestUser('toc2', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s2 });
+      tic2 = new TestUser('tic2', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s2 });
+
+      cat3 = new TestUser('cat3', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s3 });
+      toc3 = new TestUser('toc3', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s3 });
+      tic3 = new TestUser('tic3', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s3 });
+
+      /**
+       * cat <==> toc
+       */
+      await s1.initWithDAL().then(BmaDependency.duniter.methods.bma).then((bmapi) => bmapi.openConnections());
+      wotb = s1.dal.wotb;
+      await cat.createIdentity();
+      await toc.createIdentity();
+      await toc.cert(cat);
+      await cat.cert(toc);
+      await cat.join();
+      await toc.join();
+      await commit(s1)({
+        time: now + 500
+      });
+      await commit(s1)({
+        time: now + 500
+      });
+    })
+
+    after(() => {
+      return Promise.all([
+        shutDownEngine(s1)
+      ])
+    })
+
+    it('the wotb_id should be affected to new members', async () => {
+      let icat = await s1.dal.getWrittenIdtyByUIDForWotbId("cat");
+      let itoc = await s1.dal.getWrittenIdtyByUIDForWotbId("toc");
+      icat.should.have.property('wotb_id').equal(0);
+      itoc.should.have.property('wotb_id').equal(1);
+      wotb.isEnabled(0).should.equal(true);
+      wotb.isEnabled(1).should.equal(true);
+      wotb.existsLink(0, 1).should.equal(true);
+      wotb.existsLink(1, 0).should.equal(true);
+      wotb.existsLink(1, 1).should.equal(false);
+      wotb.existsLink(1, 2).should.equal(false);
+      wotb.existsLink(0, 0).should.equal(false);
+      wotb.existsLink(0, 2).should.equal(false);
+      wotb.isOutdistanced(0, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, _100_PERCENT).should.equal(__OK__);
+    });
+
+    it('a newcomer should be affected an ID + links', async () => {
+      /**
+       * cat <==> toc --> tic
+       */
+      await tic.createIdentity();
+      await toc.cert(tic);
+      await tic.join();
+      await commit(s1)();
+      let itic = await s1.dal.getWrittenIdtyByUIDForWotbId("tic");
+      itic.should.have.property('wotb_id').equal(2);
+      wotb.isEnabled(2).should.equal(true);
+      wotb.existsLink(1, 2).should.equal(true);
+      wotb.existsLink(0, 2).should.equal(false);
+      wotb.isOutdistanced(0, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, _100_PERCENT).should.equal(__OK__);
+      wotb.isOutdistanced(1, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, _100_PERCENT).should.equal(__OK__);
+      // tic is outdistanced if k = 1! (cat can't reach him)
+      wotb.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, _100_PERCENT).should.equal(__OUTDISTANCED__);
+      // but reachable if k = 2
+      wotb.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_2, _100_PERCENT).should.equal(__OK__);
+    });
+  });
+
+  describe("Server 2", () => {
+
+    let wotb:WoTBInstance
+
+    before(async () => {
+      /**
+       * tic <==> cat <==> toc
+       */
+      await s2.initWithDAL().then(BmaDependency.duniter.methods.bma).then((bmapi) => bmapi.openConnections());
+      wotb = s2.dal.wotb;
+      await cat2.createIdentity();
+      await toc2.createIdentity();
+      await tic2.createIdentity();
+      // toc2 <==> cat2
+      await toc2.cert(cat2);
+      await cat2.cert(toc2);
+      // tic2 <==> cat2
+      await tic2.cert(cat2);
+      await cat2.cert(tic2);
+      await cat2.join();
+      await toc2.join();
+      await tic2.join();
+      await commit(s2)({
+        time: now
+      });
+      // Should make MS expire for toc2
+      await commit(s2)({
+        time: now + 500
+      });
+      await commit(s2)({
+        time: now + 600
+      });
+      await cat2.join(); // Renew for not to be kicked!
+      await tic2.join(); // Renew for not to be kicked!
+      await commit(s2)({
+        time: now + 800
+      });
+      await commit(s2)({
+        time: now + 800
+      });
+      // Members excluded
+      await commit(s2)({
+        time: now + 800
+      });
+    });
+
+    after(() => {
+      return Promise.all([
+        shutDownEngine(s2)
+      ])
+    })
+
+    it('a leaver should still have links but be disabled', async () => {
+      wotb.isEnabled(0).should.equal(true);
+      wotb.isEnabled(1).should.equal(true);
+      wotb.isEnabled(2).should.equal(false);
+      // tic2 <==> cat2
+      wotb.existsLink(0, 1).should.equal(true);
+      wotb.existsLink(1, 0).should.equal(true);
+      // toc2 <==> cat2
+      wotb.existsLink(0, 2).should.equal(true);
+      wotb.existsLink(2, 0).should.equal(true);
+      // toc2 <==> tic2
+      wotb.existsLink(1, 2).should.equal(false);
+      wotb.existsLink(2, 1).should.equal(false);
+    });
+
+    it('a leaver who joins back should be enabled', async () => {
+      await toc2.join();
+      await commit(s2)();
+      wotb.isEnabled(0).should.equal(true);
+      wotb.isEnabled(1).should.equal(true);
+      wotb.isEnabled(2).should.equal(true);
+      // tic2 <==> cat2
+      wotb.existsLink(0, 1).should.equal(true);
+      wotb.existsLink(1, 0).should.equal(true);
+      // toc2 <==> cat2
+      wotb.existsLink(0, 2).should.equal(true);
+      wotb.existsLink(2, 0).should.equal(true);
+      // toc2 <==> tic2
+      wotb.existsLink(1, 2).should.equal(false);
+      wotb.existsLink(2, 1).should.equal(false);
+    });
+  });
+
+  describe("Server 3", () => {
+
+    let wotb:WoTBInstance
+
+    before(async () => {
+      await s3.initWithDAL().then(BmaDependency.duniter.methods.bma).then((bmapi) => bmapi.openConnections());
+      wotb = s3.dal.wotb;
+      await cat3.createIdentity();
+      await tic3.createIdentity();
+      // cat <==> tic
+      await tic3.cert(cat3);
+      await cat3.cert(tic3);
+      await cat3.join();
+      await tic3.join();
+    });
+
+    after(() => {
+      return Promise.all([
+        shutDownEngine(s3)
+      ])
+    })
+
+    it('two first commits: the WoT is new and OK', async () => {
+      await commit(s3)({ time: now });
+      await commit(s3)({
+        time: now + 1200
+      });
+      /**
+       * cat <==> tic
+       */
+      wotb.isEnabled(0).should.equal(true);
+      wotb.isEnabled(1).should.equal(true);
+      // cat3 <==> tic3
+      wotb.existsLink(0, 1).should.equal(true);
+      wotb.existsLink(1, 0).should.equal(true);
+      // tic3 <==> toc3
+      wotb.existsLink(1, 2).should.equal(false);
+      wotb.existsLink(2, 1).should.equal(false);
+    });
+
+    it('third & fourth commits: toc should have joined', async () => {
+      await commit(s3)({
+        time: now + 2400
+      });
+      // MedianTime is now +500 for next certs
+      await toc3.createIdentity();
+      await toc3.join();
+      await tic3.cert(toc3);
+      await commit(s3)({
+        time: now + 4000
+      });
+      // MedianTime is now +1000 for next certs
+      /**
+       * cat <==> tic --> toc
+       */
+      wotb.isEnabled(0).should.equal(true);
+      wotb.isEnabled(1).should.equal(true);
+      wotb.isEnabled(2).should.equal(true);
+      // cat3 <==> tic3
+      wotb.existsLink(0, 1).should.equal(true);
+      wotb.existsLink(1, 0).should.equal(true);
+      // tic3 <==> toc3
+      wotb.existsLink(1, 2).should.equal(true);
+      wotb.existsLink(2, 1).should.equal(false);
+    });
+
+    it('fifth commit: cat still here, but not its certs', async () => {
+      await toc3.cert(tic3);
+      await commit(s3)({
+        time: now + 4000
+      });
+      /**
+       *   cat     tic <==> toc
+       */
+      wotb.isEnabled(0).should.equal(true); // But marked as to kick: cannot issue new links
+      wotb.isEnabled(1).should.equal(true);
+      wotb.isEnabled(2).should.equal(true);
+      // cat3 <==> tic3
+      wotb.existsLink(0, 1).should.equal(false);
+      wotb.existsLink(1, 0).should.equal(false);
+      // tic3 <==> toc3
+      wotb.existsLink(1, 2).should.equal(true);
+      wotb.existsLink(2, 1).should.equal(true);
+    });
+
+    it('sixth commit: cat is gone with its certs', async () => {
+      await commit(s3)({
+        time: now + 2500
+      });
+      /**
+       *         tic <-- toc
+       */
+      wotb.isEnabled(0).should.equal(false);
+      wotb.isEnabled(1).should.equal(true);
+      wotb.isEnabled(2).should.equal(true);
+      // cat3 <==> tic3
+      wotb.existsLink(0, 1).should.equal(false);
+      wotb.existsLink(1, 0).should.equal(false);
+      // tic3 --> toc3
+      wotb.existsLink(1, 2).should.equal(false);
+      wotb.existsLink(2, 1).should.equal(true);
+    });
+
+    it('seventh commit: toc is gone, but not its cert to tic', async () => {
+      await tic3.cert(cat3);
+      await cat3.join();
+      await commit(s3)({
+        time: now + 5000
+      });
+      /**
+       *  cat <-- tic <-- [toc]
+       */
+      wotb.isEnabled(0).should.equal(true);
+      wotb.isEnabled(1).should.equal(true);
+      wotb.isEnabled(2).should.equal(false);
+      // cat3 <==> tic3
+      wotb.existsLink(0, 1).should.equal(false);
+      wotb.existsLink(1, 0).should.equal(true);
+      // tic3 --> toc3
+      wotb.existsLink(1, 2).should.equal(false);
+      wotb.existsLink(2, 1).should.equal(true);
+    });
+
+    it('revert seventh commit: toc is back, cat is gone', async () => {
+      await s3.revert();
+      wotb.isEnabled(0).should.equal(false);
+      wotb.isEnabled(1).should.equal(true);
+      wotb.isEnabled(2).should.equal(true);
+      // cat3 <==> tic3
+      wotb.existsLink(0, 1).should.equal(false);
+      wotb.existsLink(1, 0).should.equal(false);
+      // tic3 --> toc3
+      wotb.existsLink(1, 2).should.equal(false);
+      wotb.existsLink(2, 1).should.equal(true);
+    });
+
+    it('revert sixth commit: cat is back', async () => {
+      await s3.revert();
+      wotb.isEnabled(0).should.equal(true); // But marked as to kick: cannot issue new links
+      wotb.isEnabled(1).should.equal(true);
+      wotb.isEnabled(2).should.equal(true);
+      // cat3 <==> tic3
+      wotb.existsLink(0, 1).should.equal(false);
+      wotb.existsLink(1, 0).should.equal(false);
+      // tic3 <==> toc3
+      wotb.existsLink(1, 2).should.equal(true);
+      wotb.existsLink(2, 1).should.equal(true);
+    });
+
+    it('revert fifth commit', async () => {
+      await s3.revert();
+      wotb.isEnabled(0).should.equal(true);
+      wotb.isEnabled(1).should.equal(true);
+      wotb.isEnabled(2).should.equal(true);
+      // cat3 <==> tic3
+      wotb.existsLink(0, 1).should.equal(true);
+      wotb.existsLink(1, 0).should.equal(true);
+      // tic3 <==> toc3
+      wotb.existsLink(1, 2).should.equal(true);
+      wotb.existsLink(2, 1).should.equal(false);
+    });
+
+    it('revert third & fourth commits', async () => {
+      await s3.revert();
+      await s3.revert();
+      wotb.isEnabled(0).should.equal(true);
+      wotb.isEnabled(1).should.equal(true);
+      // cat3 <==> tic3
+      wotb.existsLink(0, 1).should.equal(true);
+      wotb.existsLink(1, 0).should.equal(true);
+      // tic3 <==> toc3
+      wotb.existsLink(1, 2).should.equal(false);
+      wotb.existsLink(2, 1).should.equal(false);
+    });
+
+    it('revert first & second commits', async () => {
+      await s3.revert();
+      await s3.revert();
+      wotb.isEnabled(0).should.equal(false);
+      wotb.isEnabled(1).should.equal(false);
+      wotb.isEnabled(2).should.equal(false);
+      // cat3 <==> tic3
+      wotb.existsLink(0, 1).should.equal(false);
+      wotb.existsLink(1, 0).should.equal(false);
+      // tic3 <==> toc3
+      wotb.existsLink(1, 2).should.equal(false);
+      wotb.existsLink(2, 1).should.equal(false);
+    });
+  });
+});
diff --git a/test/integration/wotb.js b/test/integration/wotb.js
deleted file mode 100644
index 029cc4b0b06a08d59695eb8c6985418bbad09bc1..0000000000000000000000000000000000000000
--- a/test/integration/wotb.js
+++ /dev/null
@@ -1,479 +0,0 @@
-// Source file from duniter: Crypto-currency software to manage libre currency such as Äž1
-// Copyright (C) 2018  Cedric Moreau <cem.moreau@gmail.com>
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU Affero General Public License for more details.
-
-"use strict";
-
-const co        = require('co');
-const should    = require('should');
-const _         = require('underscore');
-const duniter     = require('../../index');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const TestUser  = require('./tools/TestUser').TestUser
-const commit    = require('./tools/commit');
-const shutDownEngine  = require('./tools/shutDownEngine');
-
-const MEMORY_MODE = true;
-const commonConf = {
-  ipv4: '127.0.0.1',
-  currency: 'bb',
-  httpLogs: true,
-  forksize: 3,
-  sigQty: 1
-};
-
-let s1, s2, s3, cat, toc, tic, cat2, toc2, tic2, cat3, toc3, tic3
-
-const now = 1482000000;
-const _100_PERCENT = 1.0;
-const MAX_DISTANCE_1 = 1;
-const MAX_DISTANCE_2 = 2;
-const FROM_1_LINK_SENTRIES = 1;
-const __OUTDISTANCED__ = true;
-const __OK__ = false;
-
-describe("WOTB module", function() {
-
-  describe("Server 1", () => {
-
-    let wotb;
-
-    before(function() {
-
-      return co(function *() {
-
-        s1 = duniter(
-          '/bb11',
-          MEMORY_MODE,
-          _.extend({
-            port: '9337',
-            pair: {
-              pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
-              sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
-            },
-            rootoffset: 10,
-            sigQty: 1, dt: 1, ud0: 120
-          }, commonConf));
-
-        s2 = duniter(
-          '/bb41',
-          MEMORY_MODE,
-          _.extend({
-            port: '9338',
-            pair: {
-              pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
-              sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
-            },
-            rootoffset: 10,
-            sigQty: 1, dt: 1, ud0: 120,
-            msValidity: 400 // Memberships expire after 400 second delay
-          }, commonConf));
-
-        s3 = duniter(
-          '/bb11',
-          MEMORY_MODE,
-          _.extend({
-            port: '9339',
-            pair: {
-              pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV',
-              sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'
-            },
-            rootoffset: 10,
-            sigQty: 1, dt: 1, ud0: 120,
-            sigValidity: 1400, sigPeriod: 0
-          }, commonConf));
-
-        cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-        toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
-        tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
-
-        cat2 = new TestUser('cat2', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s2 });
-        toc2 = new TestUser('toc2', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s2 });
-        tic2 = new TestUser('tic2', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s2 });
-
-        cat3 = new TestUser('cat3', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s3 });
-        toc3 = new TestUser('toc3', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s3 });
-        tic3 = new TestUser('tic3', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s3 });
-
-        /**
-         * cat <==> toc
-         */
-        yield s1.initWithDAL().then(bma).then((bmapi) => bmapi.openConnections());
-        wotb = s1.dal.wotb;
-        yield cat.createIdentity();
-        yield toc.createIdentity();
-        yield toc.cert(cat);
-        yield cat.cert(toc);
-        yield cat.join();
-        yield toc.join();
-        yield commit(s1)({
-          time: now + 500
-        });
-        yield commit(s1)({
-          time: now + 500
-        });
-      });
-    });
-
-    after(() => {
-      return Promise.all([
-        shutDownEngine(s1)
-      ])
-    })
-
-    it('the wotb_id should be affected to new members', function() {
-      return co(function *() {
-        let icat = yield s1.dal.getWrittenIdtyByUIDForWotbId("cat");
-        let itoc = yield s1.dal.getWrittenIdtyByUIDForWotbId("toc");
-        icat.should.have.property('wotb_id').equal(0);
-        itoc.should.have.property('wotb_id').equal(1);
-        wotb.isEnabled(0).should.equal(true);
-        wotb.isEnabled(1).should.equal(true);
-        wotb.existsLink(0, 1).should.equal(true);
-        wotb.existsLink(1, 0).should.equal(true);
-        wotb.existsLink(1, 1).should.equal(false);
-        wotb.existsLink(1, 2).should.equal(false);
-        wotb.existsLink(0, 0).should.equal(false);
-        wotb.existsLink(0, 2).should.equal(false);
-        wotb.isOutdistanced(0, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, _100_PERCENT).should.equal(__OK__);
-      });
-    });
-
-    it('a newcomer should be affected an ID + links', function() {
-      return co(function *() {
-        /**
-         * cat <==> toc --> tic
-         */
-        yield tic.createIdentity();
-        yield toc.cert(tic);
-        yield tic.join();
-        yield commit(s1)();
-        let itic = yield s1.dal.getWrittenIdtyByUIDForWotbId("tic");
-        itic.should.have.property('wotb_id').equal(2);
-        wotb.isEnabled(2).should.equal(true);
-        wotb.existsLink(1, 2).should.equal(true);
-        wotb.existsLink(0, 2).should.equal(false);
-        wotb.isOutdistanced(0, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, _100_PERCENT).should.equal(__OK__);
-        wotb.isOutdistanced(1, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, _100_PERCENT).should.equal(__OK__);
-        // tic is outdistanced if k = 1! (cat can't reach him)
-        wotb.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, _100_PERCENT).should.equal(__OUTDISTANCED__);
-        // but reachable if k = 2
-        wotb.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_2, _100_PERCENT).should.equal(__OK__);
-      });
-    });
-  });
-
-  describe("Server 2", () => {
-
-    let wotb;
-
-    before(function() {
-
-      return co(function *() {
-        /**
-         * tic <==> cat <==> toc
-         */
-        yield s2.initWithDAL().then(bma).then((bmapi) => bmapi.openConnections());
-        wotb = s2.dal.wotb;
-        yield cat2.createIdentity();
-        yield toc2.createIdentity();
-        yield tic2.createIdentity();
-        // toc2 <==> cat2
-        yield toc2.cert(cat2);
-        yield cat2.cert(toc2);
-        // tic2 <==> cat2
-        yield tic2.cert(cat2);
-        yield cat2.cert(tic2);
-        yield cat2.join();
-        yield toc2.join();
-        yield tic2.join();
-        yield commit(s2)({
-          time: now
-        });
-        // Should make MS expire for toc2
-        yield commit(s2)({
-          time: now + 500
-        });
-        yield commit(s2)({
-          time: now + 600
-        });
-        yield cat2.join(); // Renew for not to be kicked!
-        yield tic2.join(); // Renew for not to be kicked!
-        yield commit(s2)({
-          time: now + 800
-        });
-        yield commit(s2)({
-          time: now + 800
-        });
-        // Members excluded
-        yield commit(s2)({
-          time: now + 800
-        });
-      });
-    });
-
-    after(() => {
-      return Promise.all([
-        shutDownEngine(s2)
-      ])
-    })
-
-    it('a leaver should still have links but be disabled', function() {
-      return co(function *() {
-        wotb.isEnabled(0).should.equal(true);
-        wotb.isEnabled(1).should.equal(true);
-        wotb.isEnabled(2).should.equal(false);
-        // tic2 <==> cat2
-        wotb.existsLink(0, 1).should.equal(true);
-        wotb.existsLink(1, 0).should.equal(true);
-        // toc2 <==> cat2
-        wotb.existsLink(0, 2).should.equal(true);
-        wotb.existsLink(2, 0).should.equal(true);
-        // toc2 <==> tic2
-        wotb.existsLink(1, 2).should.equal(false);
-        wotb.existsLink(2, 1).should.equal(false);
-      });
-    });
-
-    it('a leaver who joins back should be enabled', function() {
-      return co(function *() {
-        yield toc2.join();
-        yield commit(s2)();
-        wotb.isEnabled(0).should.equal(true);
-        wotb.isEnabled(1).should.equal(true);
-        wotb.isEnabled(2).should.equal(true);
-        // tic2 <==> cat2
-        wotb.existsLink(0, 1).should.equal(true);
-        wotb.existsLink(1, 0).should.equal(true);
-        // toc2 <==> cat2
-        wotb.existsLink(0, 2).should.equal(true);
-        wotb.existsLink(2, 0).should.equal(true);
-        // toc2 <==> tic2
-        wotb.existsLink(1, 2).should.equal(false);
-        wotb.existsLink(2, 1).should.equal(false);
-      });
-    });
-  });
-
-  describe("Server 3", () => {
-
-    let wotb;
-
-    before(function() {
-
-      return co(function *() {
-        yield s3.initWithDAL().then(bma).then((bmapi) => bmapi.openConnections());
-        wotb = s3.dal.wotb;
-        yield cat3.createIdentity();
-        yield tic3.createIdentity();
-        // cat <==> tic
-        yield tic3.cert(cat3);
-        yield cat3.cert(tic3);
-        yield cat3.join();
-        yield tic3.join();
-      });
-    });
-
-    after(() => {
-      return Promise.all([
-        shutDownEngine(s3)
-      ])
-    })
-
-    it('two first commits: the WoT is new and OK', function() {
-      return co(function *() {
-        yield commit(s3)({ time: now });
-        yield commit(s3)({
-          time: now + 1200
-        });
-        /**
-         * cat <==> tic
-         */
-        wotb.isEnabled(0).should.equal(true);
-        wotb.isEnabled(1).should.equal(true);
-        // cat3 <==> tic3
-        wotb.existsLink(0, 1).should.equal(true);
-        wotb.existsLink(1, 0).should.equal(true);
-        // tic3 <==> toc3
-        wotb.existsLink(1, 2).should.equal(false);
-        wotb.existsLink(2, 1).should.equal(false);
-      });
-    });
-
-    it('third & fourth commits: toc should have joined', function() {
-      return co(function *() {
-        yield commit(s3)({
-          time: now + 2400
-        });
-        // MedianTime is now +500 for next certs
-        yield toc3.createIdentity();
-        yield toc3.join();
-        yield tic3.cert(toc3);
-        yield commit(s3)({
-          time: now + 4000
-        });
-        // MedianTime is now +1000 for next certs
-        /**
-         * cat <==> tic --> toc
-         */
-        wotb.isEnabled(0).should.equal(true);
-        wotb.isEnabled(1).should.equal(true);
-        wotb.isEnabled(2).should.equal(true);
-        // cat3 <==> tic3
-        wotb.existsLink(0, 1).should.equal(true);
-        wotb.existsLink(1, 0).should.equal(true);
-        // tic3 <==> toc3
-        wotb.existsLink(1, 2).should.equal(true);
-        wotb.existsLink(2, 1).should.equal(false);
-      });
-    });
-
-    it('fifth commit: cat still here, but not its certs', function() {
-      return co(function *() {
-        yield toc3.cert(tic3);
-        yield commit(s3)({
-          time: now + 4000
-        });
-        /**
-         *   cat     tic <==> toc
-         */
-        wotb.isEnabled(0).should.equal(true); // But marked as to kick: cannot issue new links
-        wotb.isEnabled(1).should.equal(true);
-        wotb.isEnabled(2).should.equal(true);
-        // cat3 <==> tic3
-        wotb.existsLink(0, 1).should.equal(false);
-        wotb.existsLink(1, 0).should.equal(false);
-        // tic3 <==> toc3
-        wotb.existsLink(1, 2).should.equal(true);
-        wotb.existsLink(2, 1).should.equal(true);
-      });
-    });
-
-    it('sixth commit: cat is gone with its certs', function() {
-      return co(function *() {
-        yield commit(s3)({
-          time: now + 2500
-        });
-        /**
-         *         tic <-- toc
-         */
-        wotb.isEnabled(0).should.equal(false);
-        wotb.isEnabled(1).should.equal(true);
-        wotb.isEnabled(2).should.equal(true);
-        // cat3 <==> tic3
-        wotb.existsLink(0, 1).should.equal(false);
-        wotb.existsLink(1, 0).should.equal(false);
-        // tic3 --> toc3
-        wotb.existsLink(1, 2).should.equal(false);
-        wotb.existsLink(2, 1).should.equal(true);
-      });
-    });
-
-    it('seventh commit: toc is gone, but not its cert to tic', function() {
-      return co(function *() {
-        yield tic3.cert(cat3);
-        yield cat3.join();
-        yield commit(s3)({
-          time: now + 5000
-        });
-        /**
-         *  cat <-- tic <-- [toc]
-         */
-        wotb.isEnabled(0).should.equal(true);
-        wotb.isEnabled(1).should.equal(true);
-        wotb.isEnabled(2).should.equal(false);
-        // cat3 <==> tic3
-        wotb.existsLink(0, 1).should.equal(false);
-        wotb.existsLink(1, 0).should.equal(true);
-        // tic3 --> toc3
-        wotb.existsLink(1, 2).should.equal(false);
-        wotb.existsLink(2, 1).should.equal(true);
-      });
-    });
-
-    it('revert seventh commit: toc is back, cat is gone', function() {
-      return co(function *() {
-        yield s3.revert();
-        wotb.isEnabled(0).should.equal(false);
-        wotb.isEnabled(1).should.equal(true);
-        wotb.isEnabled(2).should.equal(true);
-        // cat3 <==> tic3
-        wotb.existsLink(0, 1).should.equal(false);
-        wotb.existsLink(1, 0).should.equal(false);
-        // tic3 --> toc3
-        wotb.existsLink(1, 2).should.equal(false);
-        wotb.existsLink(2, 1).should.equal(true);
-      });
-    });
-
-    it('revert sixth commit: cat is back', function() {
-      return co(function *() {
-        yield s3.revert();
-        wotb.isEnabled(0).should.equal(true); // But marked as to kick: cannot issue new links
-        wotb.isEnabled(1).should.equal(true);
-        wotb.isEnabled(2).should.equal(true);
-        // cat3 <==> tic3
-        wotb.existsLink(0, 1).should.equal(false);
-        wotb.existsLink(1, 0).should.equal(false);
-        // tic3 <==> toc3
-        wotb.existsLink(1, 2).should.equal(true);
-        wotb.existsLink(2, 1).should.equal(true);
-      });
-    });
-
-    it('revert fifth commit', function() {
-      return co(function *() {
-        yield s3.revert();
-        wotb.isEnabled(0).should.equal(true);
-        wotb.isEnabled(1).should.equal(true);
-        wotb.isEnabled(2).should.equal(true);
-        // cat3 <==> tic3
-        wotb.existsLink(0, 1).should.equal(true);
-        wotb.existsLink(1, 0).should.equal(true);
-        // tic3 <==> toc3
-        wotb.existsLink(1, 2).should.equal(true);
-        wotb.existsLink(2, 1).should.equal(false);
-      });
-    });
-
-    it('revert third & fourth commits', function() {
-      return co(function *() {
-        yield s3.revert();
-        yield s3.revert();
-        wotb.isEnabled(0).should.equal(true);
-        wotb.isEnabled(1).should.equal(true);
-        // cat3 <==> tic3
-        wotb.existsLink(0, 1).should.equal(true);
-        wotb.existsLink(1, 0).should.equal(true);
-        // tic3 <==> toc3
-        wotb.existsLink(1, 2).should.equal(false);
-        wotb.existsLink(2, 1).should.equal(false);
-      });
-    });
-
-    it('revert first & second commits', function() {
-      return co(function *() {
-        yield s3.revert();
-        yield s3.revert();
-        wotb.isEnabled(0).should.equal(false);
-        wotb.isEnabled(1).should.equal(false);
-        wotb.isEnabled(2).should.equal(false);
-        // cat3 <==> tic3
-        wotb.existsLink(0, 1).should.equal(false);
-        wotb.existsLink(1, 0).should.equal(false);
-        // tic3 <==> toc3
-        wotb.existsLink(1, 2).should.equal(false);
-        wotb.existsLink(2, 1).should.equal(false);
-      });
-    });
-  });
-});
diff --git a/test/integration/ws2p_connection.ts b/test/integration/ws2p_connection.ts
index f252d3407b46bd49b45b77e0b8fe36af8ebe9cd4..c62159d746f86a5c66416c7ea817f0c344f277fb 100644
--- a/test/integration/ws2p_connection.ts
+++ b/test/integration/ws2p_connection.ts
@@ -19,10 +19,12 @@ import {
   WS2PRemoteAuth
 } from "../../app/modules/ws2p/lib/WS2PConnection"
 import {Key, verify} from "../../app/lib/common-libs/crypto/keyring"
-import {assertThrows, getNewTestingPort} from "./tools/toolbox"
+import {getNewTestingPort} from "./tools/toolbox"
 import {WS2PMessageHandler} from "../../app/modules/ws2p/lib/impl/WS2PMessageHandler"
 import {WS2PResponse} from "../../app/modules/ws2p/lib/impl/WS2PResponse"
 import {WS2PConstants} from "../../app/modules/ws2p/lib/constants"
+import {assertThrows} from "../unit-tools"
+
 const assert = require('assert');
 const WebSocketServer = require('ws').Server
 const logger = require('../../app/lib/logger').NewLogger('ws2p')
diff --git a/test/unit-tools.ts b/test/unit-tools.ts
index b0f100b204906d1ac1d5f668e718b7176ae2e78d..3c85da7e52f1106f53c323128b1c7636e0eb3ce1 100644
--- a/test/unit-tools.ts
+++ b/test/unit-tools.ts
@@ -11,6 +11,8 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
+import * as assert from 'assert'
+
 export async function shouldThrow(promise:Promise<any>) {
   let error = false
   try {
@@ -21,3 +23,40 @@ export async function shouldThrow(promise:Promise<any>) {
   promise.should.be.rejected()
   error.should.equal(true)
 }
+
+export async function shouldNotFail<T>(promise:Promise<T>) {
+  try {
+    await promise
+  } catch(e) {
+    let err = e;
+    if (typeof e === 'string') {
+      err = JSON.parse((e as any).message)
+    }
+    should.not.exist(err);
+  }
+}
+
+export const shouldFail = async (promise:Promise<any>, message:string|null = null) => {
+  try {
+    await promise;
+    throw '{ "message": "Should have thrown an error" }'
+  } catch(e) {
+    let err = e
+    if (typeof e === "string") {
+      err = JSON.parse(e)
+    }
+    err.should.have.property('message').equal(message);
+  }
+}
+
+export const assertThrows = async (promise:Promise<any>, message:string|null = null) => {
+  try {
+    await promise;
+    throw "Should have thrown"
+  } catch(e) {
+    if (e === "Should have thrown") {
+      throw e
+    }
+    assert.equal(e, message)
+  }
+}