diff --git a/.eslintignore b/.eslintignore
index 052737334621d89f18f1b6e66abf9c0fa60712a4..55fc3e6732effa174a7d7a8d92dc89c8b7ebd80f 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,49 +1,4 @@
-app/cli.js
-app/lib/blockchain/*.js
-app/lib/blockchain/interfaces/*.js
-app/lib/computation/*.js
-app/lib/common-libs/*.js
-app/lib/common-libs/**/*.js
-app/lib/db/*.js
-app/lib/dto/*.js
-app/lib/indexer.js
-app/lib/common.js
-app/lib/dal/drivers/*.js
-app/lib/dal/sqliteDAL/*.js
-app/lib/dal/sqliteDAL/index/*.js
-app/lib/dal/fileDALs/*.js
-app/lib/dal/fileDAL.js
-app/service/*.js
-app/lib/rules/*.js
-app/lib/system/*.js
-app/lib/streams/*.js
-app/lib/helpers/*.js
-app/modules/ws2p/*.js
-app/modules/ws2p/lib/*.js
-app/modules/ws2p/lib/*/*.js
-app/lib/*.js
-app/modules/wizard.js
-app/modules/router.js
-app/modules/revert.js
-app/modules/reset.js
-app/modules/reapply.js
-app/modules/peersignal.js
-app/modules/plugin.js
-app/modules/daemon.js
-app/modules/export-bc.js
-app/modules/check-config.js
-app/modules/config.js
-app/modules/prover/*.js
-app/modules/prover/lib/*.js
-app/modules/keypair/*.js
-app/modules/keypair/lib/*.js
-app/modules/bma/*.js
-app/modules/bma/lib/*.js
-app/modules/bma/lib/entity/*.js
-app/modules/bma/lib/controllers/*.js
-app/modules/crawler/*.js
-app/modules/crawler/lib/*.js
-app/ProcessCpuProfiler.js
-app/lib/common/package.js
+app/*.js
+app/**/*.js
 test/*.js
 test/**/*.js
\ No newline at end of file
diff --git a/.eslintrc b/.eslintrc
index 1fe67b0998ca3011b46cfb79179b79d73f9db416..809451a60a39336d7fa7ffc020a76c9534d6f18a 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,11 +1,14 @@
 {
+  "parserOptions": {
+    "ecmaVersion": 8
+  },
   "plugins": [
     "mocha"
   ],
-//  "ecmaFeatures": {
-//    "arrowFunctions": true,
-//    "generators": true
-//  },
+  "ecmaFeatures": {
+    "arrowFunctions": true,
+    "generators": true
+  },
   "rules": {
 
     "curly": 0,
diff --git a/.gitignore b/.gitignore
index 0a79bb0ce1ddaf1033f74641aff5c1ba8f6ce180..6dd12606baa2fd31f558354b9063d39f2ed1e903 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,48 +35,14 @@ vagrant/duniter
 .nyc_output
 coverage/
 
-# TS migration
-test/blockchain/*.js*
-test/blockchain/*.d.ts
-test/blockchain/lib/*.js*
-test/blockchain/lib/*.d.ts
+# typecode
+typedoc/
+
 /index.js*
 /index.d.ts
 /server.js*
 /server.d.ts
 app/**/*.js*
 app/**/*.d.ts
-test/integration/revoked_pubkey_replay.js
-test/integration/server-shutdown.js
-test/integration/transactions-csv-cltv-sig.js
-test/integration/ws2p*js
-test/integration/*.js.map
-test/integration/*.d.ts
-test/integration/membership_chainability.js*
-test/integration/membership_chainability.d.ts
-test/integration/tools/toolbox.js*
-test/integration/tools/toolbox.d.ts
-test/integration/tools/TestUser.js*
-test/integration/tools/TestUser.d.ts
-test/integration/documents-currency.js*
-test/integration/documents-currency.d.ts
-test/integration/forwarding.js
-test/integration/branches_switch.js
-test/integration/branches2.js
-test/integration/transactions-chaining.js
-test/fast/modules/crawler/block_pulling.js*
-test/fast/modules/crawler/block_pulling.d.ts
-test/fast/fork*.js*
-test/fast/fork*.d.ts
-test/fast/proxies*.js*
-test/fast/proxies*.d.ts
-test/fast/modules/ws2p/*.js*
-test/fast/modules/ws2p/*.d.ts
-test/fast/modules/common/grammar.js*
-test/fast/modules/common/grammar.d.ts
-test/fast/prover/pow-1-cluster.d.ts
-test/fast/prover/pow-1-cluster.js
-test/fast/prover/pow-1-cluster.js.map
-test/fast/protocol-local-rule-chained-tx-depth.js
-test/fast/protocol-local-rule-chained-tx-depth.js.map
-test/fast/protocol-local-rule-chained-tx-depth.d.ts
+test/**/*.d.ts
+test/**/*.js*
\ No newline at end of file
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 2a23ae32731bf69c13a352cbcdca577bcde1e928..db9f62ce5939febc664a7fff20ac80eea7ca1195 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -2,6 +2,7 @@ stages:
   - github-sync
   - build
   - test
+  - pages
   - package
   - prerelease
   - release
@@ -33,28 +34,81 @@ push_to_github:
   before_script:
     - export NVM_DIR="$HOME/.nvm"
     - . "$NVM_DIR/nvm.sh"
+
+.cached_nvm: &cached_nvm
+  <<: *nvm_env
+  cache:
+    untracked: true
+    paths:
+      - node_modules/
   
 build:
-  <<: *nvm_env
+  <<: *cached_nvm
   stage: build
   script:
     - yarn
 
+pages:
+  <<: *nvm_env
+  stage: pages
+  cache: {}
+  script:
+    - yarn
+    - yarn doc
+    - mkdir -p public
+    - cp .gitlab/pages/pages-index.html public/index.html
+    - sed -i "s/{BRANCH}/$CI_COMMIT_REF_NAME/g" public/index.html
+    - mv typedoc public/
+    - echo "$CI_JOB_ID"
+    - curl "https://git.duniter.org/nodes/typescript/duniter/-/jobs/$CI_JOB_ID/artifacts/raw/coverage.tar.gz"
+    - tar xzf coverage.tar.gz
+    - mv coverage "public/coverage"
+    - ls public
+  artifacts:
+    untracked: true
+    paths:
+      - public
+  only:
+    - loki
+    - dev
+
 test:
+  <<: *cached_nvm
+  stage: test
+  script:
+    - yarn test
+    # Push coverage to GitLab pages
+    - tar cvzf coverage.tar.gz coverage/
+    # Code coverage display in GitLab
+    - sed -n 23p coverage/index.html | grep -Po "\d+.\d+" | sed -e "s/\(.*\)/<coverage>\1%<\/coverage>/"
+  coverage: '/<coverage>(\d+.\d+\%)<\/coverage>/'
+  artifacts:
+    paths:
+      - coverage.tar.gz
+    expire_in: 4h
+
+sync_g1:
   <<: *nvm_env
   stage: test
   script:
     - yarn
-    - yarn test
-    - sed -n 23p coverage/index.html
+    - bash .gitlab/test/check_g1_sync.sh
+
+sync_gtest:
+  <<: *nvm_env
+  stage: test
+  script:
+    - yarn
+    - bash .gitlab/test/check_gt_sync.sh
 
 .build_releases: &build_releases
   stage: package
   allow_failure: false
-  image: duniter/release-builder:v1.0.1
+  image: duniter/release-builder:v1.2.0
+  cache: {}
+  when: manual
   tags:
     - redshift-duniter-builder
-  when: manual
   artifacts:
     paths: &releases_artifacts
       - work/bin/
@@ -62,6 +116,7 @@ test:
 releases:test:
   <<: *build_releases
   script:
+    - rm -rf node_modules/
     - bash "release/arch/linux/build-lin.sh" "$(date +%Y%m%d).$(date +%H%M).$(date +%S)"
   artifacts:
     paths: *releases_artifacts
@@ -72,6 +127,7 @@ releases:test:
 releases:x64:
   <<: *build_releases
   script:
+    - rm -rf node_modules/
     - bash "release/arch/linux/build-lin.sh" "${CI_COMMIT_TAG#v}"
   artifacts:
     paths: *releases_artifacts
diff --git a/.gitlab/pages/pages-index.html b/.gitlab/pages/pages-index.html
new file mode 100644
index 0000000000000000000000000000000000000000..9e756d7754de4ec66024a899318502fc4c63df7a
--- /dev/null
+++ b/.gitlab/pages/pages-index.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>CI pages</title>
+    <style>
+        html, body {
+            font-family: "Courier New", Consolas, monospace;
+        }
+
+        li {
+            line-height: 25px;
+        }
+    </style>
+</head>
+<body>
+<p>
+    <img src="https://raw.github.com/duniter/duniter/master/images/250%C3%97250.png"/>
+</p>
+<h1>Continuous Integration (CI) pages:</h1>
+<p>
+    <ul>
+        <li><a href="https://nodes.duniter.io/typescript/duniter/typedoc/">Typedoc (`{BRANCH}` branch)</a></li>
+        <li><a href="https://nodes.duniter.io/typescript/duniter/coverage/">Coverage (`{BRANCH}` branch)</a></li>
+    </ul>
+</p>
+</body>
+</html>
\ No newline at end of file
diff --git a/.gitlab/test/check_g1_sync.sh b/.gitlab/test/check_g1_sync.sh
new file mode 100755
index 0000000000000000000000000000000000000000..52f0e8e521306c90a1a6923afc728b73403ef321
--- /dev/null
+++ b/.gitlab/test/check_g1_sync.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+
+G1_TARGET_BLOCK=132446 # This is a fixed block# which determines to the sha1 hashes
+G1_IINDEX_CS=26393b64cdb9abb8e4012d6914f475635cba4c60
+G1_MINDEX_CS=7c5f07c7705647365b8965fcfc5a084c2f82a388
+G1_CINDEX_CS=3803c1ed8d3dd8f31558666d8dfd30272a6d0b74
+G1_SINDEX_CS=551bdba1855d5c49cd503fcb8ad787b2a24c2c42
+
+.gitlab/test/check_indexes.sh /tmp/duniter_ci_dump/ g1 ${G1_TARGET_BLOCK} ${G1_IINDEX_CS} ${G1_MINDEX_CS} ${G1_CINDEX_CS} ${G1_SINDEX_CS}
diff --git a/.gitlab/test/check_gt_sync.sh b/.gitlab/test/check_gt_sync.sh
new file mode 100755
index 0000000000000000000000000000000000000000..b2c187f8d7839b40c7305fb85af65b7a8520f30c
--- /dev/null
+++ b/.gitlab/test/check_gt_sync.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+
+GT_TARGET_BLOCK=210000 # This is a fixed block# which determines to the sha1 hashes
+GT_IINDEX_CS=dfd2dfc3d4d0ced4c101badb4d4a1ab85de8cbde
+GT_MINDEX_CS=9d8f665f5fcf1f21082278c4787bb3df085ff109
+GT_CINDEX_CS=b141361fb40f4c13f03f4640151c7674e190a4dd
+GT_SINDEX_CS=7c6801027e39b9fea9be973d8773ac77d2c9a1f9
+
+.gitlab/test/check_indexes.sh /tmp/duniter_ci_dump/ gt ${GT_TARGET_BLOCK} ${GT_IINDEX_CS} ${GT_MINDEX_CS} ${GT_CINDEX_CS} ${GT_SINDEX_CS}
diff --git a/.gitlab/test/check_indexes.sh b/.gitlab/test/check_indexes.sh
new file mode 100755
index 0000000000000000000000000000000000000000..b4b103ea7a88cc61a2dfc56a7f79344bdca8f536
--- /dev/null
+++ b/.gitlab/test/check_indexes.sh
@@ -0,0 +1,61 @@
+#!/usr/bin/env bash
+
+ORIGIN_DIR=`pwd`
+mkdir -p $1
+DUMP_DIR=`cd $1 && pwd`
+CURRENCY=$2
+ARCHIVES="$DUMP_DIR/archives_$CURRENCY"
+DB_TEST="gitlab_ci_sync_test_$CURRENCY"
+G1_TARGET_BLOCK=$3 # This is a fixed block# which determines to the sha1 hashes
+G1_IINDEX_CS=$4
+G1_MINDEX_CS=$5
+G1_CINDEX_CS=$6
+G1_SINDEX_CS=$7
+
+checksum_test() {
+  local table=$1
+  local correct_hash=$2
+  local db=$3
+  echo "Checking $table's checksum..."
+  bin/duniter --mdb ${db} dump table "$table" > "$DUMP_DIR/$table"
+  result_hash=`sha1sum "$DUMP_DIR/$table" | grep -Po ".* " | grep -Po "[a-f0-9]+"`
+#  rm -f "$DUMP_DIR/$table"
+  if [ "$result_hash" == "$correct_hash" ]; then
+    echo "OK";
+  else
+    echo "Error! Wrong hash detected. ($result_hash != $correct_hash)"
+    exit 1
+  fi
+}
+
+sync_data() {
+  local db=$1
+  local target=$2
+  local target_block=$3
+  local reset_data="bin/duniter --mdb ${db} reset all"
+  local sync="bin/duniter --mdb ${db} sync ${target} --nointeractive ${target_block}"
+  echo "$reset_data"
+  ${reset_data}
+  echo "$sync"
+  ${sync}
+}
+
+if [ -d ${ARCHIVES} ]; then
+  echo "Updating archives..."
+  cd ${ARCHIVES}
+  git checkout master
+  git pull origin master
+else
+  echo "Cloning archives..."
+  git clone https://git.duniter.org/c-geek/blockchain-archives.git ${ARCHIVES}
+fi
+
+echo "Positionnement dans $ORIGIN_DIR"
+
+cd ${ORIGIN_DIR}
+
+sync_data ${DB_TEST} "$ARCHIVES/$CURRENCY" ${G1_TARGET_BLOCK}
+checksum_test i_index ${G1_IINDEX_CS} ${DB_TEST}
+checksum_test m_index ${G1_MINDEX_CS} ${DB_TEST}
+checksum_test c_index ${G1_CINDEX_CS} ${DB_TEST}
+checksum_test s_index ${G1_SINDEX_CS} ${DB_TEST}
diff --git a/README.md b/README.md
index 55670b0f10b18a575759d00146d5cb28d3be16e8..af456b1f7c3231554d6cdd9a3633707ab0e6020a 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-![Duniter logo](https://raw.github.com/duniter/duniter/master/images/250×250.png)
+![Duniter logo](https://git.duniter.org/nodes/typescript/duniter/raw/dev/images/250%C3%97250.png)
 
 # Duniter [![Build Status](https://api.travis-ci.org/duniter/duniter.png)](https://travis-ci.org/duniter/duniter) [![Coverage Status](https://coveralls.io/repos/github/duniter/duniter/badge.svg?branch=master)](https://coveralls.io/github/duniter/duniter?branch=master) [![Dependencies](https://david-dm.org/duniter/duniter.svg)](https://david-dm.org/duniter/duniter)
 
@@ -6,7 +6,7 @@ Duniter (previously uCoin) is a libre software allowing to create a new kind of
 
 Inspired by [Bitcoin](https://github.com/bitcoin/bitcoin) and [OpenUDC](https://github.com/Open-UDC/open-udc) projects.
 
-<p align="center"><img src="https://github.com/duniter/duniter/blob/master/images/duniter_admin_g1.png" /></p>
+<p align="center"><img src="https://git.duniter.org/nodes/typescript/duniter/raw/dev/images/duniter_admin_g1.png" /></p>
 
 ## Development state
 
diff --git a/app/ProcessCpuProfiler.ts b/app/ProcessCpuProfiler.ts
index 163f784307dba1c7a37a2527abc030dfd0c34c44..42b9999269e7b6ca6c00098b213dfdcb9b1b6fc9 100644
--- a/app/ProcessCpuProfiler.ts
+++ b/app/ProcessCpuProfiler.ts
@@ -14,11 +14,20 @@
 const SAMPLING_PERIOD = 150 // milliseconds
 const MAX_SAMPLES_DISTANCE = 20 * 1000000 // seconds
 
-function getMicrosecondsTime() {
+export function getMicrosecondsTime() {
   const [ seconds, nanoseconds ] = process.hrtime()
   return seconds * 1000000 + nanoseconds / 1000
 }
 
+export function getNanosecondsTime() {
+  const [ seconds, nanoseconds ] = process.hrtime()
+  return seconds * 1000000 + nanoseconds
+}
+
+export function getDurationInMicroSeconds(before:number) {
+  return parseInt(String(getMicrosecondsTime() - before))
+}
+
 interface CpuUsage {
   user: number
   system:number
diff --git a/app/cli.ts b/app/cli.ts
index 0060f3718be8a6d7f45749efa228847ec27076e0..33472bb2ac0cfea4e2b8eb955bb2fddb82b02a97 100644
--- a/app/cli.ts
+++ b/app/cli.ts
@@ -74,6 +74,7 @@ export const ExecuteCommand = () => {
         .option('--nohttplogs', 'Disable HTTP logs')
         .option('--isolate', 'Avoid the node to send peering or status informations to the network')
         .option('--forksize <size>', 'Maximum size of fork window', parseInt)
+        .option('--notrim', 'Disable the INDEX trimming.')
         .option('--memory', 'Memory mode')
       ;
 
diff --git a/app/lib/blockchain/BasicBlockchain.ts b/app/lib/blockchain/BasicBlockchain.ts
deleted file mode 100644
index 40cd0d668fb5fd2c1d71c06539038ec22ff4cea0..0000000000000000000000000000000000000000
--- a/app/lib/blockchain/BasicBlockchain.ts
+++ /dev/null
@@ -1,71 +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"
-import {BlockchainOperator} from "./interfaces/BlockchainOperator"
-
-export class BasicBlockchain {
-
-  constructor(private op:BlockchainOperator) {
-  }
-
-  /**
-   * Adds a block at the end of the blockchain.
-   */
-  pushBlock(b:any) {
-    return this.op.store(b)
-  }
-
-  /**
-   * Get the block identified by `number`
-   * @param number block ID.
-   * @returns {*} Promise<Block>
-   */
-  getBlock(number:number) {
-    return this.op.read(number)
-  }
-
-  /**
-   * Get the nth block from the top of the blockchain.
-   * @param index Index from top. Defaults to `0`. E.g. `0` = HEAD, `1` = HEAD~1, etc.
-   * @returns {*} Promise<Block>
-   */
-  head(index = 0) {
-    return this.op.head(index)
-  }
-
-  /**
-   * Blockchain size, in number of blocks.
-   * @returns {*} Size.
-   */
-  height() {
-    return this.op.height()
-  }
-
-  /**
-   * Get the (n+1)th blocks top blocks of the blockchain, ordered by number ascending.
-   * @param n Quantity from top. E.g. `1` = [HEAD], `3` = [HEAD, HEAD~1, HEAD~2], etc.
-   * @returns {*} Promise<Block>
-   */
-  headRange(n:number) {
-    return this.op.headRange(n)
-  }
-
-  /**
-   * Pops the blockchain HEAD.
-   * @returns {*} Promise<Block> The reverted block.
-   */
-  revertHead() {
-    return this.op.revertHead()
-  }
-}
diff --git a/app/lib/blockchain/DuniterBlockchain.ts b/app/lib/blockchain/DuniterBlockchain.ts
index 48a3215e80e231c5e07bd6ba20190101edf69025..074af4420bf5099d69dc27d99576f1f58ce6a94e 100644
--- a/app/lib/blockchain/DuniterBlockchain.ts
+++ b/app/lib/blockchain/DuniterBlockchain.ts
@@ -11,9 +11,16 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-import {MiscIndexedBlockchain} from "./MiscIndexedBlockchain"
-import {IindexEntry, IndexEntry, Indexer, MindexEntry, SindexEntry} from "../indexer"
-import {BlockchainOperator} from "./interfaces/BlockchainOperator"
+import {
+  BasedAmount,
+  FullIindexEntry,
+  IindexEntry,
+  IndexEntry,
+  Indexer,
+  MindexEntry,
+  SimpleTxEntryForWallet,
+  SimpleUdEntryForWallet
+} from "../indexer"
 import {ConfDTO} from "../dto/ConfDTO"
 import {BlockDTO} from "../dto/BlockDTO"
 import {DBHead} from "../db/DBHead"
@@ -25,16 +32,15 @@ import {CertificationDTO} from "../dto/CertificationDTO"
 import {MembershipDTO} from "../dto/MembershipDTO"
 import {TransactionDTO} from "../dto/TransactionDTO"
 import {CommonConstants} from "../common-libs/constants"
+import {FileDAL} from "../dal/fileDAL"
+import {NewLogger} from "../logger"
+import {DBTx} from "../db/DBTx"
+import {Underscore} from "../common-libs/underscore"
+import {OtherConstants} from "../other_constants"
 
-const _ = require('underscore')
+export class DuniterBlockchain {
 
-export class DuniterBlockchain extends MiscIndexedBlockchain {
-
-  constructor(blockchainStorage:BlockchainOperator, dal:any) {
-    super(blockchainStorage, dal.mindexDAL, dal.iindexDAL, dal.sindexDAL, dal.cindexDAL)
-  }
-
-  static async checkBlock(block:BlockDTO, withPoWAndSignature:boolean, conf: ConfDTO, dal:any) {
+  static async checkBlock(block:BlockDTO, withPoWAndSignature:boolean, conf: ConfDTO, dal:FileDAL) {
     const index = Indexer.localIndex(block, conf)
     if (withPoWAndSignature) {
       await CHECK.ASYNC.ALL_LOCAL(block, conf, index)
@@ -55,7 +61,9 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     // BR_G98
     if (Indexer.ruleCurrency(block, HEAD) === false) throw Error('ruleCurrency');
     // BR_G51
-    if (Indexer.ruleNumber(block, HEAD) === false) throw Error('ruleNumber');
+    if (Indexer.ruleNumber(block, HEAD) === false) {
+      throw Error('ruleNumber')
+    }
     // BR_G52
     if (Indexer.rulePreviousHash(block, HEAD) === false) throw Error('rulePreviousHash');
     // BR_G53
@@ -103,7 +111,9 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     // BR_G70
     if (Indexer.ruleCertificationToLeaver(cindex) === false) throw Error('ruleCertificationToLeaver');
     // BR_G71
-    if (Indexer.ruleCertificationReplay(cindex) === false) throw Error('ruleCertificationReplay');
+    if (Indexer.ruleCertificationReplay(cindex) === false) {
+      throw Error('ruleCertificationReplay')
+    }
     // BR_G72
     if (Indexer.ruleCertificationSignature(cindex) === false) throw Error('ruleCertificationSignature');
     // BR_G73
@@ -123,7 +133,9 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     // BR_G80
     if (Indexer.ruleMembershipLeaverIsMember(mindex) === false) throw Error('ruleMembershipLeaverIsMember');
     // BR_G81
-    if (Indexer.ruleMembershipActiveIsMember(mindex) === false) throw Error('ruleMembershipActiveIsMember');
+    if (Indexer.ruleMembershipActiveIsMember(mindex) === false) {
+      throw Error('ruleMembershipActiveIsMember')
+    }
     // BR_G82
     if (Indexer.ruleMembershipRevokedIsMember(mindex) === false) throw Error('ruleMembershipRevokedIsMember');
     // BR_G83
@@ -133,7 +145,9 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     // BR_G85
     if (Indexer.ruleMembershipExcludedIsMember(iindex) === false) throw Error('ruleMembershipExcludedIsMember');
     // BR_G86
-    if ((await Indexer.ruleToBeKickedArePresent(iindex, dal)) === false) throw Error('ruleToBeKickedArePresent');
+    if ((await Indexer.ruleToBeKickedArePresent(iindex, dal)) === false) {
+      throw Error('ruleToBeKickedArePresent')
+    }
     // BR_G103
     if (Indexer.ruleTxWritability(sindex) === false) throw Error('ruleTxWritability');
     // BR_G87
@@ -174,7 +188,7 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     return { index, HEAD }
   }
 
-  async pushTheBlock(obj: BlockDTO, index: IndexEntry[], HEAD: DBHead | null, conf: ConfDTO, dal: any, logger: any, trim = true) {
+  static async pushTheBlock(obj:BlockDTO, index:IndexEntry[], HEAD:DBHead | null, conf:ConfDTO, dal:FileDAL, logger:any, trim = true) {
     const start = Date.now();
     const block = BlockDTO.fromJSONObject(obj)
     try {
@@ -189,6 +203,13 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
       }
 
       logger.info('Block #' + block.number + ' added to the blockchain in %s ms', (Date.now() - start));
+
+      // Periodically, we trim the blockchain
+      if (block.number % CommonConstants.BLOCKS_COLLECT_THRESHOLD === 0) {
+        // Database trimming
+        await dal.loki.flushAndTrimData()
+      }
+
       return BlockDTO.fromJSONObject(added)
     }
     catch(err) {
@@ -201,7 +222,7 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     // await supra.recordIndex(index)
   }
 
-  async saveBlockData(current: DBBlock, block: BlockDTO, conf: ConfDTO, dal: any, logger: any, index: IndexEntry[], HEAD: DBHead | null, trim: boolean) {
+  static async saveBlockData(current:DBBlock|null, block:BlockDTO, conf:ConfDTO, dal:FileDAL, logger:any, index:IndexEntry[], HEAD:DBHead | null, trim: boolean) {
     if (block.number == 0) {
       await this.saveParametersForRoot(block, conf, dal);
     }
@@ -212,17 +233,14 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     await this.createNewcomers(indexes.iindex, dal, logger);
 
     // Save indexes
-    await dal.bindexDAL.saveEntity(indexes.HEAD);
-    await dal.mindexDAL.insertBatch(indexes.mindex);
-    await dal.iindexDAL.insertBatch(indexes.iindex);
-    await dal.sindexDAL.insertBatch(indexes.sindex);
-    await dal.cindexDAL.insertBatch(indexes.cindex);
+    await dal.bindexDAL.insert(indexes.HEAD);
+    await dal.flushIndexes(indexes)
 
     // Create/Update nodes in wotb
     await this.updateMembers(block, dal);
 
     // Update the wallets' blances
-    await this.updateWallets(indexes.sindex, dal)
+    await this.updateWallets(indexes.sindex, indexes.dividends, dal)
 
     if (trim) {
       const TAIL = await dal.bindexDAL.tail();
@@ -237,6 +255,7 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
       const MAX_BINDEX_SIZE = conf.forksize + bindexSize
       const currentSize = indexes.HEAD.number - TAIL.number + 1
       if (currentSize > MAX_BINDEX_SIZE) {
+        await dal.archiveBlocks()
         await dal.trimIndexes(indexes.HEAD.number - MAX_BINDEX_SIZE);
       }
     }
@@ -248,7 +267,7 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     await dal.updateWotbLinks(indexes.cindex);
 
     // Create/Update certifications
-    await this.removeCertificationsFromSandbox(block, dal);
+    await DuniterBlockchain.removeCertificationsFromSandbox(block, dal);
     // Create/Update memberships
     await this.removeMembershipsFromSandbox(block, dal);
     // Compute to be revoked members
@@ -260,10 +279,12 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     // Saves the block (DAL)
     await dal.saveBlock(dbb);
 
+    await dal.loki.commitData()
+
     return dbb
   }
 
-  async saveParametersForRoot(block:BlockDTO, conf:ConfDTO, dal:any) {
+  static async saveParametersForRoot(block:BlockDTO, conf:ConfDTO, dal:FileDAL) {
     if (block.parameters) {
       const bconf = BlockDTO.getConf(block)
       conf.c = bconf.c;
@@ -293,9 +314,10 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     }
   }
 
-  async createNewcomers(iindex:IindexEntry[], dal:any, logger:any) {
-    for (const entry of iindex) {
-      if (entry.op == CommonConstants.IDX_CREATE) {
+  static async createNewcomers(iindex:IindexEntry[], dal:FileDAL, logger:any) {
+    for (const i of iindex) {
+      if (i.op == CommonConstants.IDX_CREATE) {
+        const entry = i as FullIindexEntry
         // Reserves a wotb ID
         entry.wotb_id = dal.wotb.addNode();
         logger.trace('%s was affected wotb_id %s', entry.uid, entry.wotb_id);
@@ -306,58 +328,64 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     }
   }
 
-  async updateMembers(block:BlockDTO, dal:any) {
+  static async updateMembers(block:BlockDTO, dal:FileDAL) {
     // Joiners (come back)
     for (const inlineMS of block.joiners) {
       let ms = MembershipDTO.fromInline(inlineMS)
-      const idty = await dal.getWrittenIdtyByPubkey(ms.issuer);
+      const idty = await dal.getWrittenIdtyByPubkeyForWotbID(ms.issuer);
       dal.wotb.setEnabled(true, idty.wotb_id);
+      await dal.dividendDAL.setMember(true, ms.issuer)
     }
     // Revoked
     for (const inlineRevocation of block.revoked) {
       let revocation = RevocationDTO.fromInline(inlineRevocation)
-      await dal.revokeIdentity(revocation.pubkey, block.number);
+      await dal.revokeIdentity(revocation.pubkey)
     }
     // Excluded
     for (const excluded of block.excluded) {
-      const idty = await dal.getWrittenIdtyByPubkey(excluded);
+      const idty = await dal.getWrittenIdtyByPubkeyForWotbID(excluded);
       dal.wotb.setEnabled(false, idty.wotb_id);
+      await dal.dividendDAL.setMember(false, excluded)
     }
   }
 
-  async updateWallets(sindex:SindexEntry[], aDal:any, reverse = false) {
-    const differentConditions = _.uniq(sindex.map((entry) => entry.conditions))
+  static async updateWallets(sindex:SimpleTxEntryForWallet[], dividends:SimpleUdEntryForWallet[], aDal:any, reverse = false) {
+    const differentConditions = Underscore.uniq(sindex.map((entry) => entry.conditions).concat(dividends.map(d => d.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 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 udsOfKey: BasedAmount[] = dividends.filter(d => d.conditions === conditions).map(d => ({ amount: d.amount, base: d.base }))
+      const creates: BasedAmount[] = sindex.filter(entry => entry.conditions === conditions && entry.op === CommonConstants.IDX_CREATE)
+      const updates: BasedAmount[] = sindex.filter(entry => entry.conditions === conditions && entry.op === CommonConstants.IDX_UPDATE)
+      const positives = creates.concat(udsOfKey).reduce((sum, src) => sum + src.amount * Math.pow(10, src.base), 0)
+      const negatives = updates.reduce((sum, src) => sum + src.amount * Math.pow(10, src.base), 0)
       const wallet = await aDal.getWallet(conditions)
       let variation = positives - negatives
       if (reverse) {
         // To do the opposite operations, for a reverted block
         variation *= -1
       }
+      if (OtherConstants.TRACE_BALANCES) {
+        NewLogger().trace('Balance of %s: %s (%s %s %s)', wallet.conditions, wallet.balance + variation, wallet.balance, variation < 0 ? '-' : '+', Math.abs(variation))
+      }
       wallet.balance += variation
       await aDal.saveWallet(wallet)
     }
   }
 
-  async revertBlock(number:number, hash:string, dal:any) {
+  static async revertBlock(number:number, hash:string, dal:FileDAL, block?: DBBlock) {
 
     const blockstamp = [number, hash].join('-');
 
     // Revert links
     const writtenOn = await dal.cindexDAL.getWrittenOn(blockstamp);
     for (const entry of writtenOn) {
-      const from = await dal.getWrittenIdtyByPubkey(entry.issuer);
-      const to = await dal.getWrittenIdtyByPubkey(entry.receiver);
+      const from = await dal.getWrittenIdtyByPubkeyForWotbID(entry.issuer);
+      const to = await dal.getWrittenIdtyByPubkeyForWotbID(entry.receiver);
       if (entry.op == CommonConstants.IDX_CREATE) {
         // We remove the created link
-        dal.wotb.removeLink(from.wotb_id, to.wotb_id, true);
+        dal.wotb.removeLink(from.wotb_id, to.wotb_id);
       } else {
         // We add the removed link
-        dal.wotb.addLink(from.wotb_id, to.wotb_id, true);
+        dal.wotb.addLink(from.wotb_id, to.wotb_id);
       }
     }
 
@@ -366,37 +394,41 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
 
     // Get the money movements to revert in the balance
     const REVERSE_BALANCE = true
-    const sindexOfBlock = await dal.sindexDAL.getWrittenOn(blockstamp)
+    const sindexOfBlock = await dal.sindexDAL.getWrittenOnTxs(blockstamp)
 
-    await dal.bindexDAL.removeBlock(number);
+    await dal.bindexDAL.removeBlock(blockstamp);
     await dal.mindexDAL.removeBlock(blockstamp);
     await dal.iindexDAL.removeBlock(blockstamp);
     await dal.cindexDAL.removeBlock(blockstamp);
     await dal.sindexDAL.removeBlock(blockstamp);
+    const { createdUDsDestroyedByRevert, consumedUDsRecoveredByRevert } = await dal.dividendDAL.revertUDs(number)
 
     // Then: normal updates
-    const block = await dal.getBlockByBlockstampOrNull(blockstamp);
-    const previousBlock = await dal.getBlock(number - 1);
+    const previousBlock = await dal.getFullBlockOf(number - 1)
     // Set the block as SIDE block (equivalent to removal from main branch)
     await dal.blockDAL.setSideBlock(number, previousBlock);
 
+    // Update the dividends in our wallet
+    await this.updateWallets([], createdUDsDestroyedByRevert, dal, REVERSE_BALANCE)
+    await this.updateWallets([], consumedUDsRecoveredByRevert, dal)
     // Revert the balances variations for this block
-    await this.updateWallets(sindexOfBlock, dal, REVERSE_BALANCE)
+    await this.updateWallets(sindexOfBlock, [], dal, REVERSE_BALANCE)
 
     // Restore block's transaction as incoming transactions
-    await this.undoDeleteTransactions(block, dal)
-
-    return block
+    if (block) {
+      await this.undoDeleteTransactions(block, dal)
+    }
   }
 
-  async undoMembersUpdate(blockstamp:string, dal:any) {
+  static async undoMembersUpdate(blockstamp:string, dal:FileDAL) {
     const joiners = await dal.iindexDAL.getWrittenOn(blockstamp);
     for (const entry of joiners) {
       // Undo 'join' which can be either newcomers or comebackers
       // => equivalent to i_index.member = true AND i_index.op = 'UPDATE'
       if (entry.member === true && entry.op === CommonConstants.IDX_UPDATE) {
-        const idty = await dal.getWrittenIdtyByPubkey(entry.pub);
+        const idty = await dal.getWrittenIdtyByPubkeyForWotbID(entry.pub);
         dal.wotb.setEnabled(false, idty.wotb_id);
+        await dal.dividendDAL.setMember(false, entry.pub)
       }
     }
     const newcomers = await dal.iindexDAL.getWrittenOn(blockstamp);
@@ -405,7 +437,9 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
       // => equivalent to i_index.op = 'CREATE'
       if (entry.op === CommonConstants.IDX_CREATE) {
         // Does not matter which one it really was, we pop the last X identities
+        NewLogger().trace('removeNode')
         dal.wotb.removeNode();
+        await dal.dividendDAL.deleteMember(entry.pub)
       }
     }
     const excluded = await dal.iindexDAL.getWrittenOn(blockstamp);
@@ -413,17 +447,18 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
       // Undo excluded (make them become members again in wotb)
       // => equivalent to m_index.member = false
       if (entry.member === false && entry.op === CommonConstants.IDX_UPDATE) {
-        const idty = await dal.getWrittenIdtyByPubkey(entry.pub);
+        const idty = await dal.getWrittenIdtyByPubkeyForWotbID(entry.pub);
         dal.wotb.setEnabled(true, idty.wotb_id);
+        await dal.dividendDAL.setMember(true, entry.pub)
       }
     }
   }
 
-  async undoDeleteTransactions(block:BlockDTO, dal:any) {
+  static async undoDeleteTransactions(block:DBBlock, dal:FileDAL) {
     for (const obj of block.transactions) {
       obj.currency = block.currency;
       let tx = TransactionDTO.fromJSONObject(obj)
-      await dal.saveTransaction(tx);
+      await dal.saveTransaction(DBTx.fromTransactionDTO(tx))
     }
   }
 
@@ -433,10 +468,10 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
    * @param block Block in which are contained the certifications to remove from sandbox.
    * @param dal The DAL
    */
-  async removeCertificationsFromSandbox(block:BlockDTO, dal:any) {
+  static async removeCertificationsFromSandbox(block:BlockDTO, dal:FileDAL) {
     for (let inlineCert of block.certifications) {
       let cert = CertificationDTO.fromInline(inlineCert)
-      let idty = await dal.getWritten(cert.to);
+      let idty = await dal.getWrittenIdtyByPubkeyForHashing(cert.to);
       await dal.deleteCert({
         from: cert.from,
         target: IdentityDTO.getTargetHash(idty),
@@ -451,7 +486,7 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
    * @param block Block in which are contained the certifications to remove from sandbox.
    * @param dal The DAL
    */
-  async removeMembershipsFromSandbox(block:BlockDTO, dal:any) {
+  static async removeMembershipsFromSandbox(block:BlockDTO, dal:FileDAL) {
     const mss = block.joiners.concat(block.actives).concat(block.leavers);
     for (const inlineMS of mss) {
       let ms = MembershipDTO.fromInline(inlineMS)
@@ -462,14 +497,14 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     }
   }
 
-  async computeToBeRevoked(mindex:MindexEntry[], dal:any) {
-    const revocations = _.filter(mindex, (entry:MindexEntry) => entry.revoked_on);
+  static async computeToBeRevoked(mindex:MindexEntry[], dal:FileDAL) {
+    const revocations = Underscore.filter(mindex, (entry:MindexEntry) => !!(entry.revoked_on))
     for (const revoked of revocations) {
-      await dal.setRevoked(revoked.pub, true);
+      await dal.setRevoked(revoked.pub)
     }
   }
 
-  async deleteTransactions(block:BlockDTO, dal:any) {
+  static async deleteTransactions(block:BlockDTO, dal:FileDAL) {
     for (const obj of block.transactions) {
       obj.currency = block.currency;
       const tx = TransactionDTO.fromJSONObject(obj)
@@ -478,7 +513,7 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     }
   }
 
-  updateBlocksComputedVars(
+  static updateBlocksComputedVars(
     current:{ unitbase:number, monetaryMass:number }|null,
     block:{ number:number, unitbase:number, dividend:number|null, membersCount:number, monetaryMass:number }): void {
     // Unit Base
@@ -499,7 +534,7 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     }
   }
 
-  static pushStatsForBlocks(blocks:BlockDTO[], dal:any) {
+  static pushStatsForBlocks(blocks:BlockDTO[], dal:FileDAL) {
     const stats: { [k:string]: { blocks: number[], lastParsedBlock:number }} = {};
     // Stats
     for (const block of blocks) {
@@ -530,7 +565,7 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     return dal.pushStats(stats);
   }
 
-  async pushSideBlock(obj:BlockDTO, dal:any, logger:any) {
+  static async pushSideBlock(obj:BlockDTO, dal:FileDAL, logger:any) {
     const start = Date.now();
     const block = DBBlock.fromBlockDTO(BlockDTO.fromJSONObject(obj))
     block.fork = true;
@@ -544,11 +579,4 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
       throw err;
     }
   }
-
-  async revertHead() {
-    const indexRevert = super.indexRevert
-    const headf = super.head
-    const head = await headf()
-    await indexRevert(head.number)
-  }
 }
diff --git a/app/lib/blockchain/IndexedBlockchain.ts b/app/lib/blockchain/IndexedBlockchain.ts
deleted file mode 100644
index dd81222d526e201922e47a47cdef90f666c212ba..0000000000000000000000000000000000000000
--- a/app/lib/blockchain/IndexedBlockchain.ts
+++ /dev/null
@@ -1,139 +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"
-import {BasicBlockchain} from "./BasicBlockchain"
-import {IndexOperator} from "./interfaces/IndexOperator"
-import {BlockchainOperator} from "./interfaces/BlockchainOperator"
-
-const _ = require('underscore')
-
-export class IndexedBlockchain extends BasicBlockchain {
-
-  private initIndexer: Promise<void>
-
-  constructor(bcOperations: BlockchainOperator, private indexOperations: IndexOperator, private numberField: string, private pkFields: any) {
-    super(bcOperations)
-    this.initIndexer = indexOperations.initIndexer(pkFields)
-  }
-
-  async recordIndex(index: { [index: string]: any }) {
-    // Wait indexer init
-    await this.initIndexer
-
-    return this.indexOperations.recordIndex(index)
-  }
-
-  async indexTrim(maxNumber:number) {
-
-    // Wait indexer init
-    await this.initIndexer
-
-    const subIndexes = await this.indexOperations.getSubIndexes()
-    // Trim the subIndexes
-    const records: { [index: string]: any } = {}
-    for (const subIndex of subIndexes) {
-      records[subIndex] = []
-      const pks = typeof this.pkFields[subIndex].pk !== 'string' && this.pkFields[subIndex].pk.length ? Array.from(this.pkFields[subIndex].pk) : [this.pkFields[subIndex].pk]
-      const rm = this.pkFields[subIndex].remove
-      let potentialRecords = await this.indexOperations.findTrimable(subIndex, this.numberField, maxNumber)
-      potentialRecords = reduceBy(potentialRecords, pks)
-      for (const potential of potentialRecords) {
-        const subCriteriasRowsToDelete = criteriasFromPks(pks, potential)
-        subCriteriasRowsToDelete[this.numberField] = { $lt: maxNumber }
-        const rowsToReduce = await this.indexOperations.findWhere(subIndex, subCriteriasRowsToDelete)
-        // No reduction if 1 line to delete
-        if (rowsToReduce.length > 1) {
-          const reduced = reduce(rowsToReduce)
-          const subCriteriasRowsToKeep = criteriasFromPks(pks, potential)
-          subCriteriasRowsToKeep[this.numberField] = { $gte: maxNumber }
-          const toKeep = await this.indexOperations.findWhere(subIndex, subCriteriasRowsToKeep)
-          const subCriteriasAllRowsOfObject = criteriasFromPks(pks, potential)
-          await this.indexOperations.removeWhere(subIndex, subCriteriasAllRowsOfObject)
-          // Add the reduced row + rows to keep
-          if (!rm || !reduced[rm]) {
-            records[subIndex] = records[subIndex].concat([reduced]).concat(toKeep)
-          }
-        }
-      }
-    }
-    await this.recordIndex(records)
-    return Promise.resolve()
-  }
-
-  async indexCount(indexName: string, criterias: { [index: string]: any }) {
-
-    // Wait indexer init
-    await this.initIndexer
-
-    const records = await this.indexOperations.findWhere(indexName, criterias)
-    return records.length
-  }
-
-  async indexReduce(indexName: string, criterias: { [index: string]: any }) {
-
-    // Wait indexer init
-    await this.initIndexer
-
-    const records = await this.indexOperations.findWhere(indexName, criterias)
-    return reduce(records)
-  }
-
-  async indexReduceGroupBy(indexName: string, criterias: { [index: string]: any }, properties: string[]) {
-
-    // Wait indexer init
-    await this.initIndexer
-
-    const records = await this.indexOperations.findWhere(indexName, criterias)
-    return reduceBy(records, properties)
-  }
-
-  async indexRevert(blockNumber:number) {
-    const subIndexes = await this.indexOperations.getSubIndexes()
-    for (const subIndex of subIndexes) {
-      const removeCriterias: { [index: string]: any } = {}
-      removeCriterias[this.numberField] = blockNumber
-      await this.indexOperations.removeWhere(subIndex, removeCriterias)
-    }
-  }
-}
-
-function reduce(records: any[]) {
-  return records.reduce((obj, record) => {
-    const keys = Object.keys(record);
-    for (const k of keys) {
-      if (record[k] !== undefined && record[k] !== null) {
-        obj[k] = record[k];
-      }
-    }
-    return obj;
-  }, {});
-}
-
-function reduceBy(reducables: any[], properties: string[]) {
-  const reduced = reducables.reduce((map, entry) => {
-    const id = properties.map((prop) => entry[prop]).join('-');
-    map[id] = map[id] || [];
-    map[id].push(entry);
-    return map;
-  }, {});
-  return _.values(reduced).map((rows: any[]) => reduce(rows))
-}
-
-function criteriasFromPks(pks: string[], values: any): { [index: string]: any } {
-  const criterias: { [index: string]: any } = {}
-  for (const key of pks) {
-    criterias[key] = values[key]
-  }
-  return criterias
-}
diff --git a/app/lib/blockchain/MiscIndexedBlockchain.ts b/app/lib/blockchain/MiscIndexedBlockchain.ts
deleted file mode 100644
index 5f881ba0d0dad2f6dea1b27a734c5c4949e02cc3..0000000000000000000000000000000000000000
--- a/app/lib/blockchain/MiscIndexedBlockchain.ts
+++ /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"
-import {IndexedBlockchain} from "./IndexedBlockchain"
-import {SQLIndex} from "./SqlIndex"
-import {BlockchainOperator} from "./interfaces/BlockchainOperator"
-
-export class MiscIndexedBlockchain extends IndexedBlockchain {
-
-  constructor(blockchainStorage: BlockchainOperator, mindexDAL:any, iindexDAL:any, sindexDAL:any, cindexDAL:any) {
-    super(blockchainStorage, new SQLIndex(null, {
-      m_index: { handler: mindexDAL },
-      i_index: { handler: iindexDAL },
-      s_index: {
-        handler: sindexDAL,
-        findTrimable: (maxNumber:number) => sindexDAL.query('SELECT * FROM s_index WHERE consumed AND writtenOn < ?', [maxNumber])
-      },
-      c_index: {
-        handler: cindexDAL,
-        findTrimable: (maxNumber:number) => cindexDAL.query('SELECT * FROM c_index WHERE expired_on > 0 AND writtenOn < ?', [maxNumber])
-      }
-    }), 'writtenOn', {
-      m_index: {
-        pk: ['pub']
-      },
-      i_index: {
-        pk: ['pub']
-      },
-      s_index: {
-        pk: ['identifier', 'pos'],
-        remove: 'consumed'
-      },
-      c_index: {
-        pk: ['issuer', 'receiver', 'created_on'],
-        remove: 'expired_on'
-      }
-    })
-  }
-}
diff --git a/app/lib/blockchain/SqlBlockchain.ts b/app/lib/blockchain/SqlBlockchain.ts
deleted file mode 100644
index 84d2f5b97fac12abe67e335d692e1a8845ff58c0..0000000000000000000000000000000000000000
--- a/app/lib/blockchain/SqlBlockchain.ts
+++ /dev/null
@@ -1,76 +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"
-import {BlockchainOperator} from "./interfaces/BlockchainOperator"
-
-const indexer = require('../../lib/indexer').Indexer
-
-export class SQLBlockchain implements BlockchainOperator {
-
-  constructor(private dal: { bindexDAL:any }) {
-  }
-
-  store(b: any): Promise<any> {
-    return this.dal.bindexDAL.saveEntity(b)
-  }
-
-  read(i: number): Promise<any> {
-    return this.dal.bindexDAL.sqlFindOne({ number: i })
-  }
-
-  async head(n = 0): Promise<any> {
-    /**
-     * IMPORTANT NOTICE
-     * ----------------
-     *
-     * There is a difference between the protocol's HEAD (P_HEAD) and the database's HEAD (DB_HEAD). The relation is:
-     *
-     *     DB_HEAD~<i> = P_HEAD~<i+1>
-     *
-     * In this class methods, we expose DB_HEAD logic. But the data is stored/retrieved by DAL objects using P_HEAD logic.
-     *
-     * So if we want DB_HEAD~0 for example, we must ask P_HEAD~(0+1). The DAL object will then retrieve P_HEAD~1, which
-     * is the latest stored block in the blockchain.
-     *
-     * Note: the DAL object cannot retrieve P_HEAD~0, this value does not exist and refers to the potential incoming block.
-     *
-     * Why this behavior?
-     * ------------------
-     *
-     * Because the DAL was wrongly coded. It will be easy to fix this problem once indexer.js will only use **this class'
-     * methods**. Then, we will be able to replace (n + 1) by just (n), and replace also the complementary behavior in
-     * the DAL (BIndexDAL).
-     */
-    return this.dal.bindexDAL.head(n + 1)
-  }
-
-  async height(): Promise<number> {
-    const head = await this.dal.bindexDAL.head(1) // We do not use head(0). See the above notice.
-    if (head) {
-      return head.number + 1
-    } else {
-      return 0
-    }
-  }
-
-  headRange(m: number): Promise<any[]> {
-    return this.dal.bindexDAL.range(1, m) // We do not use range(0, m). See the above notice.
-  }
-
-  async revertHead(): Promise<any> {
-    const head = await this.dal.bindexDAL.head(1) // We do not use head(0). See the above notice.
-    await this.dal.bindexDAL.removeBlock(head.number)
-    return head
-  }
-}
diff --git a/app/lib/blockchain/SqlIndex.ts b/app/lib/blockchain/SqlIndex.ts
deleted file mode 100644
index 53cb379c94934e700abc4bab8097691533085db4..0000000000000000000000000000000000000000
--- a/app/lib/blockchain/SqlIndex.ts
+++ /dev/null
@@ -1,86 +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"
-import {IndexOperator} from "./interfaces/IndexOperator"
-import {AbstractIndex} from "../dal/sqliteDAL/AbstractIndex";
-
-const _ = require('underscore')
-
-export class SQLIndex implements IndexOperator {
-
-  private indexes: { [k:string]: any } = {}
-
-  constructor(private db:any, private definitions: any) {
-  }
-
-  async initIndexer(pkFields: any): Promise<void> {
-    const keys = _.keys(pkFields)
-    for (const k of keys) {
-      if (this.definitions[k].handler) {
-        // External table: managed by another object
-        this.indexes[k] = this.definitions[k].handler
-      } else {
-        // Internal table: managed here
-        const indexTable = new AbstractIndex<any>(this.db, k, [], this.definitions[k].fields, [], this.definitions[k].booleans)
-        this.indexes[k] = indexTable
-        indexTable.init = () => {
-          return indexTable.exec('BEGIN;' +
-            'CREATE TABLE IF NOT EXISTS ' + indexTable.table + ' (' +
-            this.definitions[k].sqlFields.join(',') +
-            ');' +
-            'COMMIT;')
-        }
-        await indexTable.init()
-      }
-    }
-  }
-
-  getSubIndexes(): Promise<string[]> {
-    return Promise.resolve(_.keys(this.indexes))
-  }
-
-  findTrimable(subIndex: string, numberField: string, maxNumber: number): Promise<any[]> {
-    if (this.definitions[subIndex].findTrimable) {
-      return this.definitions[subIndex].findTrimable(maxNumber)
-    } else {
-      const criterias:any = {}
-      criterias[numberField] = { $lt: maxNumber }
-      return this.indexes[subIndex].sqlFind(criterias)
-    }
-  }
-
-  removeWhere(subIndex: string, criterias: {}): Promise<void> {
-    if (!this.indexes[subIndex]) {
-      return Promise.resolve()
-    }
-    return this.indexes[subIndex].sqlRemoveWhere(criterias)
-  }
-
-  async recordIndex(index: any): Promise<void> {
-    const subIndexes = _.keys(index)
-    // Feed the this.indexes
-    for (const subIndex of subIndexes) {
-      await this.indexes[subIndex].insertBatch(index[subIndex])
-    }
-    return Promise.resolve()
-  }
-
-
-  findWhere(subIndex: string, criterias: {}): Promise<any[]> {
-    if (!this.indexes[subIndex]) {
-      return Promise.resolve([])
-    }
-    return this.indexes[subIndex].sqlFind(criterias)
-  }
-}
diff --git a/app/lib/blockchain/Switcher.ts b/app/lib/blockchain/Switcher.ts
index 4346fd1af0c8a1e5ef95f19f9b0994e35de0692f..083aae273a887e55cd40b75e9a8928b250b97048 100644
--- a/app/lib/blockchain/Switcher.ts
+++ b/app/lib/blockchain/Switcher.ts
@@ -12,6 +12,7 @@
 // GNU Affero General Public License for more details.
 
 import {BlockDTO} from "../dto/BlockDTO"
+
 export interface SwitchBlock {
 
   number:number
@@ -22,10 +23,10 @@ export interface SwitchBlock {
 
 export interface SwitcherDao<T extends SwitchBlock> {
 
-  getCurrent(): Promise<T>
+  getCurrent(): Promise<T|null>
   getPotentials(numberStart:number, timeStart:number, maxNumber:number): Promise<T[]>
   getBlockchainBlock(number:number, hash:string): Promise<T|null>
-  getSandboxBlock(number:number, hash:string): Promise<T|null>
+  getAbsoluteBlockInForkWindow(number:number, hash:string): Promise<T|null>
   revertTo(number:number): Promise<T[]>
   addBlock(block:T): Promise<T>
 }
@@ -73,7 +74,7 @@ export class Switcher<T extends SwitchBlock> {
    * Find all the suites' HEAD that we could potentially fork on, in the current fork window.
    * @param current
    */
-  async findPotentialSuitesHeads(current:T) {
+  async findPotentialSuitesHeads(current:{ number:number, medianTime:number }) {
     const numberStart = current.number - this.forkWindowSize
     const timeStart = current.medianTime - this.forkWindowSize * this.avgGenTime
     const suites = await this.findPotentialSuites(numberStart, timeStart)
@@ -125,7 +126,7 @@ export class Switcher<T extends SwitchBlock> {
             commonRootFound = true
           } else {
             // Have a look in sandboxes
-            previous = await this.dao.getSandboxBlock(previousNumber, previousHash)
+            previous = await this.dao.getAbsoluteBlockInForkWindow(previousNumber, previousHash)
             if (previous) {
               knownForkBlocks[BlockDTO.fromJSONObject(previous).blockstamp] = true
               const alreadyKnownInvalidBlock = this.invalidForks.indexOf([previous.number, previous.hash].join('-')) !== -1
diff --git a/app/lib/blockchain/interfaces/BlockchainOperator.ts b/app/lib/blockchain/interfaces/BlockchainOperator.ts
deleted file mode 100644
index f3f50177b91ea18f8598742f516bc76f601c4b55..0000000000000000000000000000000000000000
--- a/app/lib/blockchain/interfaces/BlockchainOperator.ts
+++ /dev/null
@@ -1,51 +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"
-
-export interface BlockchainOperator {
-
-  /**
-   * Pushes a new block at the top of the blockchain.
-   * @param b Block.
-   */
-  store(b:any):Promise<any>
-
-  /**
-   * Reads the block at index `i`.
-   * @param i Block number.
-   */
-  read(i:number):Promise<any>
-
-  /**
-   * Reads the block at index `n` from the top of the blockchain.
-   * @param n Reverse index.
-   */
-  head(n:number):Promise<any>
-
-  /**
-   * Gives the number of blocks in the blockchain.
-   */
-  height():Promise<number>
-
-  /**
-   * Reads the blocks from head(0) to head(m)
-   * @param m Quantity.
-   */
-  headRange(m:number):Promise<any[]>
-
-  /**
-   * Pops the top block.
-   */
-  revertHead():Promise<any>
-}
diff --git a/app/lib/common-libs/constants.ts b/app/lib/common-libs/constants.ts
old mode 100644
new mode 100755
index 54d3d879b74569eb1e04ee0c51ac8e8e0bc8abd2..3b16ff3e87429ced051393a61703a58f250746cb
--- a/app/lib/common-libs/constants.ts
+++ b/app/lib/common-libs/constants.ts
@@ -299,7 +299,16 @@ export const CommonConstants = {
     SPECIAL_BLOCK
   },
 
-  BLOCK_MAX_TX_CHAINING_DEPTH: 5
+  BLOCK_MAX_TX_CHAINING_DEPTH: 5,
+
+  CONST_BLOCKS_CHUNK: 250,
+  CHUNK_PREFIX: 'chunk_',
+  BLOCKS_IN_MEMORY_MAX: 288 * 60, // 60 days of blocks
+
+  MAX_AGE_OF_PEER_IN_BLOCKS: 200, // blocks
+  INITIAL_DOWNLOAD_SLOTS: 1, // 1 peer
+
+  BLOCKS_COLLECT_THRESHOLD: 30, // Number of blocks to wait before trimming the loki data
 }
 
 function exact (regexpContent:string) {
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/errors.ts b/app/lib/common-libs/errors.ts
new file mode 100755
index 0000000000000000000000000000000000000000..ffaa416c8ce74aeed8426d044402354fdc43f33f
--- /dev/null
+++ b/app/lib/common-libs/errors.ts
@@ -0,0 +1,19 @@
+
+export enum DataErrors {
+  TOO_OLD_PEER,
+  LOKI_DIVIDEND_GET_WRITTEN_ON_SHOULD_NOT_BE_USED,
+  LOKI_DIVIDEND_REMOVE_BLOCK_SHOULD_NOT_BE_USED,
+  NEGATIVE_BALANCE,
+  BLOCK_WASNT_COMMITTED,
+  CANNOT_ARCHIVE_CHUNK_WRONG_SIZE,
+  CORRUPTED_DATABASE,
+  BLOCKCHAIN_NOT_INITIALIZED_YET,
+  CANNOT_DETERMINATE_MEMBERSHIP_AGE,
+  CANNOT_DETERMINATE_IDENTITY_AGE,
+  CERT_BASED_ON_UNKNOWN_BLOCK,
+  NO_TRANSACTION_POSSIBLE_IF_NOT_CURRENT_BLOCK,
+  CANNOT_REAPPLY_NO_CURRENT_BLOCK,
+  CANNOT_REVERT_NO_CURRENT_BLOCK,
+  BLOCK_TO_REVERT_NOT_FOUND,
+  MEMBER_NOT_FOUND
+}
diff --git a/app/lib/common-libs/manual-promise.ts b/app/lib/common-libs/manual-promise.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ea7f4c436cd80bdc43c48da2aa3ec16f451f572e
--- /dev/null
+++ b/app/lib/common-libs/manual-promise.ts
@@ -0,0 +1,25 @@
+import {Querable} from "./querable"
+
+const querablePromise = require('querablep');
+
+export interface ManualPromise<T> extends Querable<T> {
+  resolve: (data: T) => void
+  reject: (error: Error) => void
+}
+
+/**
+ * Creates a new querable promise that can is manually triggered.
+ * @returns {ManualPromise<T>}
+ */
+export function newManualPromise<T>() {
+  let resolveCb: (data: T) => void = () => {}
+  let rejectCb: (error: Error) => void = () => {}
+  const p = new Promise((res, rej) => {
+    resolveCb = res
+    rejectCb = rej
+  })
+  const q: ManualPromise<T> = querablePromise(p)
+  q.resolve = resolveCb
+  q.reject = rejectCb
+  return q
+}
diff --git a/test/integration/tools/shutDownEngine.js b/app/lib/common-libs/moment.ts
similarity index 77%
rename from test/integration/tools/shutDownEngine.js
rename to app/lib/common-libs/moment.ts
index ade3f2350e7ec857dce49a590b49be61f8a0810f..ca05144233a3364fc44985f8cee8947870af7521 100644
--- a/test/integration/tools/shutDownEngine.js
+++ b/app/lib/common-libs/moment.ts
@@ -11,11 +11,6 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-const co = require('co')
+const _moment_ = require("moment")
 
-module.exports = (server) => co(function*() {
-  if (server._utProver) {
-    const farm = yield server._utProver.getWorker();
-    return farm.shutDownEngine();
-  }
-})
+export const moment = _moment_
\ No newline at end of file
diff --git a/app/lib/common-libs/programOptions.ts b/app/lib/common-libs/programOptions.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d26f63ea0958443113d37a40f89aebbd513b4e58
--- /dev/null
+++ b/app/lib/common-libs/programOptions.ts
@@ -0,0 +1,38 @@
+// 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.
+
+const opts = require('optimist').argv
+
+export interface ProgramOptions {
+  mdb?: string
+  home?: string
+  notrim?: boolean
+  nosbx?: boolean
+  nopeers?: boolean
+  syncTrace?: string
+  isSync: boolean
+  noSources: boolean
+  slow?: boolean
+}
+
+export const cliprogram: ProgramOptions = {
+  mdb: opts.mdb,
+  home: opts.home,
+  notrim: opts.notrim,
+  nosbx: opts.nosbx,
+  nopeers: opts.nopeers,
+  noSources: !!opts.nosources,
+  syncTrace: opts['sync-trace'],
+  isSync: opts._[0] === 'sync',
+  slow: opts.slow,
+}
diff --git a/app/lib/common-libs/querable.ts b/app/lib/common-libs/querable.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b5cba5da23170c599d46d7dadd138376b0d9f20f
--- /dev/null
+++ b/app/lib/common-libs/querable.ts
@@ -0,0 +1,14 @@
+const querablePromise = require('querablep');
+
+export interface Querable<T> extends Promise<T> {
+  isFulfilled(): boolean
+  isResolved(): boolean
+  isRejected(): boolean
+  startedOn: number
+}
+
+export function querablep<T>(p: Promise<T>): Querable<T> {
+  const qp = querablePromise(p)
+  qp.startedOn = Date.now()
+  return qp
+}
diff --git a/app/lib/common-libs/rawer.ts b/app/lib/common-libs/rawer.ts
index 568199c92a3a68b1db6c3666b8d0f2dd7ea2a576..9ed172071cad9d086bc01db5d13e3df19440d02b 100644
--- a/app/lib/common-libs/rawer.ts
+++ b/app/lib/common-libs/rawer.ts
@@ -31,7 +31,17 @@ export const getOfficialIdentity = (json:any, withSig = true) => {
   }
 }
 
-export const getOfficialCertification = (json:any) => {
+export const getOfficialCertification = (json:{
+  version?:number
+  currency:string
+  issuer:string
+  idty_issuer:string
+  idty_uid:string
+  idty_buid:string
+  idty_sig:string
+  buid:string
+  sig?:string
+}) => {
   let raw = getNormalHeader('Certification', json);
   raw += "IdtyIssuer: " + json.idty_issuer + '\n';
   raw += "IdtyUniqueID: " + json.idty_uid + '\n';
@@ -91,7 +101,11 @@ export const getTransaction = (json:any) => {
   return TransactionDTO.toRAW(json)
 }
 
-function getNormalHeader(doctype:string, json:any) {
+function getNormalHeader(doctype:string, json:{
+  version?:number
+  currency:string
+  issuer:string
+}) {
   let raw = "";
   raw += "Version: " + (json.version || DOCUMENTS_VERSION) + "\n";
   raw += "Type: " + doctype + "\n";
diff --git a/app/lib/common-libs/underscore.ts b/app/lib/common-libs/underscore.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2592220474e242b23f4e9af5b59609f132c6e8eb
--- /dev/null
+++ b/app/lib/common-libs/underscore.ts
@@ -0,0 +1,87 @@
+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 _underscore_.filter(elements, filterFunc)
+  },
+
+  where: <T>(elements:T[], props: { [k in keyof T]?: T[k] }): T[] => {
+    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 _underscore_.keys(map)
+  },
+
+  values: <T>(map:{ [k:string]: T }): T[] => {
+    return _underscore_.values(map)
+  },
+
+  pluck: <T, K extends keyof T>(elements:T[], k:K): T[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)
+  },
+
+  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/common-libs/websocket.ts b/app/lib/common-libs/websocket.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a9589d2aba1efa73ac575be99124f706f49f17f3
--- /dev/null
+++ b/app/lib/common-libs/websocket.ts
@@ -0,0 +1,38 @@
+// 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 * as WS from 'ws'
+
+export class WebSocket extends WS {
+  constructor(url: string, options?: { agent: any }) {
+    super(url, {
+      agent: options && options.agent,
+    })
+  }
+}
+
+export class WebSocketServer extends WS.Server {
+  constructor(options: {
+    server?: any,
+    host?: string,
+    port?: number,
+    path?: string
+  }) {
+    super({
+      server: options.server,
+      path: options.path,
+      host: options.host,
+      port: options.port,
+    })
+  }
+}
diff --git a/app/lib/common/Tristamp.ts b/app/lib/common/Tristamp.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6c3232a66b55197c7c03ce3f49b11a17bbd92015
--- /dev/null
+++ b/app/lib/common/Tristamp.ts
@@ -0,0 +1,18 @@
+// 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.
+
+export interface Tristamp {
+  number: number
+  hash: string
+  medianTime: number
+}
diff --git a/app/lib/computation/BlockchainContext.ts b/app/lib/computation/BlockchainContext.ts
index 5a511b3e2198c061fad7e26aad53e4961eece04d..daf505a3a8c9660106ddd0e3f4e01325fb3f112e 100644
--- a/app/lib/computation/BlockchainContext.ts
+++ b/app/lib/computation/BlockchainContext.ts
@@ -11,22 +11,23 @@
 // 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"
+import {DataErrors} from "../common-libs/errors"
 
-const _               = require('underscore');
 const indexer         = require('../indexer').Indexer
 const constants       = require('../constants');
 
 export class BlockchainContext {
 
   private conf:any
-  private dal:any
+  private dal:FileDAL
   private logger:any
-  private blockchain:DuniterBlockchain
   private quickSynchronizer:QuickSynchronizer
 
   /**
@@ -40,14 +41,14 @@ export class BlockchainContext {
    */
   private vHEAD_1:any
 
-  private HEADrefreshed: Promise<any> | null = Promise.resolve();
+  private HEADrefreshed: Promise<void> = Promise.resolve();
 
   /**
    * Refresh the virtual HEAD value for determined variables of the next coming block, avoiding to recompute them
    * each time a new block arrives to check if the values are correct. We can know and store them early on, in vHEAD.
    */
   private refreshHead(): Promise<void> {
-    this.HEADrefreshed = (async (): Promise<void> => {
+    this.HEADrefreshed = (async () => {
       this.vHEAD_1 = await this.dal.head(1);
       // We suppose next block will have same version #, and no particular data in the block (empty index)
       let block;
@@ -82,7 +83,7 @@ export class BlockchainContext {
     for (const k of keys) {
       copy[k] = this.vHEAD[k];
     }
-    _.extend(copy, props);
+    Underscore.extend(copy, props);
     return copy;
   }
 
@@ -106,10 +107,9 @@ export class BlockchainContext {
     return local_vHEAD.issuerDiff;
   }
 
-  setConfDAL(newConf: any, newDAL: any, theBlockchain: DuniterBlockchain, theQuickSynchronizer: QuickSynchronizer): void {
+  setConfDAL(newConf: any, newDAL: any, theQuickSynchronizer: QuickSynchronizer): void {
     this.dal = newDAL;
     this.conf = newConf;
-    this.blockchain = theBlockchain
     this.quickSynchronizer = theQuickSynchronizer
     this.logger = require('../logger').NewLogger(this.dal.profile);
   }
@@ -118,24 +118,36 @@ export class BlockchainContext {
     return DuniterBlockchain.checkBlock(block, withPoWAndSignature, this.conf, this.dal)
   }
 
-  private async addBlock(obj: BlockDTO, index: any = null, HEAD: DBHead | null = null, trim: boolean): Promise<any> {
-    const block = await this.blockchain.pushTheBlock(obj, index, HEAD, this.conf, this.dal, this.logger, trim)
-    this.vHEAD_1 = this.vHEAD = this.HEADrefreshed = null
+  private async addBlock(obj: BlockDTO, index: any = null, HEAD: DBHead | null = null, trim: boolean): Promise<BlockDTO> {
+    const block = await DuniterBlockchain.pushTheBlock(obj, index, HEAD, this.conf, this.dal, this.logger, trim)
+    this.vHEAD_1 = this.vHEAD = null
     return block
   }
 
   async addSideBlock(obj:BlockDTO): Promise<BlockDTO> {
-    const dbb = await this.blockchain.pushSideBlock(obj, this.dal, this.logger)
+    const dbb = await DuniterBlockchain.pushSideBlock(obj, this.dal, this.logger)
     return dbb.toBlockDTO()
   }
 
-  async revertCurrentBlock(): Promise<BlockDTO> {
+  async revertCurrentBlock(): Promise<DBBlock> {
     const head_1 = await this.dal.bindexDAL.head(1);
     this.logger.debug('Reverting block #%s...', head_1.number);
-    const res = await this.blockchain.revertBlock(head_1.number, head_1.hash, this.dal)
+    const block = await this.dal.getAbsoluteValidBlockInForkWindow(head_1.number, head_1.hash)
+    if (!block) {
+      throw DataErrors[DataErrors.BLOCK_TO_REVERT_NOT_FOUND]
+    }
+    await DuniterBlockchain.revertBlock(head_1.number, head_1.hash, this.dal, block)
+    // Invalidates the head, since it has changed.
+    await this.refreshHead();
+    return block
+  }
+
+  async revertCurrentHead() {
+    const head_1 = await this.dal.bindexDAL.head(1);
+    this.logger.debug('Reverting HEAD~1... (b#%s)', head_1.number);
+    await DuniterBlockchain.revertBlock(head_1.number, head_1.hash, this.dal)
     // Invalidates the head, since it has changed.
     await this.refreshHead();
-    return res;
   }
 
   async applyNextAvailableFork(): Promise<any> {
@@ -146,7 +158,7 @@ export class BlockchainContext {
       throw constants.ERRORS.NO_POTENTIAL_FORK_AS_NEXT;
     }
     const block = forks[0];
-    await this.checkAndAddBlock(block)
+    await this.checkAndAddBlock(BlockDTO.fromJSONObject(block))
     this.logger.debug('Applied block #%s', block.number);
   }
 
diff --git a/app/lib/computation/QuickSync.ts b/app/lib/computation/QuickSync.ts
index ca6c897cdb7f8c4f8c9b847dd2ac960fc98c5313..0e9c79ff3b8a1367feb9c3403badd2639896be57 100644
--- a/app/lib/computation/QuickSync.ts
+++ b/app/lib/computation/QuickSync.ts
@@ -11,14 +11,16 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict"
 import {DuniterBlockchain} from "../blockchain/DuniterBlockchain";
 import {BlockDTO} from "../dto/BlockDTO";
-import {DBTransaction} from "../db/DBTransaction";
-import {Indexer} from "../indexer";
+import {AccountsGarbagingDAL, FullSindexEntry, Indexer} from "../indexer";
 import {CurrencyConfDTO} from "../dto/ConfDTO";
+import {FileDAL} from "../dal/fileDAL"
+import {DBBlock} from "../db/DBBlock"
+import {Underscore} from "../common-libs/underscore"
+import {CommonConstants} from "../common-libs/constants"
+import {cliprogram} from "../common-libs/programOptions"
 
-const _ = require('underscore')
 const constants = require('../constants')
 
 let sync_bindex: any [] = [];
@@ -27,12 +29,11 @@ let sync_mindex: any[] = [];
 let sync_cindex: any[] = [];
 let sync_sindex: any[] = [];
 let sync_bindexSize = 0;
-let sync_allBlocks: BlockDTO[] = [];
 let sync_expires: number[] = [];
 let sync_nextExpiring = 0;
 let sync_currConf: CurrencyConfDTO;
 const sync_memoryWallets: any = {}
-const sync_memoryDAL = {
+const sync_memoryDAL:AccountsGarbagingDAL = {
   getWallet: (conditions: string) => Promise.resolve(sync_memoryWallets[conditions] || { conditions, balance: 0 }),
   saveWallet: async (wallet: any) => {
     // Make a copy
@@ -42,72 +43,36 @@ const sync_memoryDAL = {
     }
   },
   sindexDAL: {
-    getAvailableForConditions: (conditions:string) => null
+    getAvailableForConditions: (conditions:string) => Promise.resolve([])
   }
 }
 
 export class QuickSynchronizer {
 
-  constructor(private blockchain:DuniterBlockchain, private conf: any, private dal: any, private logger: any) {
+  constructor(private conf: any, private dal:FileDAL, private logger: any) {
   }
 
-  async saveBlocksInMainBranch(blocks: BlockDTO[]): Promise<void> {
-    // VERY FIRST: parameters, otherwise we compute wrong variables such as UDTime
-    if (blocks[0].number == 0) {
-      await this.blockchain.saveParametersForRoot(blocks[0], this.conf, this.dal)
-    }
-    // Helper to retrieve a block with local cache
-    const getBlock = (number: number): Promise<BlockDTO> => {
-      const firstLocalNumber = blocks[0].number;
-      if (number >= firstLocalNumber) {
-        let offset = number - firstLocalNumber;
-        return Promise.resolve(blocks[offset])
-      }
-      return this.dal.getBlock(number);
-    };
-    const getBlockByNumberAndHash = async (number: number, hash: string): Promise<BlockDTO> => {
-      const block = await getBlock(number);
-      if (!block || block.hash != hash) {
-        throw 'Block #' + [number, hash].join('-') + ' not found neither in DB nor in applying blocks';
-      }
-      return block;
-    }
-    for (const block of blocks) {
-      block.fork = false;
-      const current:BlockDTO|null = await getBlock(block.number - 1)
-      this.blockchain.updateBlocksComputedVars(current, block)
-    }
-    // Transactions recording
-    await this.updateTransactionsForBlocks(blocks, getBlockByNumberAndHash);
-    await this.dal.blockDAL.saveBunch(blocks);
-    await DuniterBlockchain.pushStatsForBlocks(blocks, this.dal);
-  }
+  async quickApplyBlocks(blocks:BlockDTO[], to: number): Promise<void> {
 
-  private async updateTransactionsForBlocks(blocks: BlockDTO[], getBlockByNumberAndHash: (number: number, hash: string) => Promise<BlockDTO>): Promise<any> {
-    let txs: DBTransaction[] = [];
-    for (const block of blocks) {
-      const newOnes: DBTransaction[] = [];
-      for (const tx of block.transactions) {
-        const [number, hash] = tx.blockstamp.split('-')
-        const refBlock: BlockDTO = (await getBlockByNumberAndHash(parseInt(number), hash))
-        // We force the usage of the reference block's currency
-        tx.currency = refBlock.currency
-        tx.hash = tx.getHash()
-        const dbTx: DBTransaction = DBTransaction.fromTransactionDTO(tx, refBlock.medianTime, true, false, refBlock.number, refBlock.medianTime)
-        newOnes.push(dbTx)
-      }
-      txs = txs.concat(newOnes);
+    sync_memoryDAL.sindexDAL = {
+      getAvailableForConditions: (conditions:string) => this.dal.sindexDAL.getAvailableForConditions(conditions)
     }
-    return this.dal.updateTransactions(txs);
-  }
 
-  async quickApplyBlocks(blocks:BlockDTO[], to: number): Promise<void> {
+    await this.dal.blockDAL.insertBatch(blocks.map((b:any) => {
+      const block = DBBlock.fromBlockDTO(b)
+      block.fork = false
+      return block
+    }))
 
-    sync_memoryDAL.sindexDAL = { getAvailableForConditions: (conditions:string) => this.dal.sindexDAL.getAvailableForConditions(conditions) }
-    let blocksToSave: BlockDTO[] = [];
+    // We only keep approx 2 months of blocks in memory, so memory consumption keeps approximately constant during the sync
+    await this.dal.blockDAL.trimBlocks(blocks[blocks.length - 1].number - CommonConstants.BLOCKS_IN_MEMORY_MAX)
 
     for (const block of blocks) {
-      sync_allBlocks.push(block);
+
+      // VERY FIRST: parameters, otherwise we compute wrong variables such as UDTime
+      if (block.number == 0) {
+        await DuniterBlockchain.saveParametersForRoot(block, this.conf, this.dal)
+      }
 
       // The new kind of object stored
       const dto = BlockDTO.fromJSONObject(block)
@@ -116,22 +81,14 @@ export class QuickSynchronizer {
         sync_currConf = BlockDTO.getConf(block);
       }
 
-      if (block.number <= to - this.conf.forksize) {
-        blocksToSave.push(dto);
+      if (block.number <= to - this.conf.forksize || cliprogram.noSources) { // If we require nosources option, this blockchain can't be valid so we don't make checks
         const index:any = Indexer.localIndex(dto, sync_currConf);
         const local_iindex = Indexer.iindex(index);
         const local_cindex = Indexer.cindex(index);
-        const local_sindex = Indexer.sindex(index);
+        const local_sindex = cliprogram.noSources ? [] : Indexer.sindex(index);
         const local_mindex = Indexer.mindex(index);
 
-        const HEAD = await Indexer.quickCompleteGlobalScope(block, sync_currConf, sync_bindex, local_iindex, local_mindex, local_cindex, {
-          getBlock: (number: number) => {
-            return Promise.resolve(sync_allBlocks[number]);
-          },
-          getBlockByBlockstamp: (blockstamp: string) => {
-            return Promise.resolve(sync_allBlocks[parseInt(blockstamp)]);
-          }
-        });
+        const HEAD = await Indexer.quickCompleteGlobalScope(block, sync_currConf, sync_bindex, local_iindex, local_mindex, local_cindex, this.dal)
         sync_bindex.push(HEAD);
 
         // Remember expiration dates
@@ -143,17 +100,16 @@ export class QuickSynchronizer {
             sync_expires.push(entry.revokes_on)
           }
         }
-        sync_expires = _.uniq(sync_expires);
 
-        await this.blockchain.createNewcomers(local_iindex, this.dal, this.logger)
+        await DuniterBlockchain.createNewcomers(local_iindex, this.dal, this.logger)
 
-        if (block.dividend
+        if ((block.dividend && !cliprogram.noSources)
           || block.joiners.length
           || block.actives.length
           || block.revoked.length
           || block.excluded.length
           || block.certifications.length
-          || block.transactions.length
+          || (block.transactions.length && !cliprogram.noSources)
           || block.medianTime >= sync_nextExpiring) {
           const nextExpiringChanged = block.medianTime >= sync_nextExpiring
 
@@ -167,25 +123,33 @@ export class QuickSynchronizer {
           sync_nextExpiring = sync_expires.reduce((max, value) => max ? Math.min(max, value) : value, 9007199254740991); // Far far away date
 
           // Fills in correctly the SINDEX
-          await Promise.all(_.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);
-              entry.conditions = src.conditions;
-            }
-          }))
+          if (!cliprogram.noSources) {
+            await Promise.all(Underscore.where(sync_sindex.concat(local_sindex), {op: 'UPDATE'}).map(async entry => {
+              if (!entry.conditions) {
+                const src = (await this.dal.getSource(entry.identifier, entry.pos, entry.srcType === 'D')) as FullSindexEntry
+                entry.conditions = src.conditions;
+              }
+            }))
+          }
 
           // Flush the INDEX (not bindex, which is particular)
-          await this.dal.mindexDAL.insertBatch(sync_mindex);
-          await this.dal.iindexDAL.insertBatch(sync_iindex);
-          await this.dal.sindexDAL.insertBatch(sync_sindex);
-          await this.dal.cindexDAL.insertBatch(sync_cindex);
+          await this.dal.flushIndexes({
+            mindex: sync_mindex,
+            iindex: sync_iindex,
+            sindex: sync_sindex,
+            cindex: sync_cindex,
+          })
           sync_iindex = local_iindex
           sync_cindex = local_cindex
           sync_mindex = local_mindex
           sync_sindex = local_sindex
 
-          sync_sindex = sync_sindex.concat(await Indexer.ruleIndexGenDividend(HEAD, local_iindex, this.dal));
-          sync_sindex = sync_sindex.concat(await Indexer.ruleIndexGarbageSmallAccounts(HEAD, sync_sindex, sync_memoryDAL));
+          // Dividends and account garbaging
+          const dividends = cliprogram.noSources ? [] : await Indexer.ruleIndexGenDividend(HEAD, local_iindex, this.dal)
+          if (!cliprogram.noSources) {
+            sync_sindex = sync_sindex.concat(await Indexer.ruleIndexGarbageSmallAccounts(HEAD, sync_sindex, dividends, sync_memoryDAL));
+          }
+
           if (nextExpiringChanged) {
             sync_cindex = sync_cindex.concat(await Indexer.ruleIndexGenCertificationExpiry(HEAD, this.dal));
             sync_mindex = sync_mindex.concat(await Indexer.ruleIndexGenMembershipExpiry(HEAD, this.dal));
@@ -193,14 +157,19 @@ export class QuickSynchronizer {
             sync_iindex = sync_iindex.concat(await Indexer.ruleIndexGenExclusionByCertificatons(HEAD, sync_cindex, local_iindex, this.conf, this.dal));
             sync_mindex = sync_mindex.concat(await Indexer.ruleIndexGenImplicitRevocation(HEAD, this.dal));
           }
-          // Update balances with UD + local garbagings
-          await this.blockchain.updateWallets(sync_sindex, sync_memoryDAL)
+
+          if (!cliprogram.noSources) {
+            // Update balances with UD + local garbagings
+            await DuniterBlockchain.updateWallets(sync_sindex, dividends, sync_memoryDAL)
+          }
 
           // Flush the INDEX again (needs to be done *before* the update of wotb links because of block#0)
-          await this.dal.iindexDAL.insertBatch(sync_iindex);
-          await this.dal.mindexDAL.insertBatch(sync_mindex);
-          await this.dal.sindexDAL.insertBatch(sync_sindex);
-          await this.dal.cindexDAL.insertBatch(sync_cindex);
+          await this.dal.flushIndexes({
+            mindex: sync_mindex,
+            iindex: sync_iindex,
+            sindex: sync_sindex,
+            cindex: sync_cindex,
+          })
 
           // --> Update links
           await this.dal.updateWotbLinks(local_cindex.concat(sync_cindex));
@@ -210,7 +179,7 @@ export class QuickSynchronizer {
           sync_sindex = [];
 
           // Create/Update nodes in wotb
-          await this.blockchain.updateMembers(block, this.dal)
+          await DuniterBlockchain.updateMembers(block, this.dal)
         } else {
           // Concat the results to the pending data
           sync_iindex = sync_iindex.concat(local_iindex);
@@ -233,26 +202,23 @@ export class QuickSynchronizer {
           // We trim it, not necessary to store it all (we already store the full blocks)
           sync_bindex.splice(0, sync_bindexSize);
 
-          // Process triming continuously to avoid super long ending of sync
+          // Process triming & archiving continuously to avoid super long ending of sync
           await this.dal.trimIndexes(sync_bindex[0].number);
         }
       } else {
 
-        if (blocksToSave.length) {
-          await this.saveBlocksInMainBranch(blocksToSave);
-        }
-        blocksToSave = [];
-
         // Save the INDEX
         await this.dal.bindexDAL.insertBatch(sync_bindex);
-        await this.dal.mindexDAL.insertBatch(sync_mindex);
-        await this.dal.iindexDAL.insertBatch(sync_iindex);
-        await this.dal.sindexDAL.insertBatch(sync_sindex);
-        await this.dal.cindexDAL.insertBatch(sync_cindex);
+        await this.dal.flushIndexes({
+          mindex: sync_mindex,
+          iindex: sync_iindex,
+          sindex: sync_sindex,
+          cindex: 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) {
@@ -260,12 +226,12 @@ export class QuickSynchronizer {
         }
 
         if (block.number === 0) {
-          await this.blockchain.saveParametersForRoot(block, this.conf, this.dal)
+          await DuniterBlockchain.saveParametersForRoot(block, this.conf, this.dal)
         }
 
         // Last block: cautious mode to trigger all the INDEX expiry mechanisms
         const { index, HEAD } = await DuniterBlockchain.checkBlock(dto, constants.WITH_SIGNATURES_AND_POW, this.conf, this.dal)
-        await this.blockchain.pushTheBlock(dto, index, HEAD, this.conf, this.dal, this.logger)
+        await DuniterBlockchain.pushTheBlock(dto, index, HEAD, this.conf, this.dal, this.logger)
 
         // Clean temporary variables
         sync_bindex = [];
@@ -274,14 +240,10 @@ export class QuickSynchronizer {
         sync_cindex = [];
         sync_sindex = [];
         sync_bindexSize = 0;
-        sync_allBlocks = [];
         sync_expires = [];
         sync_nextExpiring = 0;
         // sync_currConf = {};
       }
     }
-    if (blocksToSave.length) {
-      await this.saveBlocksInMainBranch(blocksToSave);
-    }
   }
 }
diff --git a/app/lib/constants.ts b/app/lib/constants.ts
index 5b9f76d72d3869b2dff9cfd99208c93498d0f83d..7092d69e5ff3ccb15b66161198ad571936edd2ac 100644
--- a/app/lib/constants.ts
+++ b/app/lib/constants.ts
@@ -14,7 +14,7 @@
 "use strict";
 import {CommonConstants} from "./common-libs/constants"
 import {OtherConstants} from "./other_constants"
-import { ProverConstants } from '../modules/prover/lib/constants';
+import {ProverConstants} from '../modules/prover/lib/constants';
 
 const UDID2        = "udid2;c;([A-Z-]*);([A-Z-]*);(\\d{4}-\\d{2}-\\d{2});(e\\+\\d{2}\\.\\d{2}(\\+|-)\\d{3}\\.\\d{2});(\\d+)(;?)";
 const PUBKEY       = CommonConstants.FORMATS.PUBKEY
@@ -176,7 +176,6 @@ module.exports = {
   NO_FORK_ALLOWED: false,
 
   SAFE_FACTOR: 3,
-  BLOCKS_COLLECT_THRESHOLD: 30, // Blocks to collect from memory and persist
 
   MUTE_LOGS_DURING_UNIT_TESTS: OtherConstants.MUTE_LOGS_DURING_UNIT_TESTS,
 
@@ -185,8 +184,6 @@ module.exports = {
   SANDBOX_SIZE_CERTIFICATIONS: 12,
   SANDBOX_SIZE_MEMBERSHIPS: 5000,
 
-  CURRENT_BLOCK_CACHE_DURATION: 10 * 1000, // 30 seconds
-
   // With `logs` command, the number of tail lines to show
   NB_INITIAL_LINES_TO_SHOW: 100
 };
diff --git a/app/lib/dal/drivers/LokiFsAdapter.ts b/app/lib/dal/drivers/LokiFsAdapter.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e7f5342cce566331d4db9be0fe4757f438a5dc52
--- /dev/null
+++ b/app/lib/dal/drivers/LokiFsAdapter.ts
@@ -0,0 +1,350 @@
+// 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 {FileSystem} from "../../system/directory"
+import {DataErrors} from "../../common-libs/errors"
+import {CFSCore} from "../fileDALs/CFSCore"
+import {getNanosecondsTime} from "../../../ProcessCpuProfiler"
+import {NewLogger} from "../../logger"
+
+export interface Iterator<T> {
+  next(value?: any): IteratorResult<T>
+  return?(value?: any): IteratorResult<T>
+  throw?(e?: any): IteratorResult<T>
+}
+
+export interface IteratorResult<T> {
+  done: boolean
+  value: T
+}
+
+export interface DBCommit {
+  indexFile:string,
+  changes: string[]
+  collections: {
+    [coll:string]: string
+  }
+}
+
+export class LokiFsAdapter {
+
+  private static COMMIT_FILE = "commit.json"
+  private cfs:CFSCore
+
+  protected mode = "reference"
+  protected dbref = null
+  protected dirtyPartitions: string[] = [];
+
+  constructor(dbDir:string, fs:FileSystem) {
+    this.cfs = new CFSCore(dbDir, fs)
+  }
+
+  /**
+   * Main method to manually pilot the full DB saving to disk.
+   * @param loki
+   * @returns {Promise}
+   */
+  async dbDump(loki:any) {
+    return new Promise(res => loki.saveDatabaseInternal(res))
+  }
+
+  async listPendingChanges(): Promise<string[]> {
+    if (!(await this.cfs.exists(LokiFsAdapter.COMMIT_FILE))) {
+      return []
+    }
+    const commitObj = await this.cfs.readJSON(LokiFsAdapter.COMMIT_FILE)
+    return commitObj.changes
+  }
+
+  /**
+   * Flushes the DB changes to disk.
+   * @param loki
+   * @returns {Promise<number>} The number of changes detected.
+   */
+  async flush(loki:any): Promise<number> {
+    // If the database already has a commit file: incremental changes
+    if (await this.cfs.exists(LokiFsAdapter.COMMIT_FILE)) {
+      const commit = (await this.cfs.readJSON(LokiFsAdapter.COMMIT_FILE)) as DBCommit
+      const changesFilename = 'changes.' + getNanosecondsTime() + ".json"
+      const changes = JSON.parse(loki.serializeChanges())
+      await this.cfs.writeJSON(changesFilename, changes)
+      // Mark the changes as commited
+      commit.changes.push(changesFilename)
+      await this.cfs.writeJSON(LokiFsAdapter.COMMIT_FILE, commit)
+      // Forget about the changes now that we saved them
+      loki.clearChanges()
+      return changes.length
+    } else {
+      // Otherwise we make a full dump
+      await this.dbDump(loki)
+      loki.clearChanges()
+      return 0
+    }
+  }
+
+  /**
+   *
+   * Method indirectly called by `flush`.
+   *
+   * Loki reference adapter interface function.  Saves structured json via loki database object reference.
+   *
+   * @param {string} dbname - the name to give the serialized database within the catalog.
+   * @param {object} dbref - the loki database object reference to save.
+   * @param {function} callback - callback passed obj.success with true or false
+   * @memberof LokiFsStructuredAdapter
+   */
+  public async exportDatabase(dbname:string, dbref:any, callback:any) {
+
+    this.dbref = dbref
+
+    // create (dirty) partition generator/iterator
+    let pi = this.getPartition()
+
+    // Prepare the commit: inherit from existing commit
+    let commit:DBCommit = {
+      indexFile: 'index.db.' + getNanosecondsTime() + ".json",
+      changes: [],
+      collections: {}
+    }
+    if (await this.cfs.exists(LokiFsAdapter.COMMIT_FILE)) {
+      commit.collections = ((await this.cfs.readJSON(LokiFsAdapter.COMMIT_FILE)) as DBCommit).collections
+    }
+
+    // Eventually create the tree
+    await this.cfs.makeTree('/')
+
+    this.saveNextPartition(commit, pi, async () => {
+
+      // Write the new commit file. If the process gets interrupted during this phase, the DB will likely get corrupted.
+      await this.cfs.writeJSON(LokiFsAdapter.COMMIT_FILE, commit)
+
+      const remainingFiles = [
+        LokiFsAdapter.COMMIT_FILE,
+        commit.indexFile
+      ].concat(Object.keys(commit.collections).map(k => commit.collections[k]))
+
+      // Clean obsolete DB files
+      const list = await this.cfs.list('/')
+      for (const f of list) {
+        if (remainingFiles.indexOf(f) === -1) {
+          await this.cfs.remove(f)
+        }
+      }
+
+      // Finish
+      callback(null)
+    })
+  }
+
+  /**
+   * Generator for yielding sequence of dirty partition indices to iterate.
+   *
+   * @memberof LokiFsStructuredAdapter
+   */
+  private *getPartition(): Iterator<string> {
+    let idx,
+      clen = (this.dbref as any).collections.length
+
+    // since database container (partition -1) doesn't have dirty flag at db level, always save
+    yield "";
+
+    // yield list of dirty partitions for iterateration
+    for(idx=0; idx<clen; idx++) {
+      const coll:any = (this.dbref as any).collections[idx]
+      if (coll.dirty) {
+        yield coll.name
+      }
+    }
+  }
+
+  /**
+   * Utility method for queueing one save at a time
+   */
+  private async saveNextPartition(commit:DBCommit, pi:Iterator<string>, callback:any) {
+    let li;
+    let filename;
+    let self = this;
+    let pinext = pi.next();
+
+    if (pinext.done) {
+      callback();
+      return;
+    }
+
+    // db container (partition -1) uses just dbname for filename,
+    // otherwise append collection array index to filename
+    filename = (pinext.value === "") ? commit.indexFile : ((pinext.value + "." + getNanosecondsTime()) + ".json")
+
+    // We map the collection name to a particular file
+    if (pinext.value) {
+      commit.collections[pinext.value] = filename
+    }
+
+    li = this.generateDestructured({ partition: pinext.value });
+
+    // iterate each of the lines generated by generateDestructured()
+    await this.cfs.fsStreamTo(filename, li)
+
+    self.saveNextPartition(commit, pi, callback)
+  };
+
+  /**
+   * Generator for constructing lines for file streaming output of db container or collection.
+   *
+   * @param {object=} options - output format options for use externally to loki
+   * @param {int=} options.partition - can be used to only output an individual collection or db (-1)
+   *
+   * @returns {string|array} A custom, restructured aggregation of independent serializations.
+   * @memberof LokiFsStructuredAdapter
+   */
+  *generateDestructured(options = { partition: "" }) {
+    let idx
+    let dbcopy;
+
+    // if partition is -1 we will return database container with no data
+    if (options.partition === "") {
+      // instantiate lightweight clone and remove its collection data
+      dbcopy = (this.dbref as any).copy();
+
+      for(idx=0; idx < dbcopy.collections.length; idx++) {
+        dbcopy.collections[idx].data = [];
+        dbcopy.collections[idx].changes = [];
+      }
+
+      yield dbcopy.serialize({
+        serializationMethod: "normal"
+      });
+
+      return;
+    }
+
+    // 'partitioned' along with 'partition' of 0 or greater is a request for single collection serialization
+    if (options.partition) {
+      let doccount,
+        docidx;
+
+      // dbref collections have all data so work against that
+      const coll = (this.dbref as any).collections.filter((c:any) => c.name === options.partition)[0]
+      doccount = coll.data.length;
+
+      for(docidx=0; docidx<doccount; docidx++) {
+        yield JSON.stringify(coll.data[docidx]);
+      }
+
+      if (doccount === 0) {
+        yield ''
+      }
+    }
+  };
+
+  /**
+   *
+   * Automatically called on startup.
+   *
+   * Loki persistence adapter interface function which outputs un-prototype db object reference to load from.
+   *
+   * @memberof LokiFsStructuredAdapter
+   */
+  public async loadDatabase(loki:any) {
+    let instream,
+      outstream,
+      rl,
+      self=this;
+
+    this.dbref = null;
+
+    // Load the database according to the commit file (lock for valid DB files)
+    let commitObj:DBCommit
+    if (!(await this.cfs.exists(LokiFsAdapter.COMMIT_FILE))) {
+      return
+    }
+    commitObj = await this.cfs.readJSON(LokiFsAdapter.COMMIT_FILE)
+
+    // make sure file exists
+    const dbname = commitObj.indexFile
+
+    // Trimmed data first
+    if (await this.cfs.exists(dbname)) {
+      const line = await this.cfs.read(dbname)
+      // it should single JSON object (a one line file)
+      if (self.dbref === null && line) {
+        self.dbref = JSON.parse(line)
+      }
+
+      // when that is done, examine its collection array to sequence loading each
+      if ((self.dbref as any).collections.length > 0) {
+        await self.loadNextCollection(commitObj.collections, 0)
+        loki.loadJSONObject(self.dbref)
+      }
+    } else {
+      // file does not exist, we throw as the commit file is not respected
+      throw Error(DataErrors[DataErrors.CORRUPTED_DATABASE])
+    }
+
+    // Changes data
+    for (const changeFile of commitObj.changes) {
+      const changes = await this.cfs.readJSON(changeFile)
+      let len = changes.length
+      for (let i = 1; i <= len; i++) {
+        const c = changes[i - 1]
+        const coll = loki.getCollection(c.name)
+        if (c.operation === 'I') {
+          c.obj.$loki = undefined
+          await coll.insert(c.obj)
+        }
+        else if (c.operation === 'U') {
+          await coll.update(c.obj)
+        }
+        else if (c.operation === 'R') {
+          await coll.remove(c.obj)
+        }
+        NewLogger().trace('[loki] Processed change %s (%s/%s)', c.name, i, len)
+      }
+    }
+  };
+
+
+  /**
+   * Recursive function to chain loading of each collection one at a time.
+   * If at some point i can determine how to make async driven generator, this may be converted to generator.
+   *
+   * @param {object} collectionsMap - Map between the names of the collections and their matching file of the filesystem.
+   * @param {int} collectionIndex - the ordinal position of the collection to load.
+   * @param {function} callback - callback to pass to next invocation or to call when done
+   * @memberof LokiFsStructuredAdapter
+   */
+  async loadNextCollection(collectionsMap:{ [coll:string]: string }, collectionIndex:any) {
+    let self=this,
+      obj;
+    const coll = (self.dbref as any).collections[collectionIndex]
+    if (!collectionsMap[coll.name] || !(await this.cfs.exists(collectionsMap[coll.name]))) {
+      throw Error(DataErrors[DataErrors.CORRUPTED_DATABASE])
+    }
+    const filename = collectionsMap[coll.name]
+    const content = await this.cfs.read(filename)
+    if (content) {
+      const lines = content.split('\n')
+      for (const line of lines) {
+        if (line !== "") {
+          obj = JSON.parse(line);
+          coll.data.push(obj);
+        }
+      }
+    }
+
+    // if there are more collections, load the next one
+    if (++collectionIndex < (self.dbref as any).collections.length) {
+      await self.loadNextCollection(collectionsMap, collectionIndex)
+    }
+  };
+}
\ No newline at end of file
diff --git a/app/lib/dal/drivers/LokiJsDriver.ts b/app/lib/dal/drivers/LokiJsDriver.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7a3dfc549285da3a774f3fc942dab4f2d9da008f
--- /dev/null
+++ b/app/lib/dal/drivers/LokiJsDriver.ts
@@ -0,0 +1,42 @@
+import {LokiFsAdapter} from "./LokiFsAdapter"
+import {MemFS, RealFS} from "../../system/directory"
+
+const loki = require('lokijs')
+
+export class LokiJsDriver {
+
+  private readonly lokiInstance:any
+  private adapter: LokiFsAdapter
+
+  constructor(
+    private dbFilePath:string = ''
+  ) {
+    this.adapter = new LokiFsAdapter(dbFilePath, dbFilePath ? RealFS() : MemFS())
+    this.lokiInstance = new loki(dbFilePath + '/loki.db' || 'mem' + Date.now() + '.db', {
+      adapter: this.adapter
+    })
+  }
+
+  async loadDatabase() {
+    // We load only non-memory DB
+    if (this.dbFilePath) {
+      await this.adapter.loadDatabase(this.lokiInstance)
+    }
+  }
+
+  getLokiInstance() {
+    return this.lokiInstance
+  }
+
+  async commitData() {
+    return this.adapter.flush(this.lokiInstance)
+  }
+
+  async flushAndTrimData() {
+    return this.adapter.dbDump(this.lokiInstance)
+  }
+
+  async listChangesFilesPending(): Promise<string[]> {
+    return this.adapter.listPendingChanges()
+  }
+}
diff --git a/app/lib/dal/drivers/SQLiteDriver.ts b/app/lib/dal/drivers/SQLiteDriver.ts
index b7e52b00eb19aa3fc20a6f95f14ea02b1271cda6..1b2c3896d7867e8ddee0b304e2684d13980f0e33 100644
--- a/app/lib/dal/drivers/SQLiteDriver.ts
+++ b/app/lib/dal/drivers/SQLiteDriver.ts
@@ -11,7 +11,9 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-const qfs     = require('q-io/fs')
+import {OtherConstants} from "../../other_constants"
+import {RealFS} from "../../system/directory"
+
 const sqlite3 = require("sqlite3").verbose()
 
 const MEMORY_PATH = ':memory:'
@@ -34,6 +36,11 @@ export class SQLiteDriver {
         let sqlite = new sqlite3.Database(this.path)
         await new Promise<any>((resolve) => sqlite.once('open', resolve))
         // Database is opened
+        if (OtherConstants.SQL_TRACES) {
+          sqlite.on('trace', (trace:any) => {
+            this.logger.trace(trace)
+          })
+        }
 
         // Force case sensitiveness on LIKE operator
         const sql = 'PRAGMA case_sensitive_like=ON'
@@ -75,7 +82,7 @@ export class SQLiteDriver {
     this.logger.debug('Removing SQLite database...')
     await this.closeConnection()
     if (this.path !== MEMORY_PATH) {
-      await qfs.remove(this.path)
+      await RealFS().fsUnlink(this.path)
     }
     this.logger.debug('Database removed')
   }
diff --git a/app/lib/dal/fileDAL.ts b/app/lib/dal/fileDAL.ts
index 4e441a89b32026b162f0621f6933a9bdcca29cbd..f5e556edb57f5f5424ae7b2eca139783c2d26924 100644
--- a/app/lib/dal/fileDAL.ts
+++ b/app/lib/dal/fileDAL.ts
@@ -11,93 +11,163 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
+import * as fs from 'fs'
+import * as path from 'path'
 import {SQLiteDriver} from "./drivers/SQLiteDriver"
 import {ConfDAL} from "./fileDALs/ConfDAL"
 import {StatDAL} from "./fileDALs/StatDAL"
 import {ConfDTO} from "../dto/ConfDTO"
 import {BlockDTO} from "../dto/BlockDTO"
 import {DBHead} from "../db/DBHead"
-import {DBIdentity} from "./sqliteDAL/IdentityDAL"
-import {CindexEntry, IindexEntry, IndexEntry, MindexEntry, SindexEntry} from "../indexer"
-import {DBPeer} from "./sqliteDAL/PeerDAL"
+import {DBIdentity, IdentityDAL} from "./sqliteDAL/IdentityDAL"
+import {
+  CindexEntry,
+  FullCindexEntry,
+  FullIindexEntry,
+  FullMindexEntry,
+  IindexEntry,
+  IndexEntry,
+  MindexEntry,
+  SimpleTxInput,
+  SimpleUdEntryForWallet,
+  SindexEntry
+} from "../indexer"
 import {TransactionDTO} from "../dto/TransactionDTO"
-import {DBCert} from "./sqliteDAL/CertDAL"
-import {DBWallet} from "./sqliteDAL/WalletDAL"
-import {DBTx} from "./sqliteDAL/TxsDAL"
+import {CertDAL, DBCert} from "./sqliteDAL/CertDAL"
 import {DBBlock} from "../db/DBBlock"
-import {DBMembership} from "./sqliteDAL/MembershipDAL"
+import {DBMembership, MembershipDAL} from "./sqliteDAL/MembershipDAL"
 import {MerkleDTO} from "../dto/MerkleDTO"
 import {CommonConstants} from "../common-libs/constants"
 import {PowDAL} from "./fileDALs/PowDAL";
+import {Initiable} from "./sqliteDAL/Initiable"
+import {MetaDAL} from "./sqliteDAL/MetaDAL"
+import {DataErrors} from "../common-libs/errors"
+import {BasicRevocableIdentity, IdentityDTO} from "../dto/IdentityDTO"
+import {FileSystem} from "../system/directory"
+import {WoTBInstance} from "../wot"
+import {IIndexDAO} from "./indexDAL/abstract/IIndexDAO"
+import {LokiIIndex} from "./indexDAL/loki/LokiIIndex"
+import {BIndexDAO} from "./indexDAL/abstract/BIndexDAO"
+import {MIndexDAO} from "./indexDAL/abstract/MIndexDAO"
+import {SIndexDAO} from "./indexDAL/abstract/SIndexDAO"
+import {CIndexDAO} from "./indexDAL/abstract/CIndexDAO"
+import {IdentityForRequirements} from "../../service/BlockchainService"
+import {LokiSIndex} from "./indexDAL/loki/LokiSIndex"
+import {LokiCIndex} from "./indexDAL/loki/LokiCIndex"
+import {LokiMIndex} from "./indexDAL/loki/LokiMIndex";
+import {LokiBIndex} from "./indexDAL/loki/LokiBIndex"
+import {NewLogger} from "../logger"
+import {LokiBlockchain} from "./indexDAL/loki/LokiBlockchain"
+import {BlockchainDAO} from "./indexDAL/abstract/BlockchainDAO"
+import {LokiTransactions} from "./indexDAL/loki/LokiTransactions"
+import {TxsDAO} from "./indexDAL/abstract/TxsDAO"
+import {LokiJsDriver} from "./drivers/LokiJsDriver"
+import {WalletDAO} from "./indexDAL/abstract/WalletDAO"
+import {LokiWallet} from "./indexDAL/loki/LokiWallet"
+import {PeerDAO} from "./indexDAL/abstract/PeerDAO"
+import {LokiPeer} from "./indexDAL/loki/LokiPeer"
+import {DBTx} from "../db/DBTx"
+import {DBWallet} from "../db/DBWallet"
+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"
+import {MonitorFlushedIndex} from "../debug/MonitorFlushedIndex"
+import {cliprogram} from "../common-libs/programOptions"
+import {DividendDAO, UDSource} from "./indexDAL/abstract/DividendDAO"
+import {LokiDividend} from "./indexDAL/loki/LokiDividend"
+import {HttpSource, HttpUD} from "../../modules/bma/lib/dtos"
+import {GenericDAO} from "./indexDAL/abstract/GenericDAO"
+import {LokiDAO} from "./indexDAL/loki/LokiDAO"
 
-const fs      = require('fs')
-const path    = require('path')
 const readline = require('readline')
-const _       = require('underscore');
 const indexer = require('../indexer').Indexer
 const logger = require('../logger').NewLogger('filedal');
 const constants = require('../constants');
 
 export interface FileDALParams {
   home:string
-  fs:any
+  fs:FileSystem
   dbf:() => SQLiteDriver
-  wotb:any
+  dbf2: () => LokiJsDriver
+  wotb:WoTBInstance
+}
+
+export interface IndexBatch {
+  mindex: MindexEntry[]
+  iindex: IindexEntry[]
+  sindex: SindexEntry[]
+  cindex: CindexEntry[]
 }
 
 export class FileDAL {
 
   rootPath:string
-  myFS:any
+  fs: FileSystem
+  loki:LokiJsDriver
   sqliteDriver:SQLiteDriver
-  wotb:any
+  wotb:WoTBInstance
   profile:string
 
+  // Simple file accessors
   powDAL:PowDAL
-  confDAL:any
-  metaDAL:any
-  peerDAL:any
-  blockDAL:any
-  txsDAL:any
-  statDAL:any
-  idtyDAL:any
-  certDAL:any
-  msDAL:any
-  walletDAL:any
-  bindexDAL:any
-  mindexDAL:any
-  iindexDAL:any
-  sindexDAL:any
-  cindexDAL:any
-  newDals:any
+  confDAL:ConfDAL
+  statDAL:StatDAL
+  blockchainArchiveDAL:BlockchainArchiveDAO<DBBlock>
+
+  // SQLite DALs
+  metaDAL:MetaDAL
+  idtyDAL:IdentityDAL
+  certDAL:CertDAL
+  msDAL:MembershipDAL
+
+  // New DAO entities
+  blockDAL:BlockchainDAO
+  txsDAL:TxsDAO
+  peerDAL:PeerDAO
+  walletDAL:WalletDAO
+  bindexDAL:BIndexDAO
+  mindexDAL:MIndexDAO
+  iindexDAL:IIndexDAO
+  sindexDAL:SIndexDAO
+  cindexDAL:CIndexDAO
+  dividendDAL:DividendDAO
+  newDals:{ [k:string]: Initiable }
+  private dals:(BlockchainArchiveDAO<any>|PeerDAO|WalletDAO|GenericDAO<any>)[]
+  private daos:LokiDAO[]
 
   loadConfHook: (conf:ConfDTO) => Promise<void>
   saveConfHook: (conf:ConfDTO) => Promise<ConfDTO>
 
   constructor(params:FileDALParams) {
     this.rootPath = params.home
-    this.myFS = params.fs
     this.sqliteDriver = params.dbf()
+    this.loki = params.dbf2()
     this.wotb = params.wotb
     this.profile = 'DAL'
+    this.fs = params.fs
 
     // DALs
-    this.powDAL = new PowDAL(this.rootPath, this.myFS)
-    this.confDAL = new ConfDAL(this.rootPath, this.myFS)
+    this.powDAL = new PowDAL(this.rootPath, params.fs)
+    this.confDAL = new ConfDAL(this.rootPath, params.fs)
     this.metaDAL = new (require('./sqliteDAL/MetaDAL').MetaDAL)(this.sqliteDriver);
-    this.peerDAL = new (require('./sqliteDAL/PeerDAL').PeerDAL)(this.sqliteDriver);
-    this.blockDAL = new (require('./sqliteDAL/BlockDAL').BlockDAL)(this.sqliteDriver);
-    this.txsDAL = new (require('./sqliteDAL/TxsDAL').TxsDAL)(this.sqliteDriver);
-    this.statDAL = new StatDAL(this.rootPath, this.myFS)
+    this.blockchainArchiveDAL = new CFSBlockchainArchive(new CFSCore(path.join(this.rootPath, '/archives'), params.fs), CommonConstants.CONST_BLOCKS_CHUNK)
+    this.blockDAL = new LokiBlockchain(this.loki.getLokiInstance())
+    this.txsDAL = new LokiTransactions(this.loki.getLokiInstance())
+    this.statDAL = new StatDAL(this.rootPath, params.fs)
     this.idtyDAL = new (require('./sqliteDAL/IdentityDAL').IdentityDAL)(this.sqliteDriver);
     this.certDAL = new (require('./sqliteDAL/CertDAL').CertDAL)(this.sqliteDriver);
     this.msDAL = new (require('./sqliteDAL/MembershipDAL').MembershipDAL)(this.sqliteDriver);
-    this.walletDAL = new (require('./sqliteDAL/WalletDAL').WalletDAL)(this.sqliteDriver);
-    this.bindexDAL = new (require('./sqliteDAL/index/BIndexDAL').BIndexDAL)(this.sqliteDriver);
-    this.mindexDAL = new (require('./sqliteDAL/index/MIndexDAL').MIndexDAL)(this.sqliteDriver);
-    this.iindexDAL = new (require('./sqliteDAL/index/IIndexDAL').IIndexDAL)(this.sqliteDriver);
-    this.sindexDAL = new (require('./sqliteDAL/index/SIndexDAL').SIndexDAL)(this.sqliteDriver);
-    this.cindexDAL = new (require('./sqliteDAL/index/CIndexDAL').CIndexDAL)(this.sqliteDriver);
+    this.peerDAL = new LokiPeer(this.loki.getLokiInstance())
+    this.walletDAL = new LokiWallet(this.loki.getLokiInstance())
+    this.bindexDAL = new LokiBIndex(this.loki.getLokiInstance())
+    this.mindexDAL = new LokiMIndex(this.loki.getLokiInstance())
+    this.iindexDAL = new LokiIIndex(this.loki.getLokiInstance())
+    this.sindexDAL = new LokiSIndex(this.loki.getLokiInstance())
+    this.cindexDAL = new LokiCIndex(this.loki.getLokiInstance())
+    this.dividendDAL = new LokiDividend(this.loki.getLokiInstance())
 
     this.newDals = {
       'powDAL': this.powDAL,
@@ -115,12 +185,52 @@ export class FileDAL {
       'mindexDAL': this.mindexDAL,
       'iindexDAL': this.iindexDAL,
       'sindexDAL': this.sindexDAL,
-      'cindexDAL': this.cindexDAL
+      'cindexDAL': this.cindexDAL,
+      'dividendDAL': this.dividendDAL,
+      'blockchainArchiveDAL': this.blockchainArchiveDAL,
     }
   }
 
+  public enableChangesAPI() {
+    this.daos.map(d => d.enableChangesAPI())
+  }
+
+  public disableChangesAPI() {
+    this.daos.map(d => d.disableChangesAPI())
+  }
+
   async init(conf:ConfDTO) {
-    const dalNames = _.keys(this.newDals);
+    // Init LokiJS
+    await this.loki.loadDatabase()
+    this.daos = [
+      this.blockDAL,
+      this.txsDAL,
+      this.peerDAL,
+      this.walletDAL,
+      this.bindexDAL,
+      this.mindexDAL,
+      this.iindexDAL,
+      this.sindexDAL,
+      this.cindexDAL,
+      this.dividendDAL
+    ]
+    this.dals = [
+      this.blockDAL,
+      this.txsDAL,
+      this.peerDAL,
+      this.walletDAL,
+      this.bindexDAL,
+      this.mindexDAL,
+      this.iindexDAL,
+      this.sindexDAL,
+      this.cindexDAL,
+      this.dividendDAL,
+      this.blockchainArchiveDAL,
+    ]
+    for (const indexDAL of this.dals) {
+      indexDAL.triggerInit()
+    }
+    const dalNames = Underscore.keys(this.newDals);
     for (const dalName of dalNames) {
       const dal = this.newDals[dalName];
       await dal.init();
@@ -138,6 +248,33 @@ export class FileDAL {
     return this.metaDAL.getVersion()
   }
 
+  /**
+   * Transfer a chunk of blocks from memory DB to archives if the memory DB overflows.
+   * @returns {Promise<void>}
+   */
+  async archiveBlocks() {
+    const lastArchived = await this.blockchainArchiveDAL.getLastSavedBlock()
+    const current = await this.blockDAL.getCurrent()
+    const lastNumber = lastArchived ? lastArchived.number : -1
+    const currentNumber = current ? current.number : -1
+    const difference = currentNumber - lastNumber
+    if (difference > CommonConstants.BLOCKS_IN_MEMORY_MAX) {
+      const CHUNK_SIZE = this.blockchainArchiveDAL.chunkSize
+      const nbBlocksOverflow = difference - CommonConstants.BLOCKS_IN_MEMORY_MAX
+      const chunks = (nbBlocksOverflow - (nbBlocksOverflow % CHUNK_SIZE)) / CHUNK_SIZE
+      for (let i = 0; i < chunks; i++) {
+        const start = lastNumber + (i*CHUNK_SIZE) + 1
+        const end = lastNumber + (i*CHUNK_SIZE) + CHUNK_SIZE
+        const memBlocks = await this.blockDAL.getNonForkChunk(start, end)
+        if (memBlocks.length !== CHUNK_SIZE) {
+          throw Error(DataErrors[DataErrors.CANNOT_ARCHIVE_CHUNK_WRONG_SIZE])
+        }
+        await this.blockchainArchiveDAL.archive(memBlocks)
+        await this.blockDAL.trimBlocks(end)
+      }
+    }
+  }
+
   writeFileOfBlock(block:DBBlock) {
     return this.blockDAL.saveBlock(block)
   }
@@ -152,7 +289,7 @@ export class FileDAL {
 
   async getPeer(pubkey:string) {
     try {
-      return this.peerDAL.getPeer(pubkey)
+      return await this.peerDAL.getPeer(pubkey)
     } catch (err) {
       throw Error('Unknown peer ' + pubkey);
     }
@@ -162,73 +299,91 @@ export class FileDAL {
     return  this.peerDAL.getPeersWithEndpointsLike('WS2P')
   }
 
-  async getBlock(number:number) {
-    const block = await this.blockDAL.getBlock(number)
-    return block || null;
-  }
-
-  getAbsoluteBlockByNumberAndHash(number:number, hash:string) {
-    return this.blockDAL.getAbsoluteBlock(number, hash)
-  }
-
-  getAbsoluteBlockByBlockstamp(blockstamp:string) {
-    if (!blockstamp) throw "Blockstamp is required to find the block"
-    const sp = blockstamp.split('-')
-    const number = parseInt(sp[0])
-    const hash = sp[1]
-    return this.getAbsoluteBlockByNumberAndHash(number, hash)
-  }
-
-  getBlockByBlockstampOrNull(blockstamp:string) {
+  getAbsoluteBlockInForkWindowByBlockstamp(blockstamp:string) {
     if (!blockstamp) throw "Blockstamp is required to find the block";
     const sp = blockstamp.split('-');
     const number = parseInt(sp[0]);
     const hash = sp[1];
-    return this.getBlockByNumberAndHashOrNull(number, hash);
+    return this.getAbsoluteBlockInForkWindow(number, hash)
   }
 
-  getBlockByBlockstamp(blockstamp:string) {
+  getAbsoluteValidBlockInForkWindowByBlockstamp(blockstamp:string) {
     if (!blockstamp) throw "Blockstamp is required to find the block";
     const sp = blockstamp.split('-');
     const number = parseInt(sp[0]);
     const hash = sp[1];
-    return this.getBlockByNumberAndHash(number, hash);
+    return this.getAbsoluteValidBlockInForkWindow(number, hash)
   }
 
-  async getBlockByNumberAndHash(number:number, hash:string) {
-    try {
-      const block = await this.getBlock(number);
-      if (!block || block.hash != hash)
-        throw "Not found";
-      else
-        return block;
-    } catch (err) {
-      throw 'Block ' + [number, hash].join('-') + ' not found';
+  async getBlockWeHaveItForSure(number:number): Promise<DBBlock> {
+    return (await this.blockDAL.getBlock(number)) as DBBlock || (await this.blockchainArchiveDAL.getBlockByNumber(number))
+  }
+
+  // Duniter-UI dependency
+  async getBlock(number: number): Promise<DBBlock|null> {
+    return this.getFullBlockOf(number)
+  }
+
+  async getFullBlockOf(number: number): Promise<DBBlock|null> {
+    return (await this.blockDAL.getBlock(number)) || (await this.blockchainArchiveDAL.getBlockByNumber(number))
+  }
+
+  async getBlockstampOf(number: number): Promise<string|null> {
+    const block = await this.getTristampOf(number)
+    if (block) {
+      return [block.number, block.hash].join('-')
     }
+    return null
   }
 
-  async getBlockByNumberAndHashOrNull(number:number, hash:string) {
-    try {
-      return await this.getBlockByNumberAndHash(number, hash)
-    } catch (e) {
-      return null;
+  async getTristampOf(number: number): Promise<Tristamp|null> {
+    return (await this.blockDAL.getBlock(number)) || (await this.blockchainArchiveDAL.getBlockByNumber(number))
+  }
+
+  async existsAbsoluteBlockInForkWindow(number:number, hash:string): Promise<boolean> {
+    return !!(await this.getAbsoluteBlockByNumberAndHash(number, hash))
+  }
+
+  async getAbsoluteBlockInForkWindow(number:number, hash:string): Promise<DBBlock|null> {
+    return this.getAbsoluteBlockByNumberAndHash(number, hash)
+  }
+
+  async getAbsoluteValidBlockInForkWindow(number:number, hash:string): Promise<DBBlock|null> {
+    const block = await this.getAbsoluteBlockByNumberAndHash(number, hash)
+    if (block && !block.fork) {
+      return block
     }
+    return null
+  }
+
+  async getAbsoluteBlockByNumberAndHash(number:number, hash:string): Promise<DBBlock|null> {
+    if (number > 0) {
+      return (await this.blockDAL.getAbsoluteBlock(number, hash)) || (await this.blockchainArchiveDAL.getBlock(number, hash))
+    } else {
+      // Block#0 is special
+      return (await this.blockDAL.getBlock(number)) || (await this.blockchainArchiveDAL.getBlockByNumber(number))
+    }
+  }
+
+  async getAbsoluteBlockByBlockstamp(blockstamp: string): Promise<DBBlock|null> {
+    const sp = blockstamp.split('-')
+    return this.getAbsoluteBlockByNumberAndHash(parseInt(sp[0]), sp[1])
   }
 
   async existsNonChainableLink(from:string, vHEAD_1:DBHead, sigStock:number) {
     // Cert period rule
     const medianTime = vHEAD_1 ? vHEAD_1.medianTime : 0;
-    const linksFrom = await this.cindexDAL.reducablesFrom(from)
-    const unchainables = _.filter(linksFrom, (link:CindexEntry) => link.chainable_on > medianTime);
+    const linksFrom:FullCindexEntry[] = await this.cindexDAL.reducablesFrom(from)
+    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;
   }
 
 
   async getCurrentBlockOrNull() {
-    let current = null;
+    let current:DBBlock|null = null;
     try {
       current = await this.getBlockCurrent()
     } catch (e) {
@@ -240,17 +395,10 @@ export class FileDAL {
   }
 
   getPromoted(number:number) {
-    return this.getBlock(number)
+    return this.getFullBlockOf(number)
   }
 
   // Block
-  lastUDBlock() {
-    return this.blockDAL.lastBlockWithDividend()
-  }
-
-  getRootBlock() {
-    return this.getBlock(0)
-  }
 
   getPotentialRootBlocks() {
     return this.blockDAL.getPotentialRoots()
@@ -265,7 +413,7 @@ export class FileDAL {
   }
 
   getBlocksBetween (start:number, end:number) {
-    return Promise.resolve(this.blockDAL.getBlocks(Math.max(0, start), end))
+    return this.blockDAL.getBlocks(Math.max(0, start), end)
   }
 
   getForkBlocksFollowing(current:DBBlock) {
@@ -287,79 +435,273 @@ export class FileDAL {
     return this.cindexDAL.getValidLinksTo(to)
   }
 
-  getAvailableSourcesByPubkey(pubkey:string) {
-    return this.sindexDAL.getAvailableForPubkey(pubkey)
+  async getAvailableSourcesByPubkey(pubkey:string): Promise<HttpSource[]> {
+    const txAvailable = await this.sindexDAL.getAvailableForPubkey(pubkey)
+    const sources: UDSource[] = await this.dividendDAL.getUDSources(pubkey)
+    return sources.map(d => {
+      return {
+        type: 'D',
+        noffset: d.pos,
+        identifier: pubkey,
+        amount: d.amount,
+        base: d.base,
+        conditions: 'SIG(' + pubkey + ')'
+      }
+    }).concat(txAvailable.map(s => {
+      return {
+        type: 'T',
+        noffset: s.pos,
+        identifier: s.identifier,
+        amount: s.amount,
+        base: s.base,
+        conditions: s.conditions
+      }
+    }))
+  }
+
+  async findByIdentifierPosAmountBase(identifier: string, pos: number, amount: number, base: number, isDividend: boolean): Promise<SimpleTxInput[]> {
+    if (isDividend) {
+      return this.dividendDAL.findUdSourceByIdentifierPosAmountBase(identifier, pos, amount, base)
+    } else {
+      return this.sindexDAL.findTxSourceByIdentifierPosAmountBase(identifier, pos, amount, base)
+    }
+  }
+
+  async getGlobalIdentityByHashForExistence(hash:string): Promise<boolean> {
+    const pending = await this.idtyDAL.getByHash(hash)
+    if (!pending) {
+      const idty = await this.iindexDAL.getFullFromHash(hash)
+      if (!idty) {
+        return false
+      }
+    }
+    return true
+  }
+
+  async getGlobalIdentityByHashForHashingAndSig(hash:string): Promise<{ pubkey:string, uid:string, buid:string, sig:string }|null> {
+    const pending = await this.idtyDAL.getByHash(hash)
+    if (!pending) {
+      const idty = await this.iindexDAL.getFullFromHash(hash)
+      if (!idty) {
+        return null
+      }
+      return {
+        pubkey: idty.pub,
+        uid: idty.uid,
+        buid: idty.created_on,
+        sig: idty.sig
+      }
+    }
+    return pending
+  }
+
+  async getGlobalIdentityByHashForLookup(hash:string): Promise<{ pubkey:string, uid:string, buid:string, sig:string, member:boolean, wasMember:boolean }|null> {
+    const pending = await this.idtyDAL.getByHash(hash)
+    if (!pending) {
+      const idty = await this.iindexDAL.getFullFromHash(hash)
+      if (!idty) {
+        return null
+      }
+      return {
+        pubkey: idty.pub,
+        uid: idty.uid,
+        buid: idty.created_on,
+        sig: idty.sig,
+        member: idty.member,
+        wasMember: idty.wasMember
+      }
+    }
+    return pending
+  }
+
+  async getGlobalIdentityByHashForJoining(hash:string): Promise<{ pubkey:string, uid:string, buid:string, sig:string, member:boolean, wasMember:boolean, revoked:boolean }|null> {
+    const pending = await this.idtyDAL.getByHash(hash)
+    if (!pending) {
+      const idty = await this.iindexDAL.getFullFromHash(hash)
+      if (!idty) {
+        return null
+      }
+      const membership = await this.mindexDAL.getReducedMS(idty.pub) as FullMindexEntry
+      return {
+        pubkey: idty.pub,
+        uid: idty.uid,
+        buid: idty.created_on,
+        sig: idty.sig,
+        member: idty.member,
+        wasMember: idty.wasMember,
+        revoked: !!(membership.revoked_on)
+      }
+    }
+    return pending
+  }
+
+  async getGlobalIdentityByHashForIsMember(hash:string): Promise<{ pub:string, member:boolean }|null> {
+    const pending = await this.idtyDAL.getByHash(hash)
+    if (!pending) {
+      const idty = await this.iindexDAL.getFullFromHash(hash)
+      if (!idty) {
+        return null
+      }
+      return {
+        pub: idty.pub,
+        member: idty.member
+      }
+    }
+    return {
+      pub: pending.pubkey,
+      member: pending.member
+    }
   }
 
-  async getIdentityByHashOrNull(hash:string) {
-    const pending = await this.idtyDAL.getByHash(hash);
+  async getGlobalIdentityByHashForRevocation(hash:string): Promise<{ pub:string, uid:string, created_on:string, sig:string, member:boolean, wasMember:boolean, revoked:boolean, revocation_sig:string|null, expires_on:number }|null> {
+    const pending = await this.idtyDAL.getByHash(hash)
     if (!pending) {
-      return this.iindexDAL.getFromHash(hash);
+      const idty = await this.iindexDAL.getFullFromHash(hash)
+      if (!idty) {
+        return null
+      }
+      const membership = await this.mindexDAL.getReducedMS(idty.pub) as FullMindexEntry
+      return {
+        pub: idty.pub,
+        uid: idty.uid,
+        sig: idty.sig,
+        member: idty.member,
+        wasMember: idty.wasMember,
+        expires_on: membership.expires_on,
+        created_on: idty.created_on,
+        revoked: !!(membership.revoked_on),
+        revocation_sig: membership.revocation
+      }
+    }
+    return {
+      pub: pending.pubkey,
+      uid: pending.uid,
+      sig: pending.sig,
+      expires_on: pending.expires_on,
+      created_on: pending.buid,
+      member: pending.member,
+      wasMember: pending.wasMember,
+      revoked: pending.revoked,
+      revocation_sig: pending.revocation_sig
     }
-    return pending;
   }
 
   getMembers() {
     return this.iindexDAL.getMembers()
   }
 
-  // TODO: this should definitely be reduced by removing fillInMembershipsOfIdentity
-  async getWritten(pubkey:string) {
-    try {
-      return await this.fillInMembershipsOfIdentity(this.iindexDAL.getFromPubkey(pubkey));
-    } catch (err) {
-      logger.error(err);
-      return null;
+  async getWrittenIdtyByPubkeyForHash(pubkey:string): Promise<{ hash:string }> {
+    return this.getWrittenForSureIdtyByPubkey(pubkey)
+  }
+
+  async getWrittenIdtyByPubkeyForHashing(pubkey:string): Promise<{ uid:string, created_on:string, pub:string }> {
+    return this.getWrittenForSureIdtyByPubkey(pubkey)
+  }
+
+  async getWrittenIdtyByPubkeyForWotbID(pubkey:string): Promise<{ wotb_id:number }> {
+    return this.getWrittenForSureIdtyByPubkey(pubkey)
+  }
+
+  async getWrittenIdtyByPubkeyForUidAndPubkey(pubkey:string): Promise<{ pub:string, uid:string }> {
+    return this.getWrittenForSureIdtyByPubkey(pubkey)
+  }
+
+  async getWrittenIdtyByPubkeyForIsMember(pubkey:string): Promise<{ member:boolean }|null> {
+    return this.iindexDAL.getFromPubkey(pubkey)
+  }
+
+  async getWrittenIdtyByPubkeyForUidAndIsMemberAndWasMember(pubkey:string): Promise<{ uid:string, member:boolean, wasMember:boolean }|null> {
+    return this.iindexDAL.getFromPubkey(pubkey)
+  }
+
+  async getWrittenIdtyByPubkeyOrUidForIsMemberAndPubkey(search:string): Promise<{ pub:string, member:boolean }|null> {
+    return this.iindexDAL.getFromPubkeyOrUid(search)
+  }
+
+  async getWrittenIdtyByPubkeyOrUIdForHashingAndIsMember(search:string): Promise<{ uid:string, created_on:string, pub:string, member:boolean }|null> {
+    return await this.iindexDAL.getFromPubkeyOrUid(search)
+  }
+
+  async getWrittenIdtyByPubkeyForRevocationCheck(pubkey:string): Promise<{ pub:string, uid:string, created_on:string, sig:string, revoked_on:number|null }|null> {
+    const idty = await this.iindexDAL.getFromPubkey(pubkey)
+    if (!idty) {
+      return null
+    }
+    const membership = await this.mindexDAL.getReducedMS(pubkey) as FullMindexEntry
+    return {
+      pub: idty.pub,
+      uid: idty.uid,
+      sig: idty.sig,
+      created_on: idty.created_on,
+      revoked_on: membership.revoked_on
     }
   }
 
-  async getWrittenIdtyByPubkey(pubkey:string) {
+  async getWrittenIdtyByPubkeyForCertificationCheck(pubkey:string): Promise<{ pub:string, uid:string, created_on:string, sig:string }|null> {
     const idty = await this.iindexDAL.getFromPubkey(pubkey)
     if (!idty) {
-      return null;
+      return null
+    }
+    return {
+      pub: idty.pub,
+      uid: idty.uid,
+      sig: idty.sig,
+      created_on: idty.created_on,
     }
-    const membership = await this.mindexDAL.getReducedMS(pubkey)
-    idty.revoked_on = membership.revoked_on
-    return idty;
   }
 
-  async getWrittenIdtyByUID(uid:string) {
-    const idty = await this.iindexDAL.getFromUID(uid)
+  async getWrittenIdtyByPubkeyForUidAndMemberAndCreatedOn(pubkey:string): Promise<{ uid:string, member:boolean, created_on:string }|null> {
+    const idty = await this.iindexDAL.getFromPubkey(pubkey)
     if (!idty) {
-      return null;
+      return null
+    }
+    return {
+      uid: idty.uid,
+      member: idty.member,
+      created_on: idty.created_on,
     }
-    const membership = await this.mindexDAL.getReducedMS(idty.pub)
-    idty.revoked_on = membership.revoked_on
-    return idty;
   }
 
-  async fillInMembershipsOfIdentity(queryPromise:Promise<DBIdentity>) {
-    try {
-      const idty:any = await Promise.resolve(queryPromise)
-      if (idty) {
-        const mss = await this.msDAL.getMembershipsOfIssuer(idty.pubkey);
-        const mssFromMindex = await this.mindexDAL.reducable(idty.pubkey);
-        idty.memberships = mss.concat(mssFromMindex.map((ms:MindexEntry) => {
-          const sp = ms.created_on.split('-');
-          return {
-            blockstamp: ms.created_on,
-            membership: ms.leaving ? 'OUT' : 'IN',
-            number: sp[0],
-            fpr: sp[1],
-            written_number: parseInt(ms.written_on)
-          }
-        }));
-        return idty;
-      }
-    } catch (err) {
-      logger.error(err);
+  private async getWrittenForSureIdtyByPubkey(pubkey:string) {
+    const idty = await this.iindexDAL.getFromPubkey(pubkey)
+    if (!idty) {
+      throw Error(DataErrors[DataErrors.MEMBER_NOT_FOUND])
     }
-    return null;
+    return idty
+  }
+
+  private async getWrittenForSureIdtyByUid(pubkey:string) {
+    const idty = (await this.iindexDAL.getFullFromUID(pubkey))
+    if (!idty) {
+      throw Error(DataErrors[DataErrors.MEMBER_NOT_FOUND])
+    }
+    return idty
+  }
+
+  // Duniter-UI dependency
+  async getWrittenIdtyByPubkey(pub:string): Promise<FullIindexEntry | null> {
+    return await this.iindexDAL.getFromPubkey(pub)
+  }
+
+  async getWrittenIdtyByPubkeyForExistence(uid:string) {
+    return !!(await this.iindexDAL.getFromPubkey(uid))
+  }
+
+  async getWrittenIdtyByUIDForExistence(uid:string) {
+    return !!(await this.iindexDAL.getFromUID(uid))
+  }
+
+  async getWrittenIdtyByUidForHashing(uid:string): Promise<{ uid:string, created_on:string, pub:string }> {
+    return this.getWrittenForSureIdtyByUid(uid)
+  }
+
+  async getWrittenIdtyByUIDForWotbId(uid:string): Promise<{ wotb_id:number }> {
+    return this.getWrittenForSureIdtyByUid(uid)
   }
 
   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) {
@@ -376,15 +718,15 @@ 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() {
     const revoking = await this.idtyDAL.getToRevoke();
     const toRevoke = [];
     for (const pending of revoking) {
-      const idty = await this.getWrittenIdtyByPubkey(pending.pubkey);
-      if (!idty.revoked_on) {
+      const idty = await this.getWrittenIdtyByPubkeyForRevocationCheck(pending.pubkey)
+      if (idty && !idty.revoked_on) {
         toRevoke.push(pending);
       }
     }
@@ -399,21 +741,21 @@ 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 ? parseInt(ms.revoked_on) : null;
+        f.revoked_on = ms.revoked_on ? ms.revoked_on : null;
         f.revoked = !!f.revoked_on;
         f.revocation_sig = ms.revocation || null;
       }
@@ -426,19 +768,9 @@ export class FileDAL {
     const links = await this.cindexDAL.getValidLinksTo(pub);
     let matching = certs;
     await Promise.all(links.map(async (entry:any) => {
-      entry.from = entry.issuer;
-      const wbt = entry.written_on.split('-');
-      const blockNumber = parseInt(entry.created_on); // created_on field of `c_index` does not have the full blockstamp
-      const basedBlock = await this.getBlock(blockNumber);
-      entry.block = blockNumber;
-      entry.block_number = blockNumber;
-      entry.block_hash = basedBlock ? basedBlock.hash : null;
-      entry.linked = true;
-      entry.written_block = parseInt(wbt[0]);
-      entry.written_hash = wbt[1];
-      matching.push(entry);
+      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;
   }
@@ -447,26 +779,36 @@ export class FileDAL {
     const certs = await this.certDAL.getFromPubkeyCerts(pubkey);
     const links = await this.cindexDAL.getValidLinksFrom(pubkey);
     let matching = certs;
-    await Promise.all(links.map(async (entry:any) => {
-      const idty = await this.getWrittenIdtyByPubkey(entry.receiver);
-      entry.from = entry.issuer;
-      entry.to = entry.receiver;
-      const cbt = entry.created_on.split('-');
-      const wbt = entry.written_on.split('-');
-      entry.block = parseInt(cbt[0]);
-      entry.block_number = parseInt(cbt[0]);
-      entry.block_hash = cbt[1];
-      entry.target = idty.hash;
-      entry.linked = true;
-      entry.written_block = parseInt(wbt[0]);
-      entry.written_hash = wbt[1];
-      matching.push(entry);
+    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;
   }
 
+  async cindexEntry2DBCert(entry:CindexEntry): Promise<DBCert> {
+    const idty = await this.getWrittenIdtyByPubkeyForHash(entry.receiver)
+    const wbt = entry.written_on.split('-')
+    const block = (await this.blockDAL.getBlock(entry.created_on)) as DBBlock
+    return {
+      issuers: [entry.issuer],
+      linked: true,
+      written: true,
+      written_block: parseInt(wbt[0]),
+      written_hash: wbt[1],
+      sig: entry.sig,
+      block_number: block.number,
+      block_hash: block.hash,
+      target: idty.hash,
+      to: entry.receiver,
+      from: entry.issuer,
+      block: block.number,
+      expired: !!entry.expired_on,
+      expires_on: entry.expires_on,
+    }
+  }
+
   async isSentry(pubkey:string, conf:ConfDTO) {
     const current = await this.getCurrentBlockOrNull();
     if (current) {
@@ -480,12 +822,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) {
@@ -500,36 +842,34 @@ 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) {
+  async findNewcomers(blockMedianTime = 0): Promise<DBMembership[]> {
     const pending = await this.msDAL.getPendingIN()
-    const mss = await Promise.all(pending.map(async (p:any) => {
+    const mss: DBMembership[] = await Promise.all<DBMembership>(pending.map(async (p:any) => {
       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:any) => ms)
-      .sortBy((ms:any) => -ms.sigDate)
+    return Underscore.chain(Underscore.filter(mss, ms => !!ms) as DBMembership[])
+      .sortBy((ms:DBMembership) => -ms.blockNumber)
       .value()
   }
 
-  async findLeavers(blockMedianTime = 0) {
+  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:any) => ms)
-      .sortBy((ms:any) => -ms.sigDate)
+    return Underscore.chain(Underscore.filter(mss, ms => !!ms) as DBMembership[])
+      .sortBy(ms => -ms.blockNumber)
       .value();
   }
 
@@ -537,8 +877,12 @@ export class FileDAL {
     return  this.cindexDAL.existsNonReplayableLink(from, to)
   }
 
-  getSource(identifier:string, pos:number) {
-    return this.sindexDAL.getSource(identifier, pos)
+  async getSource(identifier:string, pos:number, isDividend: boolean): Promise<SimpleTxInput | null> {
+    if (isDividend) {
+      return this.dividendDAL.getUDSource(identifier, pos)
+    } else {
+      return this.sindexDAL.getTxSource(identifier, pos)
+    }
   }
 
   async isMember(pubkey:string):Promise<boolean> {
@@ -586,15 +930,17 @@ export class FileDAL {
   }
 
   async setRevoked(pubkey:string) {
-    const idty = await this.getWrittenIdtyByPubkey(pubkey);
-    idty.revoked = true;
-    return await this.idtyDAL.saveIdentity(idty);
+    return await this.idtyDAL.setRevoked(pubkey)
   }
 
-  setRevocating = (existing:DBIdentity, revocation_sig:string) => {
-    existing.revocation_sig = revocation_sig;
-    existing.revoked = false;
-    return this.idtyDAL.saveIdentity(existing);
+  setRevocating = (idty:BasicRevocableIdentity, revocation_sig:string) => {
+    const dbIdentity = IdentityDTO.fromBasicIdentity(idty)
+    dbIdentity.member = idty.member
+    dbIdentity.wasMember = idty.wasMember
+    dbIdentity.expires_on = idty.expires_on
+    dbIdentity.revocation_sig = revocation_sig
+    dbIdentity.revoked = false
+    return this.idtyDAL.saveIdentity(dbIdentity)
   }
 
   async getPeerOrNull(pubkey:string) {
@@ -621,17 +967,17 @@ 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) {
+  async findPeers(pubkey:string): Promise<DBPeer[]> {
     try {
       const peer = await this.getPeer(pubkey);
       return [peer];
@@ -640,9 +986,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) {
@@ -677,27 +1023,29 @@ export class FileDAL {
     }
   }
 
-  async saveBlock(block:BlockDTO) {
-    const dbb = DBBlock.fromBlockDTO(block)
+  async saveBlock(dbb:DBBlock) {
     dbb.wrong = false;
     await Promise.all([
       this.saveBlockInFile(dbb),
-      this.saveTxsInFiles(block.transactions, block.number, block.medianTime)
+      this.saveTxsInFiles(dbb.transactions, dbb.number, dbb.medianTime)
     ])
   }
 
-  async generateIndexes(block:DBBlock, conf:ConfDTO, index:IndexEntry[], HEAD:DBHead) {
+  async generateIndexes(block:BlockDTO, conf:ConfDTO, index:IndexEntry[], aHEAD:DBHead|null) {
     // We need to recompute the indexes for block#0
-    if (!index || !HEAD || HEAD.number == 0) {
+    let HEAD:DBHead
+    if (!index || !aHEAD || aHEAD.number == 0) {
       index = indexer.localIndex(block, conf)
       HEAD = await indexer.completeGlobalScope(block, conf, index, this)
+    } else {
+      HEAD = aHEAD
     }
     let mindex = indexer.mindex(index);
     let iindex = indexer.iindex(index);
     let sindex = indexer.sindex(index);
     let cindex = indexer.cindex(index);
-    sindex = sindex.concat(await indexer.ruleIndexGenDividend(HEAD, iindex, this));
-    sindex = sindex.concat(await indexer.ruleIndexGarbageSmallAccounts(HEAD, sindex, this));
+    const dividends = await indexer.ruleIndexGenDividend(HEAD, iindex, this) // Requires that newcomers are already in DividendDAO
+    sindex = sindex.concat(await indexer.ruleIndexGarbageSmallAccounts(HEAD, sindex, dividends, this));
     cindex = cindex.concat(await indexer.ruleIndexGenCertificationExpiry(HEAD, this));
     mindex = mindex.concat(await indexer.ruleIndexGenMembershipExpiry(HEAD, this));
     iindex = iindex.concat(await indexer.ruleIndexGenExclusionByMembership(HEAD, mindex, this));
@@ -705,32 +1053,36 @@ export class FileDAL {
     mindex = mindex.concat(await indexer.ruleIndexGenImplicitRevocation(HEAD, this));
     await indexer.ruleIndexCorrectMembershipExpiryDate(HEAD, mindex, this);
     await indexer.ruleIndexCorrectCertificationExpiryDate(HEAD, cindex, this);
-    return { HEAD, mindex, iindex, sindex, cindex };
+    return { HEAD, mindex, iindex, sindex, cindex, dividends };
   }
 
   async updateWotbLinks(cindex:CindexEntry[]) {
     for (const entry of cindex) {
-      const from = await this.getWrittenIdtyByPubkey(entry.issuer);
-      const to = await this.getWrittenIdtyByPubkey(entry.receiver);
+      const from = await this.getWrittenIdtyByPubkeyForWotbID(entry.issuer);
+      const to = await this.getWrittenIdtyByPubkeyForWotbID(entry.receiver);
       if (entry.op == CommonConstants.IDX_CREATE) {
+        // NewLogger().trace('addLink %s -> %s', from.wotb_id, to.wotb_id)
         this.wotb.addLink(from.wotb_id, to.wotb_id);
       } else {
         // Update = removal
+        NewLogger().trace('removeLink %s -> %s', from.wotb_id, to.wotb_id)
         this.wotb.removeLink(from.wotb_id, to.wotb_id);
       }
     }
   }
 
   async trimIndexes(maxNumber:number) {
-    await this.bindexDAL.trimBlocks(maxNumber);
-    await this.iindexDAL.trimRecords(maxNumber);
-    await this.mindexDAL.trimRecords(maxNumber);
-    await this.cindexDAL.trimExpiredCerts(maxNumber);
-    await this.sindexDAL.trimConsumedSource(maxNumber);
-    return true;
+    if (!cliprogram.notrim) {
+      await this.bindexDAL.trimBlocks(maxNumber)
+      await this.iindexDAL.trimRecords(maxNumber)
+      await this.mindexDAL.trimRecords(maxNumber)
+      await this.cindexDAL.trimExpiredCerts(maxNumber)
+    }
+    await this.sindexDAL.trimConsumedSource(maxNumber)
+    await this.dividendDAL.trimConsumedUDs(maxNumber)
   }
 
-  async trimSandboxes(block:DBBlock) {
+  async trimSandboxes(block:{ medianTime: number }) {
     await this.certDAL.trimExpiredCerts(block.medianTime);
     await this.msDAL.trimExpiredMemberships(block.medianTime);
     await this.idtyDAL.trimExpiredIdentities(block.medianTime);
@@ -753,7 +1105,8 @@ export class FileDAL {
   async saveTxsInFiles(txs:TransactionDTO[], block_number:number, medianTime:number) {
     return Promise.all(txs.map(async (tx) => {
       const sp = tx.blockstamp.split('-');
-      tx.blockstampTime = (await this.getBlockByNumberAndHash(parseInt(sp[0]), sp[1])).medianTime;
+      const basedBlock = (await this.getAbsoluteBlockByNumberAndHash(parseInt(sp[0]), sp[1])) as DBBlock
+      tx.blockstampTime = basedBlock.medianTime;
       const txEntity = TransactionDTO.fromJSONObject(tx)
       txEntity.computeAllHashes();
       return this.txsDAL.addLinked(TransactionDTO.fromJSONObject(txEntity), block_number, medianTime);
@@ -768,14 +1121,6 @@ export class FileDAL {
     return merkle;
   }
 
-  removeAllSourcesOfBlock(blockstamp:string) {
-    return this.sindexDAL.removeBlock(blockstamp)
-  }
-
-  updateTransactions(txs:DBTx[]) {
-    return this.txsDAL.insertBatchOfTxs(txs)
-  }
-
   savePendingIdentity(idty:DBIdentity) {
     return this.idtyDAL.saveIdentity(idty)
   }
@@ -827,13 +1172,19 @@ export class FileDAL {
     return history;
   }
 
-  async getUDHistory(pubkey:string) {
-    const sources = await this.sindexDAL.getUDSources(pubkey)
+  async getUDHistory(pubkey:string): Promise<{ history: HttpUD[] }> {
+    const sources: UDSource[] = await this.dividendDAL.getUDSources(pubkey)
     return {
-      history: sources.map((src:SindexEntry) => _.extend({
-        block_number: src.pos,
-        time: src.written_time
-      }, src))
+      history: (await Promise.all<HttpUD>(sources.map(async (src) => {
+        const block = await this.getBlockWeHaveItForSure(src.pos)
+        return {
+          block_number: src.pos,
+          time: block.medianTime,
+          consumed: src.consumed,
+          amount: src.amount,
+          base: src.base
+        }
+      })))
     }
   }
 
@@ -842,11 +1193,11 @@ export class FileDAL {
   }
 
   async getUniqueIssuersBetween(start:number, end:number) {
-    const current = await this.blockDAL.getCurrent();
+    const current = (await this.blockDAL.getCurrent()) as DBBlock
     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))
   }
 
   /**
@@ -884,11 +1235,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) {
@@ -938,11 +1289,11 @@ export class FileDAL {
   }
 
   async cleanCaches() {
-    await _.values(this.newDals).map((dal:any) => dal.cleanCache && dal.cleanCache())
+    await Underscore.values(this.newDals).map((dal:Initiable) => dal.cleanCache && dal.cleanCache())
   }
 
   async close() {
-    await _.values(this.newDals).map((dal:any) => dal.cleanCache && dal.cleanCache())
+    await Underscore.values(this.newDals).map((dal:Initiable) => dal.cleanCache && dal.cleanCache())
     return this.sqliteDriver.closeConnection();
   }
 
@@ -974,4 +1325,41 @@ export class FileDAL {
       }
     })
   }
+
+  async findReceiversAbove(minsig: number) {
+    const receiversAbove:string[] = await this.cindexDAL.getReceiversAbove(minsig)
+    const members:IdentityForRequirements[] = []
+    for (const r of receiversAbove) {
+      const i = await this.iindexDAL.getFullFromPubkey(r)
+      members.push({
+        hash: i.hash || "",
+        member: i.member || false,
+        wasMember: i.wasMember || false,
+        pubkey: i.pub,
+        uid: i.uid || "",
+        buid: i.created_on || "",
+        sig: i.sig || "",
+        revocation_sig: "",
+        revoked: false,
+        revoked_on: 0
+      })
+    }
+    return members
+  }
+
+  @MonitorFlushedIndex()
+  async flushIndexes(indexes: IndexBatch) {
+    await this.mindexDAL.insertBatch(indexes.mindex)
+    await this.iindexDAL.insertBatch(indexes.iindex)
+    await this.sindexDAL.insertBatch(indexes.sindex.filter(s => s.srcType === 'T')) // We don't store dividends in SINDEX
+    await this.cindexDAL.insertBatch(indexes.cindex)
+    await this.dividendDAL.consume(indexes.sindex.filter(s => s.srcType === 'D'))
+  }
+
+  async updateDividend(blockNumber: number, dividend: number|null, unitbase: number, local_iindex: IindexEntry[]): Promise<SimpleUdEntryForWallet[]> {
+    if (dividend) {
+      return this.dividendDAL.produceDividend(blockNumber, dividend, unitbase, local_iindex)
+    }
+    return []
+  }
 }
diff --git a/app/lib/dal/fileDALs/AbstractCFS.ts b/app/lib/dal/fileDALs/AbstractCFS.ts
index c03ccb0e5e75909760baa9e24cf3273af245bd58..128a441af4ad55135ca8425267ff347a4388e713 100644
--- a/app/lib/dal/fileDALs/AbstractCFS.ts
+++ b/app/lib/dal/fileDALs/AbstractCFS.ts
@@ -12,13 +12,20 @@
 // GNU Affero General Public License for more details.
 
 import {CFSCore} from "./CFSCore";
+import {Initiable} from "../sqliteDAL/Initiable"
+import {FileSystem} from "../../system/directory"
+import {FileDAL} from "../fileDAL"
 
-export class AbstractCFS {
+export abstract class AbstractCFS extends Initiable {
 
-  protected coreFS:CFSCore
-  protected dal:any
+  public coreFS:CFSCore
+  protected dal:FileDAL
 
-  constructor(rootPath:string, qioFS:any) {
+  constructor(rootPath:string, qioFS:FileSystem) {
+    super()
     this.coreFS = new CFSCore(rootPath, qioFS)
   }
+
+  cleanCache() {
+  }
 }
diff --git a/app/lib/dal/fileDALs/CFSCore.ts b/app/lib/dal/fileDALs/CFSCore.ts
index 0de15b707aeac9ac09001b410647699bd4ffd810..019155abe5149360d5199937a4de0f9a48732919 100644
--- a/app/lib/dal/fileDALs/CFSCore.ts
+++ b/app/lib/dal/fileDALs/CFSCore.ts
@@ -13,7 +13,9 @@
 
 "use strict";
 
-const _ = require('underscore');
+import {FileSystem} from "../../system/directory"
+import {Underscore} from "../../common-libs/underscore"
+
 const path = require('path');
 
 const DEEP_WRITE = true;
@@ -24,7 +26,7 @@ export class CFSCore {
   private deletionFolderPromise: Promise<any> | null
   private createDeletionFolder: () => Promise<any> | null
 
-  constructor(private rootPath:string, private qfs:any) {
+  constructor(private rootPath:string, private qfs:FileSystem) {
     this.deletedFolder = path.join(rootPath, '.deleted')
     this.deletionFolderPromise = null
 
@@ -42,12 +44,12 @@ export class CFSCore {
    */
   async read(filePath:string): Promise<string | null> {
     try {
-      const isDeleted = await this.qfs.exists(path.join(this.deletedFolder, this.toRemoveFileName(filePath)));
+      const isDeleted = await this.qfs.fsExists(path.join(this.deletedFolder, this.toRemoveFileName(filePath)));
       if (isDeleted) {
         // A deleted file must be considered non-existant
         return null;
       }
-      return await this.qfs.read(path.join(this.rootPath, filePath));
+      return await this.qfs.fsReadFile(path.join(this.rootPath, filePath));
     } catch (e) {
       return null
     }
@@ -60,12 +62,12 @@ export class CFSCore {
    */
   async exists(filePath:string): Promise<boolean | null> {
     try {
-      const isDeleted = await this.qfs.exists(path.join(this.deletedFolder, this.toRemoveFileName(filePath)));
+      const isDeleted = await this.qfs.fsExists(path.join(this.deletedFolder, this.toRemoveFileName(filePath)));
       if (isDeleted) {
         // A deleted file must be considered non-existant
         return false;
       }
-      return await this.qfs.exists(path.join(this.rootPath, filePath))
+      return await this.qfs.fsExists(path.join(this.rootPath, filePath))
     } catch (e) {
       return null
     }
@@ -80,19 +82,19 @@ export class CFSCore {
   async list(ofPath:string): Promise<string[]> {
     const dirPath = path.normalize(ofPath);
     let files: string[] = [], folder = path.join(this.rootPath, dirPath);
-    const hasDir = await this.qfs.exists(folder);
+    const hasDir = await this.qfs.fsExists(folder);
     if (hasDir) {
-      files = files.concat(await this.qfs.list(folder));
+      files = files.concat(await this.qfs.fsList(folder));
     }
-    const hasDeletedFiles = await this.qfs.exists(this.deletedFolder);
+    const hasDeletedFiles = await this.qfs.fsExists(this.deletedFolder);
     if (hasDeletedFiles) {
-      const deletedFiles = await this.qfs.list(this.deletedFolder);
+      const deletedFiles = await this.qfs.fsList(this.deletedFolder);
       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)
   };
 
   /**
@@ -102,7 +104,7 @@ export class CFSCore {
    * @param deep Wether to make a deep write or not.
    */
   async write(filePath:string, content:string, deep:boolean): Promise<void> {
-    return this.qfs.write(path.join(this.rootPath, filePath), content);
+    return this.qfs.fsWrite(path.join(this.rootPath, filePath), content);
   };
 
   /**
@@ -111,10 +113,10 @@ export class CFSCore {
    * @param deep Wether to remove the file in the root core or not.
    * @returns {*} Promise of removal.
    */
-  async remove(filePath:string, deep:boolean): Promise<void> {
+  async remove(filePath:string, deep = false): Promise<void> {
     // Make a deep physical deletion
     // Root core: physical deletion
-    return this.qfs.remove(path.join(this.rootPath, filePath));
+    await this.qfs.fsUnlink(path.join(this.rootPath, filePath));
   }
 
   /**
@@ -138,9 +140,9 @@ export class CFSCore {
       let folder = this.rootPath;
       for (let i = 0, len = folders.length; i < len; i++) {
         folder = folder ? path.join(folder, folders[i]) : folders[i];
-        let exists = await this.qfs.exists(folder);
+        let exists = await this.qfs.fsExists(folder);
         if (!exists) {
-          await this.qfs.makeDirectory(folder);
+          await this.qfs.fsMakeDirectory(folder);
         }
       }
     } catch (e) {
@@ -225,4 +227,8 @@ export class CFSCore {
   private toRemoveFileName(filePath:string) {
     return path.normalize(filePath).replace(/\//g, '__').replace(/\\/g, '__');
   }
+
+  fsStreamTo(filename: string, iterator: IterableIterator<string>) {
+    return this.qfs.fsStreamTo(path.join(this.rootPath, filename), iterator)
+  }
 }
diff --git a/app/lib/dal/fileDALs/ConfDAL.ts b/app/lib/dal/fileDALs/ConfDAL.ts
index 1fa90e1482b5fe29c177c819cea9c0df9dce8a43..f42197b7ef4a9200bf0909f268cee68df822a465 100644
--- a/app/lib/dal/fileDALs/ConfDAL.ts
+++ b/app/lib/dal/fileDALs/ConfDAL.ts
@@ -14,14 +14,14 @@
 import {AbstractCFS} from "./AbstractCFS"
 import {ConfDTO} from "../../dto/ConfDTO"
 import {CommonConstants} from "../../common-libs/constants";
-
-const _ = require('underscore');
+import {FileSystem} from "../../system/directory"
+import {Underscore} from "../../common-libs/underscore"
 
 export class ConfDAL extends AbstractCFS {
 
   private logger:any
 
-  constructor(rootPath:string, qioFS:any) {
+  constructor(rootPath:string, qioFS:FileSystem) {
     super(rootPath, qioFS)
     this.logger = require('../../logger').NewLogger()
   }
@@ -61,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/PowDAL.ts b/app/lib/dal/fileDALs/PowDAL.ts
index eaba6594d4243fc2b7bec5551887c167a54fc527..095bb9f4117f02b8d6b38f95dbf9eece8bfb3eba 100644
--- a/app/lib/dal/fileDALs/PowDAL.ts
+++ b/app/lib/dal/fileDALs/PowDAL.ts
@@ -12,12 +12,13 @@
 // GNU Affero General Public License for more details.
 
 import {AbstractCFS} from "./AbstractCFS"
+import {FileSystem} from "../../system/directory"
 
 export class PowDAL extends AbstractCFS {
 
   private static POW_FILE = "pow.txt"
 
-  constructor(rootPath:string, qioFS:any) {
+  constructor(rootPath:string, qioFS:FileSystem) {
     super(rootPath, qioFS)
   }
 
diff --git a/app/lib/dal/fileDALs/StatDAL.ts b/app/lib/dal/fileDALs/StatDAL.ts
index 1e913c5fe57558c051c3fd611de5d143ed264fc2..96f03e5444b18cc43e31047097606a056e105b79 100644
--- a/app/lib/dal/fileDALs/StatDAL.ts
+++ b/app/lib/dal/fileDALs/StatDAL.ts
@@ -12,12 +12,12 @@
 // GNU Affero General Public License for more details.
 
 import {AbstractCFS} from "./AbstractCFS";
-import {CFSCore} from "./CFSCore";
-const _ = require('underscore');
+import {FileSystem} from "../../system/directory"
+import {Underscore} from "../../common-libs/underscore"
 
 export class StatDAL extends AbstractCFS {
 
-  constructor(rootPath:string, qioFS:any) {
+  constructor(rootPath:string, qioFS:FileSystem) {
     super(rootPath, qioFS)
   }
 
@@ -39,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/CFSBlockchainArchive.ts b/app/lib/dal/indexDAL/CFSBlockchainArchive.ts
new file mode 100644
index 0000000000000000000000000000000000000000..361315590e00ef203f419e12c7162ff34484c32a
--- /dev/null
+++ b/app/lib/dal/indexDAL/CFSBlockchainArchive.ts
@@ -0,0 +1,123 @@
+import {BlockchainArchiveDAO, BlockLike} from "./abstract/BlockchainArchiveDAO"
+import {CFSCore} from "../fileDALs/CFSCore"
+
+export class CFSBlockchainArchive<T extends BlockLike> implements BlockchainArchiveDAO<T> {
+
+  constructor(private cfs:CFSCore, private _chunkSize:number) {
+  }
+
+  async archive(records: T[]): Promise<number> {
+    if (!this.checkBlocksRepresentChunks(records)) {
+      return 0
+    }
+    if (!this.checkBlocksAreWellChained(records)) {
+      return 0
+    }
+    const chunks = this.splitIntoChunks(records)
+    for (const c of chunks) {
+      const fileName = this.getFileName(c[0].number)
+      await this.cfs.writeJSON(fileName, c)
+    }
+    return chunks.length
+  }
+
+  private checkBlocksRepresentChunks(records: BlockLike[]): boolean {
+    return !(records[0].number % this._chunkSize !== 0 || (records[records.length - 1].number + 1) % this._chunkSize !== 0)
+
+  }
+
+  private checkBlocksAreWellChained(records: T[]): boolean {
+    let previous:BlockLike = {
+      number: records[0].number - 1,
+      hash: records[0].previousHash,
+      previousHash: ''
+    }
+    for (const b of records) {
+      if (b.previousHash !== previous.hash || b.number !== previous.number + 1) {
+        return false
+      }
+      previous = b
+    }
+    return true
+  }
+
+  private splitIntoChunks(records: T[]): T[][] {
+    const nbChunks = records.length / this._chunkSize
+    const chunks: T[][] = []
+    for (let i = 0; i < nbChunks; i++) {
+      chunks.push(records.slice(i * this._chunkSize, (i + 1) * this._chunkSize))
+    }
+    return chunks
+  }
+
+  async getBlock(number: number, hash: string): Promise<T|null> {
+    const block = await this.getBlockByNumber(number)
+    if (!block) {
+      return null
+    }
+    return block.hash === hash ? block : null
+  }
+
+  async getBlockByNumber(number: number): Promise<T|null> {
+    if (number < 0) {
+      return null
+    }
+    const content = await this.getChunk(number)
+    if (!content) {
+      // The block's chunk is not archived
+      return null
+    }
+    return content[this.getPositionInChunk(number)]
+  }
+
+  async getChunk(number:number): Promise<(T[])|null> {
+    const file = this.getFileName(number)
+    return this.cfs.readJSON(file)
+  }
+
+  async getLastSavedBlock(): Promise<T | null> {
+    const list = await this.cfs.list('/')
+    const max = list
+      .map(f => f.replace(`chunk_`, ''))
+      .map(f => f.replace(`-${this._chunkSize}.json`, ''))
+      .map(f => parseInt(f))
+      .reduce((v, max) => {
+        return Math.max(v, max)
+      }, 0)
+    const content = await this.getChunk(max * this._chunkSize)
+    if (!content) {
+      return null
+    }
+    return this.getBlock(content[content.length - 1].number, content[content.length - 1].hash)
+  }
+
+  private getFileName(number:number) {
+    const rest = number % this._chunkSize
+    const chunk = (number - rest) / this._chunkSize
+    return CFSBlockchainArchive.getChunkName(chunk, this._chunkSize)
+  }
+
+  private static getChunkName(chunkNumber:number, chunkSize:number) {
+    return `chunk_${chunkNumber}-${chunkSize}.json`
+  }
+
+  private getPositionInChunk(number:number) {
+    return number % this._chunkSize
+  }
+
+  async init(): Promise<void> {
+    return this.cfs.makeTree('/')
+  }
+
+  triggerInit(): void {
+    // TODO: remove triggerInit from all the DAOs, it is a wrong implementation
+  }
+
+  cleanCache(): void {
+    // TODO: is it really useful?
+  }
+
+  get chunkSize(): number {
+    return this._chunkSize
+  }
+}
diff --git a/app/lib/dal/indexDAL/abstract/BIndexDAO.ts b/app/lib/dal/indexDAL/abstract/BIndexDAO.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8ca8ff55a0f6b0d737a7000b8fcf07ea44ae551b
--- /dev/null
+++ b/app/lib/dal/indexDAL/abstract/BIndexDAO.ts
@@ -0,0 +1,13 @@
+import {GenericDAO} from "./GenericDAO"
+import {DBHead} from "../../../db/DBHead"
+
+export interface BIndexDAO extends GenericDAO<DBHead> {
+
+  head(n:number): Promise<DBHead> // TODO: possibly null?
+
+  tail(): Promise<DBHead> // TODO: possibly null?
+
+  range(n:number, m:number): Promise<DBHead[]>
+
+  trimBlocks(maxnumber:number): Promise<void>
+}
diff --git a/app/lib/dal/indexDAL/abstract/BlockchainArchiveDAO.ts b/app/lib/dal/indexDAL/abstract/BlockchainArchiveDAO.ts
new file mode 100644
index 0000000000000000000000000000000000000000..123c169ea4c9aa6d44d9f33e6e7430ea9d0e27d5
--- /dev/null
+++ b/app/lib/dal/indexDAL/abstract/BlockchainArchiveDAO.ts
@@ -0,0 +1,48 @@
+import {Initiable} from "../../sqliteDAL/Initiable"
+import {DBBlock} from "../../../db/DBBlock"
+
+export interface BlockLike {
+  number:number
+  hash:string
+  previousHash:string
+}
+
+export interface BlockchainArchiveDAO<T extends BlockLike> extends Initiable {
+
+  /**
+   * Trigger the initialization of the DAO. Called when the underlying DB is ready.
+   */
+  triggerInit(): void
+
+  /**
+   * Retrieves a block from the archives.
+   * @param {number} number Block number.
+   * @param {string} hash Block hash.
+   * @returns {Promise<DBBlock>}
+   */
+  getBlock(number:number, hash:string): Promise<T|null>
+
+  /**
+   * Retrieves a block from the archives, without checking the hash.
+   * @param {number} number Block number.
+   * @returns {Promise<DBBlock>}
+   */
+  getBlockByNumber(number:number): Promise<T|null>
+
+  /**
+   * Archives a suite of blocks.
+   *
+   * Throws an exception is blocks does not follow each other, or does not follow previously archived blocks.
+   * @param {DBBlock[]} records The blocks to archive.
+   * @returns {Promise<void>}
+   */
+  archive(records:T[]): Promise<number>
+
+  /**
+   * Retrieve the last block (maximum number) that was archived.
+   * @returns {Promise<BlockLike | null>}
+   */
+  getLastSavedBlock(): Promise<T|null>
+
+  readonly chunkSize:number
+}
diff --git a/app/lib/dal/indexDAL/abstract/BlockchainDAO.ts b/app/lib/dal/indexDAL/abstract/BlockchainDAO.ts
new file mode 100644
index 0000000000000000000000000000000000000000..47a5927b5c119e7bc9c283e12248e8b37f8e0dfe
--- /dev/null
+++ b/app/lib/dal/indexDAL/abstract/BlockchainDAO.ts
@@ -0,0 +1,43 @@
+import {GenericDAO} from "./GenericDAO"
+import {DBBlock} from "../../../db/DBBlock"
+
+export interface BlockchainDAO extends GenericDAO<DBBlock> {
+
+  getCurrent(): Promise<DBBlock|null>
+
+  getBlock(number:string | number): Promise<DBBlock|null>
+
+  getAbsoluteBlock(number:number, hash:string): Promise<DBBlock|null>
+
+  saveBlock(block:DBBlock): Promise<DBBlock>
+
+  saveSideBlock(block:DBBlock): Promise<DBBlock>
+
+  getPotentialRoots(): Promise<DBBlock[]>
+
+  getBlocks(start:number, end:number): Promise<DBBlock[]>
+
+  getNextForkBlocks(number:number, hash:string): Promise<DBBlock[]>
+
+  getPotentialForkBlocks(numberStart:number, medianTimeStart:number, maxNumber:number): Promise<DBBlock[]>
+
+  lastBlockOfIssuer(issuer:string): Promise<DBBlock|null>
+
+  lastBlockWithDividend(): Promise<DBBlock|null>
+
+  getCountOfBlocksIssuedBy(issuer:string): Promise<number>
+
+  saveBunch(blocks:DBBlock[]): Promise<void>
+
+  dropNonForkBlocksAbove(number: number): Promise<void>
+
+  setSideBlock(number:number, previousBlock:DBBlock|null): Promise<void>
+
+  removeForkBlock(number:number): Promise<void>
+
+  removeForkBlockAboveOrEqual(number:number): Promise<void>
+
+  trimBlocks(number:number): Promise<void>
+
+  getNonForkChunk(start:number, end:number): Promise<DBBlock[]>
+}
diff --git a/app/lib/dal/indexDAL/abstract/CIndexDAO.ts b/app/lib/dal/indexDAL/abstract/CIndexDAO.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c507c2d47412e0a135447f58c9d405453784af1b
--- /dev/null
+++ b/app/lib/dal/indexDAL/abstract/CIndexDAO.ts
@@ -0,0 +1,26 @@
+import {CindexEntry, FullCindexEntry} from "../../../indexer"
+import {ReduceableDAO} from "./ReduceableDAO"
+
+export interface CIndexDAO extends ReduceableDAO<CindexEntry> {
+
+  getValidLinksTo(receiver:string): Promise<CindexEntry[]>
+
+  getValidLinksFrom(issuer:string): Promise<CindexEntry[]>
+
+  findExpired(medianTime:number): Promise<CindexEntry[]>
+
+  findByIssuerAndReceiver(issuer: string, receiver: string): Promise<CindexEntry[]>
+
+  findByIssuerAndChainableOnGt(issuer: string, medianTime: number): Promise<CindexEntry[]>
+
+  findByReceiverAndExpiredOn(pub: string, expired_on: number): Promise<CindexEntry[]>
+
+  existsNonReplayableLink(issuer:string, receiver:string): Promise<boolean>
+
+  getReceiversAbove(minsig: number): Promise<string[]>
+
+  reducablesFrom(from:string): Promise<FullCindexEntry[]>
+
+  trimExpiredCerts(belowNumber:number): Promise<void>
+
+}
diff --git a/app/lib/dal/indexDAL/abstract/DividendDAO.ts b/app/lib/dal/indexDAL/abstract/DividendDAO.ts
new file mode 100644
index 0000000000000000000000000000000000000000..69e74c7a7b02bc8483aededd6b54c6feea6631e8
--- /dev/null
+++ b/app/lib/dal/indexDAL/abstract/DividendDAO.ts
@@ -0,0 +1,54 @@
+import {GenericDAO} from "./GenericDAO"
+import {IindexEntry, SimpleTxInput, SimpleUdEntryForWallet, SindexEntry} from "../../../indexer"
+
+export interface DividendEntry {
+  pub: string
+  member: boolean
+  availables: number[]
+  consumed: number[]
+  consumedUDs: {
+    dividendNumber: number,
+    txHash: string,
+    txCreatedOn: string,
+    txLocktime: number,
+    dividend: {
+      amount: number,
+      base: number
+    }
+  }[]
+  dividends: { amount: number, base: number }[]
+}
+
+export interface UDSource {
+  consumed: boolean
+  pos: number
+  amount: number
+  base: number
+}
+
+export interface DividendDAO extends GenericDAO<DividendEntry> {
+
+  setMember(member: boolean, pub: string): Promise<void>
+
+  produceDividend(blockNumber: number, dividend: number, unitbase: number, local_iindex: IindexEntry[]): Promise<SimpleUdEntryForWallet[]>
+
+  getUDSources(pub: string): Promise<UDSource[]>
+
+  findUdSourceByIdentifierPosAmountBase(identifier: string, pos: number, amount: number, base: number): Promise<SimpleTxInput[]>
+
+  getUDSource(identifier: string, pos: number): Promise<SimpleTxInput|null>
+
+  createMember(pub: string): Promise<void>
+
+  consume(filter: SindexEntry[]): Promise<void>
+
+  deleteMember(pub: string): Promise<void>
+
+  getWrittenOnUDs(number: number): Promise<SimpleUdEntryForWallet[]>
+
+  revertUDs(number: number): Promise<{ createdUDsDestroyedByRevert: SimpleUdEntryForWallet[], consumedUDsRecoveredByRevert: SimpleUdEntryForWallet[] }>
+
+  findForDump(criterion: any): Promise<SindexEntry[]>
+
+  trimConsumedUDs(belowNumber:number): Promise<void>
+}
diff --git a/app/lib/dal/indexDAL/abstract/GenericDAO.ts b/app/lib/dal/indexDAL/abstract/GenericDAO.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ff2fd53c1792209ca125c8ee5f0bf5d718c9ecc0
--- /dev/null
+++ b/app/lib/dal/indexDAL/abstract/GenericDAO.ts
@@ -0,0 +1,51 @@
+import {Initiable} from "../../sqliteDAL/Initiable"
+import {LokiDAO} from "../loki/LokiDAO"
+
+export interface GenericDAO<T> extends Initiable, LokiDAO {
+
+  /**
+   * Trigger the initialization of the DAO. Called when the underlying DB is ready.
+   */
+  triggerInit(): void
+
+  /**
+   * Make a generic find.
+   * @param criterion Criterion object, LokiJS's find object format.
+   * @returns {Promise<any>} A set of records.
+   */
+  findRaw(criterion: any): Promise<any>
+
+  /**
+   * Make a generic find with some ordering.
+   * @param criterion Criterion object, LokiJS's find object format.
+   * @param sort A LokiJS's compunded sort object.
+   * @returns {Promise<any>} A set of records.
+   */
+  findRawWithOrder(criterion: any, sort:((string|((string|boolean)[]))[])): Promise<T[]>
+
+  /**
+   * Make a single insert.
+   * @param record The record to insert.
+   */
+  insert(record:T): Promise<void>
+
+  /**
+   * Make a batch insert.
+   * @param records The records to insert as a batch.
+   */
+  insertBatch(records:T[]): Promise<void>
+
+  /**
+   * Get the set of records written on a particular blockstamp.
+   * @param {string} blockstamp The blockstamp we want the records written at.
+   * @returns {Promise<T[]>} The records (array).
+   */
+  getWrittenOn(blockstamp:string): Promise<T[]>
+
+  /**
+   * Remove all entries written at given `blockstamp`, if these entries are still in the index.
+   * @param {string} blockstamp Blockstamp of the entries we want to remove.
+   * @returns {Promise<void>}
+   */
+  removeBlock(blockstamp:string): Promise<void>
+}
diff --git a/app/lib/dal/indexDAL/abstract/IIndexDAO.ts b/app/lib/dal/indexDAL/abstract/IIndexDAO.ts
new file mode 100644
index 0000000000000000000000000000000000000000..698f580c103ad8807c8e20a88bf5050046530d75
--- /dev/null
+++ b/app/lib/dal/indexDAL/abstract/IIndexDAO.ts
@@ -0,0 +1,32 @@
+import {FullIindexEntry, IindexEntry} from "../../../indexer"
+import {ReduceableDAO} from "./ReduceableDAO"
+import {OldIindexEntry} from "../../../db/OldIindexEntry"
+
+export interface IIndexDAO extends ReduceableDAO<IindexEntry> {
+
+  reducable(pub:string): Promise<IindexEntry[]>
+
+  findByPub(pub:string): Promise<IindexEntry[]>
+
+  findByUid(pub:string): Promise<IindexEntry[]>
+
+  getMembers(): Promise<{ pubkey:string, uid:string|null }[]>
+
+  getFromPubkey(pub:string): Promise<FullIindexEntry|null>
+
+  getFromUID(uid:string): Promise<FullIindexEntry|null>
+
+  getFromPubkeyOrUid(search:string): Promise<FullIindexEntry|null>
+
+  searchThoseMatching(search:string): Promise<OldIindexEntry[]>
+
+  getFullFromUID(uid:string): Promise<FullIindexEntry>
+
+  getFullFromPubkey(pub:string): Promise<FullIindexEntry>
+
+  getFullFromHash(hash:string): Promise<FullIindexEntry>
+
+  getToBeKickedPubkeys(): Promise<string[]>
+
+  findAllByWrittenOn(): Promise<IindexEntry[]>
+}
diff --git a/app/lib/dal/indexDAL/abstract/MIndexDAO.ts b/app/lib/dal/indexDAL/abstract/MIndexDAO.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b8fef98bb846c1eea98fa8ca198f7d2221ebebcd
--- /dev/null
+++ b/app/lib/dal/indexDAL/abstract/MIndexDAO.ts
@@ -0,0 +1,17 @@
+import {FullMindexEntry, MindexEntry} from "../../../indexer"
+import {ReduceableDAO} from "./ReduceableDAO"
+
+export interface MIndexDAO extends ReduceableDAO<MindexEntry>  {
+
+  reducable(pub:string): Promise<MindexEntry[]>
+
+  getRevokedPubkeys(): Promise<string[]>
+
+  findByPubAndChainableOnGt(pub:string, medianTime:number): Promise<MindexEntry[]>
+
+  findRevokesOnLteAndRevokedOnIsNull(medianTime:number): Promise<MindexEntry[]>
+
+  findExpiresOnLteAndRevokesOnGt(medianTime:number): Promise<MindexEntry[]>
+
+  getReducedMS(pub:string): Promise<FullMindexEntry|null>
+}
diff --git a/app/lib/dal/indexDAL/abstract/PeerDAO.ts b/app/lib/dal/indexDAL/abstract/PeerDAO.ts
new file mode 100644
index 0000000000000000000000000000000000000000..97756b4227a35787eccd1b955568acca7069d98c
--- /dev/null
+++ b/app/lib/dal/indexDAL/abstract/PeerDAO.ts
@@ -0,0 +1,62 @@
+import {Initiable} from "../../sqliteDAL/Initiable"
+import {DBPeer} from "../../../db/DBPeer"
+import {LokiDAO} from "../loki/LokiDAO"
+
+export interface PeerDAO extends Initiable, LokiDAO {
+
+  /**
+   * Trigger the initialization of the DAO. Called when the underlying DB is ready.
+   */
+  triggerInit(): void
+
+  listAll(): Promise<DBPeer[]>
+
+  withUPStatus(): Promise<DBPeer[]>
+
+  /**
+   * Saves a wallet.
+   * @param {DBPeer} peer
+   * @returns {Promise<DBPeer>}
+   */
+  savePeer(peer:DBPeer): Promise<DBPeer>
+
+  /**
+   * Find a wallet based on conditions.
+   * @param {string} pubkey
+   * @returns {Promise<DBPeer>}
+   */
+  getPeer(pubkey:string): Promise<DBPeer>
+
+  /**
+   * Find all peers with at least one endpoint matching given parameter.
+   * @param {string} ep
+   * @returns {Promise<DBPeer[]>}
+   */
+  getPeersWithEndpointsLike(ep:string): Promise<DBPeer[]>
+
+  /**
+   * Make a batch insert.
+   * @param records The records to insert as a batch.
+   */
+  insertBatch(records:DBPeer[]): Promise<void>
+
+  /**
+   * Remove a peer by its pubkey.
+   * @param {string} pubkey
+   * @returns {Promise<void>}
+   */
+  removePeerByPubkey(pubkey:string): Promise<void>
+
+  /**
+   * Remove peers that were set down before a certain datetime.
+   * @param {number} thresholdTime
+   * @returns {Promise<void>}
+   */
+  removePeersDownBefore(thresholdTime:number): Promise<void>
+
+  /**
+   * Remove all the peers.
+   * @returns {Promise<void>}
+   */
+  removeAll(): Promise<void>
+}
diff --git a/app/lib/dal/indexDAL/abstract/ReduceableDAO.ts b/app/lib/dal/indexDAL/abstract/ReduceableDAO.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5eaf55f7bb066381b9596b739f856c416b3def89
--- /dev/null
+++ b/app/lib/dal/indexDAL/abstract/ReduceableDAO.ts
@@ -0,0 +1,11 @@
+import {GenericDAO} from "./GenericDAO"
+
+export interface ReduceableDAO<T> extends GenericDAO<T> {
+
+  /**
+   * Reduce all records sharing a same reduction key that written before given block number.
+   * @param {number} belowNumber All records written strictly under `belowNumber` have to be reduced on the reduction key.
+   * @returns {Promise<void>}
+   */
+  trimRecords(belowNumber:number): Promise<void>
+}
diff --git a/app/lib/dal/indexDAL/abstract/SIndexDAO.ts b/app/lib/dal/indexDAL/abstract/SIndexDAO.ts
new file mode 100644
index 0000000000000000000000000000000000000000..be5aa17033a1a2ef0e7eca2fa2816a181990866e
--- /dev/null
+++ b/app/lib/dal/indexDAL/abstract/SIndexDAO.ts
@@ -0,0 +1,24 @@
+import {FullSindexEntry, SimpleTxEntryForWallet, SimpleTxInput, SindexEntry} from "../../../indexer"
+import {ReduceableDAO} from "./ReduceableDAO"
+
+export interface UDSource {
+  consumed: boolean
+  pos: number
+  amount: number
+  base: number
+}
+
+export interface SIndexDAO extends ReduceableDAO<SindexEntry> {
+
+  findTxSourceByIdentifierPosAmountBase(identifier: string, pos: number, amount: number, base: number): Promise<SimpleTxInput[]>
+
+  getTxSource(identifier:string, pos:number): Promise<FullSindexEntry|null>
+
+  getAvailableForPubkey(pubkey:string): Promise<{ amount:number, base:number, conditions: string, identifier: string, pos: number }[]>
+
+  getAvailableForConditions(conditionsStr:string): Promise<SindexEntry[]>
+
+  trimConsumedSource(belowNumber:number): Promise<void>
+
+  getWrittenOnTxs(blockstamp: string): Promise<SimpleTxEntryForWallet[]>
+}
diff --git a/app/lib/dal/indexDAL/abstract/TxsDAO.ts b/app/lib/dal/indexDAL/abstract/TxsDAO.ts
new file mode 100644
index 0000000000000000000000000000000000000000..84c53b0086f205eaa5f1d91a66866102da3aab21
--- /dev/null
+++ b/app/lib/dal/indexDAL/abstract/TxsDAO.ts
@@ -0,0 +1,35 @@
+import {GenericDAO} from "./GenericDAO"
+import {TransactionDTO} from "../../../dto/TransactionDTO"
+import {SandBox} from "../../sqliteDAL/SandBox"
+import {DBTx} from "../../../db/DBTx"
+
+export interface TxsDAO extends GenericDAO<DBTx> {
+
+  trimExpiredNonWrittenTxs(limitTime:number): Promise<void>
+
+  getAllPending(versionMin:number): Promise<DBTx[]>
+
+  getTX(hash:string): Promise<DBTx>
+
+  addLinked(tx:TransactionDTO, block_number:number, time:number): Promise<DBTx>
+
+  addPending(dbTx:DBTx): Promise<DBTx>
+
+  getLinkedWithIssuer(pubkey:string): Promise<DBTx[]>
+
+  getLinkedWithRecipient(pubkey:string): Promise<DBTx[]>
+
+  getPendingWithIssuer(pubkey:string): Promise<DBTx[]>
+
+  getPendingWithRecipient(pubkey:string): Promise<DBTx[]>
+
+  removeTX(hash:string): Promise<DBTx|null>
+
+  removeAll(): Promise<void>
+
+  sandbox:SandBox<{ issuers: string[], output_base:number, output_amount:number }>
+
+  getSandboxRoom(): Promise<number>
+
+  setSandboxSize(size:number): void
+}
diff --git a/app/lib/dal/indexDAL/abstract/WalletDAO.ts b/app/lib/dal/indexDAL/abstract/WalletDAO.ts
new file mode 100644
index 0000000000000000000000000000000000000000..dfb0d0f50c01bd87a4489e0b28c83a0e04a1e680
--- /dev/null
+++ b/app/lib/dal/indexDAL/abstract/WalletDAO.ts
@@ -0,0 +1,31 @@
+import {Initiable} from "../../sqliteDAL/Initiable"
+import {DBWallet} from "../../../db/DBWallet"
+import {LokiDAO} from "../loki/LokiDAO"
+
+export interface WalletDAO extends Initiable, LokiDAO {
+
+  /**
+   * Trigger the initialization of the DAO. Called when the underlying DB is ready.
+   */
+  triggerInit(): void
+
+  /**
+   * Saves a wallet.
+   * @param {DBWallet} wallet
+   * @returns {Promise<DBWallet>}
+   */
+  saveWallet(wallet:DBWallet): Promise<DBWallet>
+
+  /**
+   * Find a wallet based on conditions.
+   * @param {string} conditions
+   * @returns {Promise<DBWallet>}
+   */
+  getWallet(conditions:string): Promise<DBWallet>
+
+  /**
+   * Make a batch insert.
+   * @param records The records to insert as a batch.
+   */
+  insertBatch(records:DBWallet[]): Promise<void>
+}
diff --git a/app/lib/dal/indexDAL/loki/LokiBIndex.ts b/app/lib/dal/indexDAL/loki/LokiBIndex.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6471996e141c968280c17bd29e66265074d66b8c
--- /dev/null
+++ b/app/lib/dal/indexDAL/loki/LokiBIndex.ts
@@ -0,0 +1,91 @@
+import {DBHead} from "../../../db/DBHead"
+import {BIndexDAO} from "../abstract/BIndexDAO"
+import {NewLogger} from "../../../logger"
+import {MonitorLokiExecutionTime} from "../../../debug/MonitorLokiExecutionTime"
+import {LokiProtocolIndex} from "./LokiProtocolIndex"
+
+const logger = NewLogger()
+
+export class LokiBIndex extends LokiProtocolIndex<DBHead> implements BIndexDAO {
+
+  private HEAD:DBHead|null = null
+
+  constructor(loki:any) {
+    super(loki, 'bindex', ['number', 'hash'])
+  }
+
+  async insert(record: DBHead): Promise<void> {
+    this.HEAD = record
+    return super.insert(record);
+  }
+
+  async removeBlock(blockstamp: string): Promise<void> {
+    this.HEAD = await this.head(2)
+    return super.removeBlock(blockstamp);
+  }
+
+  async head(n: number): Promise<DBHead> {
+    if (!n) {
+      throw "Cannot read HEAD~0, which is the incoming block"
+    }
+    if (n === 1 && this.HEAD) {
+      // Cached
+      return this.HEAD
+    } else if (this.HEAD) {
+      // Another than HEAD
+      return this.collection
+        .find({ number: this.HEAD.number - n + 1 })[0]
+    } else {
+      // Costly method, as a fallback
+      return this.collection
+        .chain()
+        .find({})
+        .simplesort('number', true)
+        .data()[n - 1]
+    }
+  }
+
+  async range(n: number, m: number): Promise<DBHead[]> {
+    if (!n) {
+      throw "Cannot read HEAD~0, which is the incoming block"
+    }
+    const HEAD = await this.head(1)
+    if (!HEAD) {
+      return []
+    }
+    return this.collection
+      .chain()
+      .find({
+        $and: [
+          { number: { $lte: HEAD.number - n + 1 } },
+          { number: { $gte: HEAD.number - m + 1 } },
+        ]
+      })
+      .simplesort('number', true)
+      .data().slice(n - 1, m)
+  }
+
+  async tail(): Promise<DBHead> {
+    const HEAD = await this.head(1)
+    if (!HEAD) {
+      return HEAD
+    }
+    const nbHEADs = this.collection.length()
+    return this.collection
+      .find({ number: HEAD.number - nbHEADs + 1 })[0]
+  }
+
+  @MonitorLokiExecutionTime(true)
+  async trimBlocks(maxnumber: number): Promise<void> {
+    this.collection
+      .chain()
+      .find({ number: { $lt: maxnumber }})
+      .remove()
+  }
+
+  @MonitorLokiExecutionTime(true)
+  async getWrittenOn(blockstamp: string): Promise<DBHead[]> {
+    const criterion:any = { number: parseInt(blockstamp) }
+    return this.collection.find(criterion)
+  }
+}
diff --git a/app/lib/dal/indexDAL/loki/LokiBlockchain.ts b/app/lib/dal/indexDAL/loki/LokiBlockchain.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1c125c194a895508a62c6526a4730492419bb95e
--- /dev/null
+++ b/app/lib/dal/indexDAL/loki/LokiBlockchain.ts
@@ -0,0 +1,247 @@
+import {BlockchainDAO} from "../abstract/BlockchainDAO"
+import {DBBlock} from "../../../db/DBBlock"
+import {MonitorLokiExecutionTime} from "../../../debug/MonitorLokiExecutionTime"
+import {LokiProtocolIndex} from "./LokiProtocolIndex"
+
+export class LokiBlockchain extends LokiProtocolIndex<DBBlock> implements BlockchainDAO {
+
+  private current:DBBlock|null = null
+
+  constructor(loki:any) {
+    super(loki, 'blockchain', ['number', 'hash', 'fork'])
+  }
+
+  cleanCache(): void {
+    super.cleanCache()
+    this.current = null
+  }
+
+  async getCurrent() {
+    if (this.current) {
+      // Cached
+      return this.current
+    } else {
+      // Costly method, as a fallback
+      return this.collection
+        .chain()
+        .find({
+          fork: false
+        })
+        .simplesort('number', true)
+        .data()[0]
+    }
+  }
+
+  @MonitorLokiExecutionTime(true)
+  async getBlock(number:string | number) {
+    return this.collection
+      .chain()
+      .find({
+        number: parseInt(String(number)),
+        fork: false
+      })
+      .data()[0]
+  }
+
+  async getPotentialRoots() {
+    return this.collection
+      .chain()
+      .find({ number: 0, fork: true })
+      .data()
+  }
+
+  async saveBunch(blocks:DBBlock[]) {
+    return this.insertBatch(blocks)
+  }
+
+  async insertBatch(records: DBBlock[]): Promise<void> {
+    const lastInBatch = records[records.length - 1]
+    if (!this.current || this.current.number < lastInBatch.number) {
+      this.current = lastInBatch
+    }
+    return super.insertBatch(records)
+  }
+
+  async removeBlock(blockstamp: string): Promise<void> {
+    // Never remove blocks
+  }
+
+  async removeForkBlock(number:number): Promise<void> {
+    await this.collection
+      .chain()
+      .find({
+        fork: true,
+        number
+      })
+      .remove()
+  }
+
+  async removeForkBlockAboveOrEqual(number:number): Promise<void> {
+    await this.collection
+      .chain()
+      .find({
+        fork: true,
+        number: { $gte: number }
+      })
+      .remove()
+  }
+
+  async trimBlocks(number:number): Promise<void> {
+    await this.collection
+      .chain()
+      .find({
+        number: { $lte: number }
+      })
+      .remove()
+  }
+
+  async getAbsoluteBlock(number: number, hash: string): Promise<DBBlock | null> {
+    return this.collection
+      .chain()
+      .find({
+        number,
+        hash
+      })
+      .data()[0]
+  }
+
+  async getBlocks(start: number, end: number): Promise<DBBlock[]> {
+    return this.collection
+      .chain()
+      .find({
+        number: { $between: [start, end] },
+        fork: false
+      })
+      .simplesort('number')
+      .data()
+  }
+
+  async getCountOfBlocksIssuedBy(issuer: string): Promise<number> {
+    return this.collection
+      .chain()
+      .find({
+        issuer,
+        fork: false
+      })
+      .data()
+      .length
+  }
+
+  async getNextForkBlocks(number: number, hash: string): Promise<DBBlock[]> {
+    return this.collection
+      .chain()
+      .find({
+        fork: true,
+        number: number + 1,
+        previousHash: hash
+      })
+      .simplesort('number')
+      .data()
+  }
+
+  async getPotentialForkBlocks(numberStart: number, medianTimeStart: number, maxNumber: number): Promise<DBBlock[]> {
+    return this.collection
+      .chain()
+      .find({
+        fork: true,
+        number: { $between: [numberStart, maxNumber] },
+        medianTime: { $gte: medianTimeStart }
+      })
+      .simplesort('number', true)
+      .data()
+  }
+
+  async lastBlockOfIssuer(issuer: string): Promise<DBBlock | null> {
+    return this.collection
+      .chain()
+      .find({
+        fork: false,
+        issuer
+      })
+      .simplesort('number', true)
+      .data()[0]
+  }
+
+  async lastBlockWithDividend(): Promise<DBBlock | null> {
+    return this.collection
+      .chain()
+      .find({
+        fork: false,
+        dividend: { $gt: 0 }
+      })
+      .simplesort('number', true)
+      .data()[0]
+  }
+
+  async saveBlock(block: DBBlock): Promise<DBBlock> {
+    if (!this.current || this.current.number < block.number) {
+      this.current = block;
+    }
+    return this.insertOrUpdate(block, false)
+  }
+
+  async saveSideBlock(block: DBBlock): Promise<DBBlock> {
+    return this.insertOrUpdate(block, true)
+  }
+
+  async insertOrUpdate(block: DBBlock, isFork:boolean): Promise<DBBlock> {
+    block.fork = isFork
+    const conditions = { number: block.number, hash: block.hash }
+    const existing = (await this.findRaw(conditions))[0]
+    if (existing && existing.fork !== isFork) {
+      // Existing block: we only allow to change the fork flag
+      this.collection
+        .chain()
+        .find(conditions)
+        .update(b => {
+          b.fork = isFork
+          b.monetaryMass = block.monetaryMass
+          b.dividend = block.dividend
+        })
+    }
+    else if (!existing) {
+      await this.insert(block)
+    }
+    return block
+  }
+
+  async dropNonForkBlocksAbove(number: number): Promise<void> {
+    this.collection
+      .chain()
+      .find({
+        fork: false,
+        number: { $gt: number }
+      })
+      .remove()
+  }
+
+  async setSideBlock(number: number, previousBlock: DBBlock | null): Promise<void> {
+    this.collection
+      .chain()
+      .find({
+        number
+      })
+      .update((b:DBBlock) => {
+        b.fork = true
+      })
+    // Also update the cache if concerned
+    if (this.current && this.current.number === number) {
+      if (previousBlock && this.current.previousHash === previousBlock.hash) {
+        this.current = previousBlock
+      } else {
+        this.current = null
+      }
+    }
+  }
+
+  async getNonForkChunk(start: number, end: number): Promise<DBBlock[]> {
+    return this.collection
+      .chain()
+      .find({
+        fork: false,
+        number: { $between: [start, end ]}
+      })
+      .simplesort('number')
+      .data()
+  }
+}
diff --git a/app/lib/dal/indexDAL/loki/LokiCIndex.ts b/app/lib/dal/indexDAL/loki/LokiCIndex.ts
new file mode 100644
index 0000000000000000000000000000000000000000..218ef22ee08afc716e70ae13e89e49cfe74bf134
--- /dev/null
+++ b/app/lib/dal/indexDAL/loki/LokiCIndex.ts
@@ -0,0 +1,161 @@
+import {CIndexDAO} from "../abstract/CIndexDAO"
+import {CindexEntry, FullCindexEntry, Indexer} from "../../../indexer"
+import {CommonConstants} from "../../../common-libs/constants"
+import {MonitorLokiExecutionTime} from "../../../debug/MonitorLokiExecutionTime"
+import {LokiProtocolIndex} from "./LokiProtocolIndex"
+
+export class LokiCIndex extends LokiProtocolIndex<CindexEntry> implements CIndexDAO {
+
+  constructor(loki:any) {
+    super(loki, 'cindex', ['issuer', 'receiver'])
+  }
+
+  async existsNonReplayableLink(issuer: string, receiver: string): Promise<boolean> {
+    return Indexer.DUP_HELPERS.reduce<CindexEntry>(
+      this.collection
+        .chain()
+        .find({
+          $and: [
+            { issuer },
+            { receiver },
+          ]
+        })
+        .simplesort('writtenOn')
+        .data()
+    ).op === CommonConstants.IDX_CREATE
+  }
+
+  async findByIssuerAndChainableOnGt(issuer: string, medianTime: number): Promise<CindexEntry[]> {
+    return this.collection
+      .chain()
+      .find({
+        $and: [
+          { issuer },
+          { chainable_on: { $gt: medianTime } },
+        ]
+      })
+      .simplesort('writtenOn')
+      .data()
+  }
+
+  async findByIssuerAndReceiver(issuer: string, receiver: string): Promise<CindexEntry[]> {
+    return this.collection
+      .chain()
+      .find({
+        $and: [
+          { issuer },
+          { receiver },
+        ]
+      })
+      .simplesort('writtenOn')
+      .data()
+  }
+
+  async findByReceiverAndExpiredOn(pub: string, expired_on: number): Promise<CindexEntry[]> {
+    return this.collection
+      .chain()
+      .find({
+        $and: [
+          { receiver: pub },
+          { expired_on },
+        ]
+      })
+      .simplesort('writtenOn')
+      .data()
+  }
+
+  async findExpired(medianTime: number): Promise<CindexEntry[]> {
+    return this.collection
+      .chain()
+      .find({ expires_on: { $lte: medianTime } })
+      .simplesort('writtenOn')
+      .data()
+      .filter(c => {
+        return this.collection
+          .find({
+            op: CommonConstants.IDX_UPDATE,
+            issuer: c.issuer,
+            receiver: c.receiver,
+            created_on: c.created_on,
+          })
+          .length === 0
+      })
+  }
+
+  async reducablesFrom(from: string): Promise<FullCindexEntry[]> {
+    const reducables = this.collection
+      .chain()
+      .find({ issuer: from })
+      .simplesort('writtenOn')
+      .data()
+    return Indexer.DUP_HELPERS.reduceBy(reducables, ['issuer', 'receiver', 'created_on'])
+  }
+
+  async getReceiversAbove(minsig: number): Promise<string[]> {
+    const reduction = this.collection
+      .find({})
+      .reduce((map:any, c) => {
+        if (!map[c.receiver]) {
+          map[c.receiver] = 0
+        }
+        map[c.receiver]++
+        return map
+      }, {})
+    return Object.keys(reduction)
+      .map(receiver => ({ receiver, count: reduction[receiver]}))
+      .filter(o => o.count >= minsig)
+      .map(o => o.receiver)
+  }
+
+  async getValidLinksFrom(issuer: string): Promise<CindexEntry[]> {
+    return this.collection
+      .find({ issuer })
+      .filter(r => this.collection.find({ issuer: r.issuer, receiver: r.receiver, created_on: r.created_on, expired_on: { $gt: 0 } }).length === 0)
+  }
+
+  async getValidLinksTo(receiver: string): Promise<CindexEntry[]> {
+    return this.collection
+      .find({ receiver })
+      .filter(r => this.collection.find({ issuer: r.issuer, receiver: r.receiver, created_on: r.created_on, expired_on: { $gt: 0 } }).length === 0)
+  }
+
+  @MonitorLokiExecutionTime(true)
+  async trimExpiredCerts(belowNumber: number): Promise<void> {
+    const expired = this.collection.find({
+      $and: [
+        { expired_on: { $gt: 0 }},
+        { writtenOn: { $lt: belowNumber }},
+      ]
+    })
+    for (const e of expired) {
+      this.collection
+        .chain()
+        .find({
+          issuer: e.issuer,
+          receiver: e.receiver,
+          created_on: e.created_on
+        })
+        .remove()
+    }
+  }
+
+  /**
+   * For CINDEX, trimming records <=> removing the expired certs
+   * @param {number} belowNumber Number below which an expired certification must be removed.
+   * @returns {Promise<void>}
+   */
+  async trimRecords(belowNumber: number): Promise<void> {
+    return this.trimExpiredCerts(belowNumber)
+  }
+
+  private reduced(issuer:string, receiver:string, created_on:number): FullCindexEntry {
+    return Indexer.DUP_HELPERS.reduce(this.reducable(issuer, receiver, created_on))
+  }
+
+  private reducable(issuer:string, receiver:string, created_on:number): CindexEntry[] {
+    return this.collection.chain()
+      .find({ issuer, receiver, created_on })
+      .simplesort('writtenOn')
+      .data()
+  }
+}
diff --git a/app/lib/dal/indexDAL/loki/LokiCollection.ts b/app/lib/dal/indexDAL/loki/LokiCollection.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e160608b620f75c4858fa95c87990618b1ef985e
--- /dev/null
+++ b/app/lib/dal/indexDAL/loki/LokiCollection.ts
@@ -0,0 +1,59 @@
+import {LokiChainableFind, LokiCollection} from "./LokiTypes"
+import {NewLogger} from "../../../logger"
+import {getMicrosecondsTime} from "../../../../ProcessCpuProfiler"
+
+const logger = NewLogger()
+
+export class LokiProxyCollection<T> implements LokiCollection<T> {
+
+  constructor(public collection:LokiCollection<T>, private collectionName:string) {
+  }
+
+  get data() {
+    return this.collection.data
+  }
+
+  length(): number {
+    return this.collection.data.length
+  }
+
+  insert(entity:T) {
+    this.collection.insert(entity)
+  }
+
+  remove(entity:T) {
+    this.collection.remove(entity)
+  }
+
+  find(criterion:{ [t in keyof T|'$or'|'$and']?: any }) {
+    const now = getMicrosecondsTime()
+    const res = this.collection.find(criterion)
+    // logger.trace('[loki][%s][find] %sµs', this.collectionName, getDurationInMicroSeconds(now), criterion)
+    return res
+  }
+
+  chain(): LokiChainableFind<T> {
+    return this.collection.chain()
+  }
+
+  setChangesApi(enabled: boolean) {
+    this.collection.setChangesApi(enabled)
+    // This is a Loki bug: `disableDeltaChangesApi` should be impacted just like `disableChangesApi`:
+    ;(this.collection as any).disableDeltaChangesApi = !enabled
+  }
+
+  // Returns the real Loki property
+  get disableChangesApi() {
+    return this.collection.disableChangesApi
+  }
+
+  // Returns the real Loki property
+  get disableDeltaChangesApi() {
+    return this.collection.disableDeltaChangesApi
+  }
+
+  get changes() {
+    return this.collection.changes
+  }
+
+}
diff --git a/app/lib/dal/indexDAL/loki/LokiCollectionManager.ts b/app/lib/dal/indexDAL/loki/LokiCollectionManager.ts
new file mode 100755
index 0000000000000000000000000000000000000000..ce6d2ad06d0fb67baf363f1df1b8b977e946a067
--- /dev/null
+++ b/app/lib/dal/indexDAL/loki/LokiCollectionManager.ts
@@ -0,0 +1,47 @@
+import {LokiCollection} from "./LokiTypes"
+import {LokiProxyCollection} from "./LokiCollection"
+import {NewLogger} from "../../../logger"
+import {LokiDAO} from "./LokiDAO"
+import {cliprogram} from "../../../common-libs/programOptions"
+
+const logger = NewLogger()
+
+export abstract class LokiCollectionManager<T> implements LokiDAO {
+
+  protected collection:LokiCollection<T>
+  protected collectionIsInitialized: Promise<void>
+  protected resolveCollection: () => void
+
+  public constructor(
+    protected loki:any,
+    protected collectionName:'iindex'|'mindex'|'cindex'|'sindex'|'bindex'|'blockchain'|'txs'|'wallet'|'peer'|'dividend',
+    protected indices: (keyof T)[]) {
+    this.collectionIsInitialized = new Promise<void>(res => this.resolveCollection = res)
+  }
+
+  get lokiCollection(): LokiCollection<T> {
+    return this.collection
+  }
+
+  public triggerInit() {
+    const coll = this.loki.addCollection(this.collectionName, {
+      indices: this.indices,
+      disableChangesApi: cliprogram.isSync
+    })
+    this.collection = new LokiProxyCollection(coll, this.collectionName)
+    this.resolveCollection()
+  }
+
+  public enableChangesAPI() {
+    this.collection.setChangesApi(true)
+  }
+
+  public disableChangesAPI() {
+    this.collection.setChangesApi(false)
+  }
+
+  async init(): Promise<void> {
+    await this.collectionIsInitialized
+    logger.info('Collection %s ready', this.collectionName)
+  }
+}
\ No newline at end of file
diff --git a/app/lib/dal/indexDAL/loki/LokiDAO.ts b/app/lib/dal/indexDAL/loki/LokiDAO.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b060804d77b59d7bdc76ed8d2565bd73547471c8
--- /dev/null
+++ b/app/lib/dal/indexDAL/loki/LokiDAO.ts
@@ -0,0 +1,10 @@
+import {LokiCollection} from "./LokiTypes"
+
+export interface LokiDAO {
+
+  enableChangesAPI(): void
+
+  disableChangesAPI(): void
+
+  lokiCollection: LokiCollection<any>
+}
diff --git a/app/lib/dal/indexDAL/loki/LokiDividend.ts b/app/lib/dal/indexDAL/loki/LokiDividend.ts
new file mode 100644
index 0000000000000000000000000000000000000000..daa96c8efdc0bc8a1232cf1778fe49464946760e
--- /dev/null
+++ b/app/lib/dal/indexDAL/loki/LokiDividend.ts
@@ -0,0 +1,335 @@
+import {LokiIndex} from "./LokiIndex"
+import {DividendDAO, DividendEntry, UDSource} from "../abstract/DividendDAO"
+import {IindexEntry, SimpleTxInput, SimpleUdEntryForWallet, SindexEntry} from "../../../indexer"
+import {DataErrors} from "../../../common-libs/errors"
+
+export class LokiDividend extends LokiIndex<DividendEntry> implements DividendDAO {
+
+  constructor(loki:any) {
+    super(loki, 'dividend', ['pub'])
+  }
+
+  async createMember(pub: string): Promise<void> {
+    const existing = this.collection.find({ pub })[0]
+    if (!existing) {
+      await this.insert({ pub, member: true, availables: [], dividends: [], consumed: [], consumedUDs: [] })
+    } else {
+      await this.setMember(true, pub)
+    }
+  }
+
+  async setMember(member: boolean, pub: string) {
+    await this.collection
+      .chain()
+      .find({ pub })
+      .update(r => {
+        r.member = member
+      })
+  }
+
+  async deleteMember(pub: string): Promise<void> {
+    this.collection
+      .chain()
+      .find({ pub })
+      .remove()
+  }
+
+  async produceDividend(blockNumber: number, dividend: number, unitbase: number, local_iindex: IindexEntry[]): Promise<SimpleUdEntryForWallet[]> {
+    const dividends: SimpleUdEntryForWallet[] = []
+    // Then produce the UD
+    this.collection
+      .chain()
+      .find({ member: true })
+      .update(r => {
+        r.availables.push(blockNumber)
+        r.dividends.push({ amount: dividend, base: unitbase })
+        dividends.push({
+          srcType: 'D',
+          amount: dividend,
+          base: unitbase,
+          conditions: 'SIG(' + r.pub + ')',
+          op: 'CREATE',
+          identifier: r.pub,
+          pos: blockNumber
+        })
+      })
+    return dividends
+  }
+
+  async consume(filter: SindexEntry[]): Promise<void> {
+    for (const dividendToConsume of filter) {
+      this.collection
+        .chain()
+        // We look at the dividends of this member
+        .find({
+          pub: dividendToConsume.identifier
+        })
+        // Then we try to consume the dividend being spent
+        .update(m => {
+          const index = m.availables.indexOf(dividendToConsume.pos)
+
+          // We add it to the consumption history
+          m.consumed.push(dividendToConsume.writtenOn) // `writtenOn` is the date (block#) of consumption
+          m.consumedUDs.push({
+            dividendNumber: dividendToConsume.pos,
+            dividend: m.dividends[index],
+            txCreatedOn: dividendToConsume.created_on as string,
+            txLocktime: dividendToConsume.locktime,
+            txHash: dividendToConsume.tx as string,
+          })
+
+          // We remove it from available dividends
+          m.availables.splice(index, 1)
+          m.dividends.splice(index, 1)
+        })
+    }
+  }
+
+  async getUDSources(pub: string): Promise<UDSource[]> {
+    const member = this.collection
+      .chain()
+      .find({ pub })
+      .data()[0]
+    if (!member) {
+      return []
+    }
+    return member.availables.map(pos => this.toUDSource(member, pos) as UDSource)
+  }
+
+  async findUdSourceByIdentifierPosAmountBase(identifier: string, pos: number, amount: number, base: number): Promise<SimpleTxInput[]> {
+    const member = this.collection.find({ pub: identifier })[0]
+    let src: UDSource|null = null
+    if (member) {
+      const udSrc = this.toUDSource(member, pos)
+      if (udSrc && udSrc.amount === amount && udSrc.base === base) {
+        src = udSrc
+      }
+    }
+    return [{
+      written_time: 0,
+      conditions: 'SIG(' + identifier + ')',
+      consumed: !src,
+      amount,
+      base
+    }]
+  }
+
+  private toUDSource(entry: DividendEntry, pos: number): UDSource|null {
+    const index = entry.availables.indexOf(pos)
+    if (index === -1) {
+      return null
+    }
+    const src = entry.dividends[index]
+    return {
+      consumed: false,
+      pos,
+      amount: src.amount,
+      base: src.base,
+    }
+  }
+
+  async getUDSource(identifier: string, pos: number): Promise<SimpleTxInput|null> {
+    const member = this.collection.find({ pub: identifier })[0]
+    let src: UDSource|null = null
+    if (member) {
+      src = this.toUDSource(member, pos)
+    }
+    if (!src) {
+      return null
+    }
+    return {
+      written_time: 0,
+      conditions: 'SIG(' + identifier + ')',
+      consumed: !src,
+      amount: src.amount,
+      base: src.base
+    }
+  }
+
+  async getWrittenOn(blockstamp: string): Promise<DividendEntry[]> {
+    throw Error(DataErrors[DataErrors.LOKI_DIVIDEND_GET_WRITTEN_ON_SHOULD_NOT_BE_USED])
+  }
+
+  async getWrittenOnUDs(number: number): Promise<SimpleUdEntryForWallet[]> {
+    const res: SimpleUdEntryForWallet[] = []
+    this.collection
+      .chain()
+      .find({ availables: { $contains: number } })
+      .data()
+      .map(m => {
+        const s = this.toUDSource(m, number) as UDSource
+        res.push({
+          srcType: 'D',
+          op: 'CREATE',
+          conditions: 'SIG(' + m.pub + ')',
+          amount: s.amount,
+          base: s.base,
+          identifier: m.pub,
+          pos: s.pos
+        })
+      })
+    return res
+  }
+
+  async removeBlock(blockstamp: string): Promise<void> {
+    throw Error(DataErrors[DataErrors.LOKI_DIVIDEND_REMOVE_BLOCK_SHOULD_NOT_BE_USED])
+  }
+
+  /**
+   * Remove UD data produced in a block, either UD production or UD consumption.
+   * @param {number} number Block number to revert the created UDs.
+   * @returns {Promise<{createdUDsDestroyedByRevert: SimpleUdEntryForWallet[]}>}
+   */
+  async revertUDs(number: number): Promise<{
+    createdUDsDestroyedByRevert: SimpleUdEntryForWallet[]
+    consumedUDsRecoveredByRevert: SimpleUdEntryForWallet[]
+  }> {
+    const createdUDsDestroyedByRevert: SimpleUdEntryForWallet[] = []
+    const consumedUDsRecoveredByRevert: SimpleUdEntryForWallet[] = []
+    // Remove produced dividends at this block
+    this.collection
+      .chain()
+      .find({ availables: { $contains: number }})
+      .update(m => {
+        const index = m.availables.indexOf(number)
+        const src = m.dividends[index]
+        createdUDsDestroyedByRevert.push({
+          conditions: 'SIG(' + m.pub + ')',
+          pos: number,
+          identifier: m.pub,
+          amount: src.amount,
+          base: src.base,
+          srcType: 'D',
+          op: 'CREATE'
+        })
+        m.availables.splice(index, 1)
+        m.dividends.splice(index, 1)
+      })
+    // Unconsumed dividends consumed at this block
+    this.collection
+      .chain()
+      .find({ consumed: { $contains: number }})
+      .update(m => {
+        const index = m.consumed.indexOf(number)
+
+        const src = m.consumedUDs[index].dividend
+        consumedUDsRecoveredByRevert.push({
+          conditions: 'SIG(' + m.pub + ')',
+          pos: m.consumedUDs[index].dividendNumber,
+          identifier: m.pub,
+          amount: src.amount,
+          base: src.base,
+          srcType: 'D',
+          op: 'CREATE'
+        })
+
+        // We put it back as available
+        m.availables.push(m.consumedUDs[index].dividendNumber)
+        m.dividends.push(m.consumedUDs[index].dividend)
+
+        // We remove it from consumed
+        m.consumed.splice(index, 1)
+        m.consumedUDs.splice(index, 1)
+      })
+    return {
+      createdUDsDestroyedByRevert,
+      consumedUDsRecoveredByRevert,
+    }
+  }
+
+  async findForDump(criterion: any): Promise<SindexEntry[]> {
+    const entries: SindexEntry[] = []
+    const rows = await this.findRaw(criterion)
+    for (const m of rows) {
+      // Generate for unspent UDs
+      for (let i = 0; i < m.availables.length; i++) {
+        const writtenOn = m.availables[i]
+        const ud = m.dividends[i]
+        entries.push({
+          op: 'CREATE',
+          index: 'SINDEX',
+          srcType: 'D',
+          tx: null,
+          identifier: m.pub,
+          writtenOn,
+          pos: writtenOn,
+          created_on: 'NULL', // TODO
+          written_on: writtenOn + '', // TODO
+          written_time: 0, // TODO
+          amount: ud.amount,
+          base: ud.base,
+          locktime: null as any,
+          consumed: false,
+          conditions: 'SIG(' + m.pub + ')',
+          unlock: null,
+          txObj: null as any, // TODO
+          age: 0,
+        })
+      }
+      // Generate for spent UDs
+      for (let i = 0; i < m.consumed.length; i++) {
+        const writtenOn = m.consumed[i]
+        const ud = m.consumedUDs[i]
+        entries.push({
+          op: 'CREATE',
+          index: 'SINDEX',
+          srcType: 'D',
+          tx: null,
+          identifier: m.pub,
+          writtenOn: ud.dividendNumber,
+          pos: ud.dividendNumber,
+          created_on: 'NULL', // TODO
+          written_on: writtenOn + '', // TODO
+          written_time: 0, // TODO
+          amount: ud.dividend.amount,
+          base: ud.dividend.base,
+          locktime: null as any,
+          consumed: false,
+          conditions: 'SIG(' + m.pub + ')',
+          unlock: null,
+          txObj: null as any, // TODO
+          age: 0,
+        })
+        entries.push({
+          op: 'UPDATE',
+          index: 'SINDEX',
+          srcType: 'D',
+          tx: ud.txHash,
+          identifier: m.pub,
+          writtenOn,
+          pos: ud.dividendNumber,
+          created_on: ud.txCreatedOn,
+          written_on: writtenOn + '', // TODO
+          written_time: 0, // TODO
+          amount: ud.dividend.amount,
+          base: ud.dividend.base,
+          locktime: ud.txLocktime,
+          consumed: true,
+          conditions: 'SIG(' + m.pub + ')',
+          unlock: null,
+          txObj: null as any, // TODO
+          age: 0,
+        })
+      }
+    }
+    return entries
+  }
+
+  async trimConsumedUDs(belowNumber: number): Promise<void> {
+    // Remove dividends consumed before `belowNumber`
+    this.collection
+      .chain()
+      .find({})
+      .update(m => {
+        for (let i = 0; i < m.consumed.length; i++) {
+          const consumedBlockNumber = m.consumed[i]
+          if (consumedBlockNumber < belowNumber) {
+            // We trim this entry as it can't be reverted now
+            m.consumed.splice(i, 1)
+            m.consumedUDs.splice(i, 1)
+            i-- // The array changed, we loop back before i++
+          }
+        }
+      })
+  }
+}
diff --git a/app/lib/dal/indexDAL/loki/LokiIIndex.ts b/app/lib/dal/indexDAL/loki/LokiIIndex.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e0effa5d8c2660be973b3c58d8d116763d7abfee
--- /dev/null
+++ b/app/lib/dal/indexDAL/loki/LokiIIndex.ts
@@ -0,0 +1,180 @@
+import {FullIindexEntry, IindexEntry, Indexer} from "../../../indexer"
+import {IIndexDAO} from "../abstract/IIndexDAO"
+import {LokiPubkeySharingIndex} from "./LokiPubkeySharingIndex"
+import {OldIindexEntry} from "../../../db/OldIindexEntry"
+
+export class LokiIIndex extends LokiPubkeySharingIndex<IindexEntry> implements IIndexDAO {
+
+  constructor(loki:any) {
+    super(loki, 'iindex', [
+      'pub',
+      'uid',
+      'member',
+    ])
+  }
+
+  reducable(pub: string): Promise<IindexEntry[]> {
+    return this.findByPub(pub)
+  }
+
+  async findAllByWrittenOn(): Promise<IindexEntry[]> {
+    return this.collection.chain()
+      .find({})
+      .simplesort('writtenOn')
+      .data()
+  }
+
+  async findByPub(pub: string): Promise<IindexEntry[]> {
+    return this.collection.chain()
+      .find({ pub })
+      .simplesort('writtenOn')
+      .data()
+  }
+
+  async findByUid(uid: string): Promise<IindexEntry[]> {
+    return this.collection.chain()
+      .find({ uid })
+      .simplesort('writtenOn')
+      .data()
+  }
+
+  async getMembers(): Promise<{ pubkey: string; uid: string|null }[]> {
+    return this.collection
+      // Those who are still marked member somewhere
+      .find({ member: true })
+      // We reduce them
+      .map(r => {
+        return Indexer.DUP_HELPERS.reduce(
+          this.collection
+            .chain()
+            .find({ pub: r.pub })
+            .simplesort('writtenOn')
+            .data()
+        )
+      })
+      // We keep only the real members (because we could have excluded)
+      .filter(r => r.member)
+      // We map
+      .map(this.toCorrectEntity)
+  }
+
+  async getFromPubkey(pub: string): Promise<FullIindexEntry | null> {
+    return this.retrieveIdentityOnPubOrNull(
+      { pub }
+    ) as Promise<FullIindexEntry|null>
+  }
+
+  async getFromUID(uid: string): Promise<FullIindexEntry | null> {
+    return this.retrieveIdentityOnPubOrNull(
+      this.collection
+        .chain()
+        .find({ uid })
+        .data()[0]
+    ) as Promise<FullIindexEntry|null>
+  }
+
+  async getFromPubkeyOrUid(search: string): Promise<FullIindexEntry | null> {
+    const idty = await this.getFromPubkey(search)
+    if (idty) {
+      return idty
+    }
+    return this.getFromUID(search) as Promise<FullIindexEntry|null>
+  }
+
+  async searchThoseMatching(search: string): Promise<OldIindexEntry[]> {
+    const reducables = Indexer.DUP_HELPERS.reduceBy(this.collection
+      .chain()
+      .find({
+        $or: [
+          { pub: { $contains: search } },
+          { uid: { $contains: search } },
+        ]
+      })
+      .data()
+    , ['pub'])
+    // We get the full representation for each member
+    return await Promise.all(reducables.map(async (entry) => {
+      return this.toCorrectEntity(Indexer.DUP_HELPERS.reduce(await this.reducable(entry.pub)))
+    }))
+  }
+
+  async getFullFromUID(uid: string): Promise<FullIindexEntry> {
+    return (await this.getFromUID(uid)) as FullIindexEntry
+  }
+
+  async getFullFromPubkey(pub: string): Promise<FullIindexEntry> {
+    return (await this.getFromPubkey(pub)) as FullIindexEntry
+  }
+
+  async getFullFromHash(hash: string): Promise<FullIindexEntry> {
+    return this.retrieveIdentityOnPubOrNull(
+      this.collection
+        .chain()
+        .find({ hash })
+        .data()[0]
+    ) as Promise<FullIindexEntry>
+  }
+
+  async retrieveIdentityOnPubOrNull(entry:{ pub:string }|null) {
+    if (!entry) {
+      return null
+    }
+    return this.entityOrNull(
+      this.collection
+        .chain()
+        .find({ pub: entry.pub })
+        .simplesort('writtenOn')
+        .data()
+    ) as Promise<FullIindexEntry|null>
+  }
+
+  async getToBeKickedPubkeys(): Promise<string[]> {
+    return this.collection
+    // Those who are still marked member somewhere
+      .find({ kick: true })
+      // We reduce them
+      .map(r => {
+        return Indexer.DUP_HELPERS.reduce(
+          this.collection
+            .chain()
+            .find({ pub: r.pub })
+            .simplesort('writtenOn')
+            .data()
+        )
+      })
+      // We keep only the real members (because we could have excluded)
+      .filter(r => r.kick)
+      // We map
+      .map(r => r.pub)
+  }
+
+  private async entityOrNull(reducable:IindexEntry[]) {
+    if (reducable.length) {
+      return this.toCorrectEntity(Indexer.DUP_HELPERS.reduce(reducable))
+    }
+    return null
+  }
+
+  private toCorrectEntity(row:IindexEntry): OldIindexEntry {
+    // Old field
+    return {
+      pubkey: row.pub,
+      pub: row.pub,
+      buid: row.created_on,
+      revocation_sig: null,
+      uid: row.uid,
+      hash: row.hash,
+      sig: row.sig,
+      created_on: row.created_on,
+      member: row.member,
+      wasMember: row.wasMember,
+      kick: row.kick,
+      wotb_id: row.wotb_id,
+      age: row.age,
+      index: row.index,
+      op: row.op,
+      writtenOn: row.writtenOn,
+      written_on: row.written_on
+    }
+  }
+}
diff --git a/app/lib/dal/indexDAL/loki/LokiIndex.ts b/app/lib/dal/indexDAL/loki/LokiIndex.ts
new file mode 100644
index 0000000000000000000000000000000000000000..877cdc511c375456d8358d4057c81aa04d961d1d
--- /dev/null
+++ b/app/lib/dal/indexDAL/loki/LokiIndex.ts
@@ -0,0 +1,35 @@
+import {GenericDAO} from "../abstract/GenericDAO"
+import {LokiCollectionManager} from "./LokiCollectionManager"
+import {MonitorLokiExecutionTime} from "../../../debug/MonitorLokiExecutionTime"
+
+export abstract class LokiIndex<T> extends LokiCollectionManager<T> implements GenericDAO<T> {
+
+  cleanCache(): void {
+  }
+
+  async insert(record: T): Promise<void> {
+    this.collection.insert(record)
+  }
+
+  @MonitorLokiExecutionTime(true)
+  async findRaw(criterion?:any) {
+    return this.collection.find(criterion)
+  }
+
+  @MonitorLokiExecutionTime(true)
+  async findRawWithOrder(criterion:any, sort:((string|((string|boolean)[]))[])) {
+    const res = this.collection
+      .chain()
+      .find(criterion)
+      .compoundsort(sort)
+    return res.data()
+  }
+
+  @MonitorLokiExecutionTime()
+  async insertBatch(records: T[]): Promise<void> {
+    records.map(r => this.insert(r))
+  }
+
+  abstract getWrittenOn(blockstamp: string): Promise<T[]>
+  abstract removeBlock(blockstamp: string): Promise<void>
+}
diff --git a/app/lib/dal/indexDAL/loki/LokiMIndex.ts b/app/lib/dal/indexDAL/loki/LokiMIndex.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5ab94e90c3ebf4644056be693d819f7509fb633c
--- /dev/null
+++ b/app/lib/dal/indexDAL/loki/LokiMIndex.ts
@@ -0,0 +1,63 @@
+import {FullMindexEntry, Indexer, MindexEntry} from "../../../indexer"
+import {MIndexDAO} from "../abstract/MIndexDAO"
+import {LokiPubkeySharingIndex} from "./LokiPubkeySharingIndex"
+
+export class LokiMIndex extends LokiPubkeySharingIndex<MindexEntry> implements MIndexDAO {
+
+  constructor(loki:any) {
+    super(loki, 'mindex', ['pub'])
+  }
+
+  async findByPubAndChainableOnGt(pub: string, medianTime: number): Promise<MindexEntry[]> {
+    return this.collection
+      .find({
+        $and: [
+          { pub },
+          { chainable_on: { $gt: medianTime } },
+        ]
+      })
+  }
+
+  async findExpiresOnLteAndRevokesOnGt(medianTime: number): Promise<MindexEntry[]> {
+    return this.collection
+      .find({
+        $and: [
+          { expires_on: { $lte: medianTime } },
+          { revokes_on: { $gt: medianTime } },
+        ]
+      })
+  }
+
+  async findRevokesOnLteAndRevokedOnIsNull(medianTime: number): Promise<MindexEntry[]> {
+    return this.collection
+      .find({
+        $and: [
+          { revokes_on: { $lte: medianTime } },
+          { revoked_on: null },
+        ]
+      })
+  }
+
+  async getReducedMS(pub: string): Promise<FullMindexEntry | null> {
+    const reducable = (await this.reducable(pub)) as (FullMindexEntry)[]
+    if (reducable.length) {
+      return Indexer.DUP_HELPERS.reduce(reducable)
+    }
+    return null
+  }
+
+  async getRevokedPubkeys(): Promise<string[]> {
+    return this.collection
+      .find({ revoked_on: { $gt: 0 } })
+      // We map
+      .map(r => r.pub)
+  }
+
+  async reducable(pub: string): Promise<MindexEntry[]> {
+    return this.collection.chain()
+      .find({ pub })
+      .simplesort('writtenOn')
+      .data()
+  }
+
+}
diff --git a/app/lib/dal/indexDAL/loki/LokiPeer.ts b/app/lib/dal/indexDAL/loki/LokiPeer.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c067aa2976b1379e0b8548677a4c44f0f329b2d8
--- /dev/null
+++ b/app/lib/dal/indexDAL/loki/LokiPeer.ts
@@ -0,0 +1,107 @@
+import {LokiCollectionManager} from "./LokiCollectionManager"
+import {PeerDAO} from "../abstract/PeerDAO"
+import {DBPeer} from "../../../db/DBPeer"
+
+export class LokiPeer extends LokiCollectionManager<DBPeer> implements PeerDAO {
+
+  constructor(loki:any) {
+    super(loki, 'peer', ['pubkey'])
+  }
+
+  async init(): Promise<void> {
+    await super.init();
+    this.cleanEmptyPeers()
+  }
+
+  cleanCache(): void {
+  }
+
+  async listAll(): Promise<DBPeer[]> {
+    return this.collection
+      .find({})
+  }
+
+  async withUPStatus(): Promise<DBPeer[]> {
+    return this.collection
+      .find({ status: 'UP' })
+  }
+
+  async getPeer(pubkey: string): Promise<DBPeer> {
+    return this.collection
+      .find({ pubkey })[0]
+  }
+
+  async insertBatch(peers: DBPeer[]): Promise<void> {
+    for (const p of peers) {
+      this.collection.insert(p)
+    }
+  }
+
+  async savePeer(peer: DBPeer): Promise<DBPeer> {
+    let updated = false
+    this.collection
+      .chain()
+      .find({ pubkey: peer.pubkey })
+      .update(p => {
+        p.version = peer.version
+        p.currency = peer.currency
+        p.status = peer.status
+        p.statusTS = peer.statusTS
+        p.hash = peer.hash
+        p.first_down = peer.first_down
+        p.last_try = peer.last_try
+        p.pubkey = peer.pubkey
+        p.block = peer.block
+        p.signature = peer.signature
+        p.endpoints = peer.endpoints
+        p.raw = peer.raw
+        updated = true
+      })
+    if (!updated) {
+      await this.insertBatch([peer])
+    }
+    return peer
+  }
+
+  async removePeerByPubkey(pubkey:string): Promise<void> {
+    this.collection
+      .chain()
+      .find({ pubkey })
+      .remove()
+  }
+
+  async removePeersDownBefore(thresholdTime:number): Promise<void> {
+    this.collection
+      .chain()
+      .find({
+        $and: [
+          { first_down: { $lt: thresholdTime } },
+          { first_down: { $gt: 0 } },
+        ]
+      })
+      .remove()
+  }
+
+  async removeAll(): Promise<void> {
+    this.collection
+      .chain()
+      .find({})
+      .remove()
+  }
+
+  async cleanEmptyPeers(): Promise<void> {
+    this.collection
+      .chain()
+      .find({})
+      .where(p => !p.endpoints || !p.endpoints.length)
+      .remove()
+  }
+
+  async getPeersWithEndpointsLike(ep: string): Promise<DBPeer[]> {
+    return this.collection
+      .chain()
+      .find({})
+      .where(p => p.endpoints.filter(ep => ep.indexOf(ep) !== -1).length > 0)
+      .data()
+  }
+}
\ No newline at end of file
diff --git a/app/lib/dal/indexDAL/loki/LokiProtocolIndex.ts b/app/lib/dal/indexDAL/loki/LokiProtocolIndex.ts
new file mode 100644
index 0000000000000000000000000000000000000000..90848ed997e145725805f3fd010efe8cde653dda
--- /dev/null
+++ b/app/lib/dal/indexDAL/loki/LokiProtocolIndex.ts
@@ -0,0 +1,23 @@
+import {GenericDAO} from "../abstract/GenericDAO"
+import {MonitorLokiExecutionTime} from "../../../debug/MonitorLokiExecutionTime"
+import {LokiIndex} from "./LokiIndex"
+
+export interface IndexData {
+  written_on: string
+  writtenOn: number
+}
+
+export abstract class LokiProtocolIndex<T extends IndexData> extends LokiIndex<T> implements GenericDAO<T> {
+
+  @MonitorLokiExecutionTime(true)
+  async getWrittenOn(blockstamp: string): Promise<T[]> {
+    const criterion:any = { writtenOn: parseInt(blockstamp) }
+    return this.collection.find(criterion)
+  }
+
+  @MonitorLokiExecutionTime(true)
+  async removeBlock(blockstamp: string): Promise<void> {
+    const data = await this.getWrittenOn(blockstamp)
+    data.map(d => this.collection.remove(d))
+  }
+}
diff --git a/app/lib/dal/indexDAL/loki/LokiPubkeySharingIndex.ts b/app/lib/dal/indexDAL/loki/LokiPubkeySharingIndex.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4fb0a3fd806263aff5d75b29e8d6d0fb721df1ef
--- /dev/null
+++ b/app/lib/dal/indexDAL/loki/LokiPubkeySharingIndex.ts
@@ -0,0 +1,39 @@
+import {Indexer} from "../../../indexer"
+import {MonitorLokiExecutionTime} from "../../../debug/MonitorLokiExecutionTime"
+import {LokiProtocolIndex} from "./LokiProtocolIndex"
+
+export class LokiPubkeySharingIndex<T extends { written_on:string, writtenOn:number, pub:string }> extends LokiProtocolIndex<T> {
+
+  @MonitorLokiExecutionTime(true)
+  async trimRecords(belowNumber: number): Promise<void> {
+    // TODO: may be optimized by only selecting new offseted records
+    const criterion:any = {
+      writtenOn: {
+        $lt: belowNumber
+      }
+    }
+    const trimmable = await this.collection
+      .chain()
+      .find(criterion)
+      .simplesort('writtenOn')
+      .data()
+    const trimmableByPub: { [pub:string]: T[] } = {}
+    for (const t of trimmable) {
+      if (!trimmableByPub[t.pub]) {
+        trimmableByPub[t.pub] = []
+      }
+      trimmableByPub[t.pub].push(t)
+    }
+    for (const pub of Object.keys(trimmableByPub)) {
+      if (trimmableByPub[pub].length > 1) {
+        // Remove the existing records
+        for (const t of trimmableByPub[pub]) {
+          this.collection.remove(t)
+        }
+        // Insert a new one that gathers them
+        const reduced = Indexer.DUP_HELPERS.reduce(trimmableByPub[pub])
+        this.collection.insert(reduced)
+      }
+    }
+  }
+}
diff --git a/app/lib/dal/indexDAL/loki/LokiSIndex.ts b/app/lib/dal/indexDAL/loki/LokiSIndex.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8038f3fff7e0a28ec337c09e958fe88877e28ad7
--- /dev/null
+++ b/app/lib/dal/indexDAL/loki/LokiSIndex.ts
@@ -0,0 +1,113 @@
+import {FullSindexEntry, Indexer, SimpleTxEntryForWallet, SindexEntry} from "../../../indexer"
+import {SIndexDAO} from "../abstract/SIndexDAO"
+import {Underscore} from "../../../common-libs/underscore"
+import {MonitorLokiExecutionTime} from "../../../debug/MonitorLokiExecutionTime"
+import {LokiProtocolIndex} from "./LokiProtocolIndex"
+import {LokiDividend} from "./LokiDividend"
+
+export class LokiSIndex extends LokiProtocolIndex<SindexEntry> implements SIndexDAO {
+
+  private lokiDividend: LokiDividend
+
+  constructor(loki:any) {
+    super(loki, 'sindex', ['identifier', 'conditions', 'writtenOn'])
+    this.lokiDividend = new LokiDividend(loki)
+  }
+
+  async findTxSourceByIdentifierPosAmountBase(identifier: string, pos: number, amount: number, base: number): Promise<SindexEntry[]> {
+    return this.collection
+      .chain()
+      .find({ identifier, pos, amount, base })
+      .simplesort('writtenOn')
+      .data()
+      .map(src => {
+        src.type = src.tx ? 'T' : 'D'
+        return src
+      })
+  }
+
+  async getAvailableForConditions(conditionsStr: string): Promise<SindexEntry[]> {
+    const sources = this.collection
+      .chain()
+      .find({ conditions: conditionsStr })
+      .simplesort('writtenOn')
+      .data()
+      .filter(s => this.collection.find({ identifier: s.identifier, pos: s.pos, consumed: true }).length === 0)
+      .map(src => {
+        src.type = src.tx ? 'T' : 'D'
+        return src
+      })
+    return Underscore.sortBy(sources, (row:SindexEntry) => row.type == 'D' ? 0 : 1)
+  }
+
+  async getAvailableForPubkey(pubkey: string): Promise<{ amount: number; base: number, conditions: string, identifier: string, pos: number }[]> {
+    return this.collection
+      .chain()
+      .find({ conditions: { $regex: 'SIG\\(' + pubkey + '\\)' } })
+      .simplesort('writtenOn')
+      .data()
+      .filter(s => this.collection.find({ identifier: s.identifier, pos: s.pos, consumed: true }).length === 0)
+      .map(src => {
+        src.type = src.tx ? 'T' : 'D'
+        return src
+      })
+  }
+
+  async getTxSource(identifier: string, pos: number): Promise<FullSindexEntry | null> {
+    const reducables = this.collection
+      .chain()
+      .find({ identifier, pos })
+      .compoundsort([['writtenOn', false], ['op', false]])
+      .data()
+      .map(src => {
+        src.type = src.tx ? 'T' : 'D'
+        return src
+      })
+    if (reducables.length === 0) {
+      return null
+    }
+    return Indexer.DUP_HELPERS.reduce(reducables)
+  }
+
+  @MonitorLokiExecutionTime(true)
+  async trimConsumedSource(belowNumber: number): Promise<void> {
+    const consumed = this.collection
+      .find({ writtenOn: { $lt: belowNumber }})
+      .filter(s => s.consumed)
+    for (const e of consumed) {
+      this.collection
+        .chain()
+        .find({
+          identifier: e.identifier,
+          pos: e.pos
+        })
+        .remove()
+    }
+  }
+
+  /**
+   * For SINDEX, trimming records <=> removing the consumed sources.
+   * @param {number} belowNumber Number below which a consumed source must be removed.
+   * @returns {Promise<void>}
+   */
+  async trimRecords(belowNumber: number): Promise<void> {
+    return this.trimConsumedSource(belowNumber)
+  }
+
+  async getWrittenOnTxs(blockstamp: string): Promise<SimpleTxEntryForWallet[]> {
+    const entries = (await this.getWrittenOn(blockstamp))
+    const res: SimpleTxEntryForWallet[] = []
+    entries.forEach(s => {
+      res.push({
+        srcType: 'T',
+        op: s.op,
+        conditions: s.conditions,
+        amount: s.amount,
+        base: s.base,
+        identifier: s.identifier,
+        pos: s.pos
+      })
+    })
+    return res
+  }
+}
diff --git a/app/lib/dal/indexDAL/loki/LokiTransactions.ts b/app/lib/dal/indexDAL/loki/LokiTransactions.ts
new file mode 100644
index 0000000000000000000000000000000000000000..78ebf7fe54f6a98a4a5364d3095ca76c784b03b5
--- /dev/null
+++ b/app/lib/dal/indexDAL/loki/LokiTransactions.ts
@@ -0,0 +1,200 @@
+// 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 * as moment from "moment"
+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"
+import {LokiProtocolIndex} from "./LokiProtocolIndex"
+
+const constants = require('../../../constants')
+
+export class LokiTransactions extends LokiProtocolIndex<DBTx> implements TxsDAO {
+
+  constructor(loki: any) {
+    super(loki, 'txs', [])
+    this.sandbox = new SandBox(
+      constants.SANDBOX_SIZE_TRANSACTIONS,
+      () => this.getSandboxTxs(),
+      (compared: { issuers: string[], output_base: number, output_amount: number },
+       reference: { issuers: string[], output_base: number, output_amount: number }
+      ) => {
+        if (compared.output_base < reference.output_base) {
+          return -1;
+        }
+        else if (compared.output_base > reference.output_base) {
+          return 1;
+        }
+        else if (compared.output_amount > reference.output_amount) {
+          return -1;
+        }
+        else if (compared.output_amount < reference.output_amount) {
+          return 1;
+        }
+        else {
+          return 0;
+        }
+      })
+  }
+
+  sandbox: SandBox<{ issuers: string[]; output_base: number; output_amount: number }>
+
+  async addLinked(tx: TransactionDTO, block_number: number, time: number): Promise<DBTx> {
+    const dbTx = DBTx.fromTransactionDTO(tx)
+    dbTx.block_number = block_number
+    dbTx.time = time
+    dbTx.received = moment().unix()
+    dbTx.written = true
+    dbTx.removed = false
+    dbTx.hash = tx.getHash()
+    await this.insertOrUpdate(dbTx)
+    return dbTx
+  }
+
+  async addPending(dbTx: DBTx): Promise<DBTx> {
+    dbTx.received = moment().unix()
+    dbTx.written = false
+    dbTx.removed = false
+    await this.insertOrUpdate(dbTx)
+    return dbTx
+  }
+
+  async insertOrUpdate(dbTx: DBTx): Promise<DBTx> {
+    const conditions = { hash: dbTx.hash }
+    const existing = (await this.findRaw(conditions))[0]
+    if (existing) {
+      // Existing block: we only allow to change the fork flag
+      this.collection
+        .chain()
+        .find(conditions)
+        .update(tx => {
+          tx.block_number = dbTx.block_number
+          tx.time = dbTx.time
+          tx.received = dbTx.received
+          tx.written = dbTx.written
+          tx.removed = dbTx.removed
+          tx.hash = dbTx.hash
+        })
+    }
+    else if (!existing) {
+      await this.insert(dbTx)
+    }
+    return dbTx
+  }
+
+  async getAllPending(versionMin: number): Promise<DBTx[]> {
+    return this.findRaw({
+      written: false,
+      removed: false,
+      version: {$gte: versionMin}
+    })
+  }
+
+  async getLinkedWithIssuer(pubkey: string): Promise<DBTx[]> {
+    return this.findRaw({
+      issuers: {$contains: pubkey},
+      written: true
+    })
+  }
+
+  async getLinkedWithRecipient(pubkey: string): Promise<DBTx[]> {
+    const rows = await this.findRaw({
+      recipients: {$contains: pubkey},
+      written: true
+    })
+    // Which does not contains the key as issuer
+    return Underscore.filter(rows, (row: DBTx) => row.issuers.indexOf(pubkey) === -1);
+  }
+
+  async getPendingWithIssuer(pubkey: string): Promise<DBTx[]> {
+    return this.findRaw({
+      issuers: {$contains: pubkey},
+      written: false,
+      removed: false
+    })
+  }
+
+  async getPendingWithRecipient(pubkey: string): Promise<DBTx[]> {
+    return this.findRaw({
+      recipients: {$contains: pubkey},
+      written: false,
+      removed: false
+    })
+  }
+
+  async getTX(hash: string): Promise<DBTx> {
+    return (await this.findRaw({
+      hash: hash
+    }))[0]
+  }
+
+  async removeTX(hash: string): Promise<DBTx | null> {
+    let txRemoved = null
+    await this.collection
+      .chain()
+      .find({
+        hash: hash
+      })
+      .update(tx => {
+        tx.removed = true
+        txRemoved = tx
+      })
+    return txRemoved
+  }
+
+  async removeAll(): Promise<void> {
+    await this.collection
+      .chain()
+      .find({})
+      .remove()
+  }
+
+  async trimExpiredNonWrittenTxs(limitTime: number): Promise<void> {
+    await this.collection
+      .chain()
+      .find({
+        written: false,
+        blockstampTime: {$lte: limitTime}
+      })
+      .remove()
+  }
+
+  /**************************
+   * SANDBOX STUFF
+   */
+
+  async getSandboxTxs() {
+    // SELECT * FROM txs WHERE NOT written AND NOT removed ORDER BY output_base DESC, output_amount DESC
+    // return this.query('SELECT * FROM sandbox_txs LIMIT ' + (this.sandbox.maxSize), [])
+    return this.collection
+      .chain()
+      .find({
+        written: false,
+        removed: false
+      })
+      .compoundsort(['output_base', ['output_amount', true]])
+      .limit(this.sandbox.maxSize)
+      .data()
+  }
+
+  getSandboxRoom() {
+    return this.sandbox.getSandboxRoom()
+  }
+
+  setSandboxSize(maxSize: number) {
+    this.sandbox.maxSize = maxSize
+  }
+
+}
diff --git a/app/lib/dal/indexDAL/loki/LokiTypes.ts b/app/lib/dal/indexDAL/loki/LokiTypes.ts
new file mode 100644
index 0000000000000000000000000000000000000000..08b8c21dc1518487c7b53f27361afec0754691b7
--- /dev/null
+++ b/app/lib/dal/indexDAL/loki/LokiTypes.ts
@@ -0,0 +1,47 @@
+
+export interface RealLokiCollection<T> {
+
+  data: T[]
+
+  length(): number
+
+  insert(entity:T): void
+
+  remove(entity:T): void
+
+  find(criterion:{ [t in keyof T|'$or'|'$and']?: any }): T[]
+
+  chain(): LokiChainableFind<T>
+
+  setChangesApi(disable: boolean): void
+
+  disableChangesApi: boolean
+
+  disableDeltaChangesApi: boolean
+
+  changes: any[]
+}
+
+export interface LokiCollection<T> extends RealLokiCollection<T> {
+
+  collection: RealLokiCollection<T>
+}
+
+export interface LokiChainableFind<T> {
+
+  find(criterion:{ [t in keyof T|'$or'|'$and']?: any }): LokiChainableFind<T>
+
+  simplesort(prop:keyof T, desc?:boolean): LokiChainableFind<T>
+
+  limit(l:number): LokiChainableFind<T>
+
+  update(cb:(t:T) => void): LokiChainableFind<T>
+
+  where(filter:(t:T) => boolean): LokiChainableFind<T>
+
+  remove(): LokiChainableFind<T>
+
+  compoundsort(sort:((string|((string|boolean)[]))[])): LokiChainableFind<T>
+
+  data(): T[]
+}
\ No newline at end of file
diff --git a/app/lib/dal/indexDAL/loki/LokiWallet.ts b/app/lib/dal/indexDAL/loki/LokiWallet.ts
new file mode 100644
index 0000000000000000000000000000000000000000..caf8d31344051be9dca42cc31c05ac925945f2a2
--- /dev/null
+++ b/app/lib/dal/indexDAL/loki/LokiWallet.ts
@@ -0,0 +1,39 @@
+import {WalletDAO} from "../abstract/WalletDAO"
+import {LokiCollectionManager} from "./LokiCollectionManager"
+import {DBWallet} from "../../../db/DBWallet"
+
+export class LokiWallet extends LokiCollectionManager<DBWallet> implements WalletDAO {
+
+  constructor(loki:any) {
+    super(loki, 'wallet', ['conditions'])
+  }
+
+  cleanCache(): void {
+  }
+
+  async getWallet(conditions: string): Promise<DBWallet> {
+    return this.collection
+      .find({ conditions })[0]
+  }
+
+  async insertBatch(records: DBWallet[]): Promise<void> {
+    for (const w of records) {
+      this.collection.insert(w)
+    }
+  }
+
+  async saveWallet(wallet: DBWallet): Promise<DBWallet> {
+    let updated = false
+    this.collection
+      .chain()
+      .find({ conditions: wallet.conditions })
+      .update(w => {
+        w.balance = wallet.balance
+        updated = true
+      })
+    if (!updated) {
+      await this.insertBatch([wallet])
+    }
+    return wallet
+  }
+}
\ No newline at end of file
diff --git a/app/lib/dal/sqliteDAL/AbstractIndex.ts b/app/lib/dal/sqliteDAL/AbstractIndex.ts
deleted file mode 100644
index 298295be161751372f971eb068d046f45fe3b531..0000000000000000000000000000000000000000
--- a/app/lib/dal/sqliteDAL/AbstractIndex.ts
+++ /dev/null
@@ -1,61 +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 {AbstractSQLite, BeforeSaveHook} from "./AbstractSQLite";
-import {SQLiteDriver} from "../drivers/SQLiteDriver";
-import {IndexEntry, Indexer} from "../../indexer";
-
-const _ = require('underscore');
-
-export class AbstractIndex<T extends IndexEntry> extends AbstractSQLite<T> {
-
-  constructor(
-    driver:SQLiteDriver,
-    table: string,
-    pkFields: string[] = [],
-    fields: string[] = [],
-    arrays: string[] = [],
-    booleans: string[] = [],
-    bigintegers: string[] = [],
-    transientFields: string[] = [],
-    beforeSaveHook: BeforeSaveHook<T> | null = null
-  ) {
-    super(driver, table, pkFields, fields, arrays, booleans, bigintegers, transientFields, beforeSaveHook)
-  }
-
-  public async init() {}
-
-  getWrittenOn(blockstamp:string) {
-    return this.query('SELECT * FROM ' + this.table + ' WHERE written_on = ?', [blockstamp])
-  }
-
-  async trimRecords(belowNumber:number) {
-    const belowRecords:T[] = await this.query('SELECT COUNT(*) as nbRecords, pub FROM ' + this.table + ' ' +
-      'WHERE CAST(written_on as int) < ? ' +
-      'GROUP BY pub ' +
-      'HAVING nbRecords > 1', [belowNumber]);
-    const reducedByPub = Indexer.DUP_HELPERS.reduceBy(belowRecords, ['pub']);
-    for (const record of reducedByPub) {
-      const recordsOfPub = await this.query('SELECT * FROM ' + this.table + ' WHERE pub = ?', [record.pub]);
-      const toReduce = _.filter(recordsOfPub, (rec:T) => parseInt(rec.written_on) < belowNumber);
-      if (toReduce.length) {
-        // Clean the records in the DB
-        await this.exec('DELETE FROM ' + this.table + ' WHERE pub = \'' + record.pub + '\'');
-        const nonReduced = _.filter(recordsOfPub, (rec:T) => parseInt(rec.written_on) >= belowNumber);
-        const reduced = Indexer.DUP_HELPERS.reduce(toReduce);
-        // Persist
-        await this.insertBatch([reduced].concat(nonReduced));
-      }
-    }
-  }
-}
diff --git a/app/lib/dal/sqliteDAL/AbstractSQLite.ts b/app/lib/dal/sqliteDAL/AbstractSQLite.ts
index 8b9a13926764b7f8619b62dc7e57128a3afe23b8..2649520427b96e64cdde25ae981fb991596c841a 100644
--- a/app/lib/dal/sqliteDAL/AbstractSQLite.ts
+++ b/app/lib/dal/sqliteDAL/AbstractSQLite.ts
@@ -12,20 +12,18 @@
 // GNU Affero General Public License for more details.
 
 import {SQLiteDriver} from "../drivers/SQLiteDriver"
-/**
- * Created by cgeek on 22/08/15.
- */
+import {Initiable} from "./Initiable"
+import {Underscore} from "../../common-libs/underscore"
+import {NewLogger} from "../../logger"
+import {MonitorSQLExecutionTime} from "../../debug/MonitorSQLExecutionTime"
 
-const _ = require('underscore');
-const co = require('co');
-const colors = require('colors');
-const logger = require('../../logger').NewLogger('sqlite');
+const logger = NewLogger('sqlite')
 
 export interface BeforeSaveHook<T> {
   (t:T): void
 }
 
-export abstract class AbstractSQLite<T> {
+export abstract class AbstractSQLite<T> extends Initiable {
 
   constructor(
     private driver:SQLiteDriver,
@@ -38,28 +36,14 @@ export abstract class AbstractSQLite<T> {
     private transientFields: string[] = [],
     private beforeSaveHook: BeforeSaveHook<T> | null = null
   ) {
+    super()
   }
 
+  @MonitorSQLExecutionTime()
   async query(sql:string, params: any[] = []): Promise<T[]> {
     try {
-      //logger.trace(sql, JSON.stringify(params || []));
-      const start = Date.now()
       const res = await this.driver.executeAll(sql, params || []);
-      const duration = Date.now() - start;
-      const entities = res.map((t:T) => this.toEntity(t))
-      // Display result
-      let msg = sql + ' | %s\t==> %s rows in %s ms';
-      if (duration <= 2) {
-        msg = colors.green(msg);
-      } else if(duration <= 5) {
-        msg = colors.yellow(msg);
-      } else if (duration <= 10) {
-        msg = colors.magenta(msg);
-      } else if (duration <= 100) {
-        msg = colors.red(msg);
-      }
-      logger.query(msg, JSON.stringify(params || []), entities.length, duration);
-      return entities;
+      return res.map((t:T) => this.toEntity(t))
     } catch (e) {
       logger.error('ERROR >> %s', sql, JSON.stringify(params || []), e.stack || e.message || e);
       throw e;
@@ -81,7 +65,7 @@ export abstract class AbstractSQLite<T> {
   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);
   }
@@ -92,12 +76,12 @@ export abstract class AbstractSQLite<T> {
   }
 
   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]))
   }
 
@@ -145,14 +129,9 @@ export abstract class AbstractSQLite<T> {
     await this.query('DELETE FROM ' + this.table + ' WHERE ' + conditions, condValues)
   }
 
-  exec(sql:string): Promise<void> {
-    try {
-      //console.warn(sql);
-      return this.driver.executeSql(sql);
-    } catch (e) {
-      //console.error('ERROR >> %s', sql);
-      throw e;
-    }
+  @MonitorSQLExecutionTime()
+  async exec(sql:string) {
+    await this.driver.executeSql(sql)
   }
 
   getInsertQuery(): string {
@@ -197,8 +176,14 @@ export abstract class AbstractSQLite<T> {
     }
   }
 
+  /**
+   * To redefine if necessary in subclasses.
+   */
+  cleanCache() {
+  }
+
   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) {
@@ -219,7 +204,7 @@ export abstract class AbstractSQLite<T> {
 
   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/BlockDAL.ts b/app/lib/dal/sqliteDAL/BlockDAL.ts
deleted file mode 100644
index a595055e0ad00fa79937ad40755edfdfaa6e9b40..0000000000000000000000000000000000000000
--- a/app/lib/dal/sqliteDAL/BlockDAL.ts
+++ /dev/null
@@ -1,182 +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 {AbstractSQLite} from "./AbstractSQLite"
-import {SQLiteDriver} from "../drivers/SQLiteDriver"
-import {DBBlock} from "../../db/DBBlock"
-
-const constants = require('../../constants');
-
-const IS_FORK = true;
-const IS_NOT_FORK = false;
-
-export class BlockDAL extends AbstractSQLite<DBBlock> {
-
-  private current: any
-
-  constructor(driver:SQLiteDriver) {
-    super(
-      driver,
-      'block',
-      // PK fields
-      ['number','hash'],
-      // Fields
-      ['fork', 'hash', 'inner_hash', 'signature', 'currency', 'issuer', 'issuersCount', 'issuersFrame', 'issuersFrameVar', 'parameters', 'previousHash', 'previousIssuer', 'version', 'membersCount', 'monetaryMass', 'UDTime', 'medianTime', 'dividend', 'unitbase', 'time', 'powMin', 'number', 'nonce', 'transactions', 'certifications', 'identities', 'joiners', 'actives', 'leavers', 'revoked', 'excluded', 'len'],
-      // Arrays
-      ['identities','certifications','actives','revoked','excluded','leavers','joiners','transactions'],
-      // Booleans
-      ['wrong'],
-      // BigIntegers
-      ['monetaryMass'],
-      // Transient
-      []
-    )
-
-    /**
-     * Periodically cleans the current block cache.
-     * It seems the cache is not always correct and may stuck the node, so it is preferable to reset it periodically.
-     */
-    setInterval(this.cleanCache, constants.CURRENT_BLOCK_CACHE_DURATION);
-  }
-
-  async init() {
-    await this.exec('BEGIN;' +
-      'CREATE TABLE IF NOT EXISTS ' + this.table + ' (' +
-      'fork BOOLEAN NOT NULL,' +
-      'hash VARCHAR(64) NOT NULL,' +
-      'inner_hash VARCHAR(64) NOT NULL,' +
-      'signature VARCHAR(100) NOT NULL,' +
-      'currency VARCHAR(50) NOT NULL,' +
-      'issuer VARCHAR(50) NOT NULL,' +
-      'parameters VARCHAR(255),' +
-      'previousHash VARCHAR(64),' +
-      'previousIssuer VARCHAR(50),' +
-      'version INTEGER NOT NULL,' +
-      'membersCount INTEGER NOT NULL,' +
-      'monetaryMass VARCHAR(100) DEFAULT \'0\',' +
-      'UDTime DATETIME,' +
-      'medianTime DATETIME NOT NULL,' +
-      'dividend INTEGER DEFAULT \'0\',' +
-      'unitbase INTEGER NULL,' +
-      'time DATETIME NOT NULL,' +
-      'powMin INTEGER NOT NULL,' +
-      'number INTEGER NOT NULL,' +
-      'nonce INTEGER NOT NULL,' +
-      'transactions TEXT,' +
-      'certifications TEXT,' +
-      'identities TEXT,' +
-      'joiners TEXT,' +
-      'actives TEXT,' +
-      'leavers TEXT,' +
-      'revoked TEXT,' +
-      'excluded TEXT,' +
-      'created DATETIME DEFAULT NULL,' +
-      'updated DATETIME DEFAULT NULL,' +
-      'PRIMARY KEY (number,hash)' +
-      ');' +
-      'CREATE INDEX IF NOT EXISTS idx_block_hash ON block (hash);' +
-      'CREATE INDEX IF NOT EXISTS idx_block_fork ON block (fork);' +
-      'COMMIT;')
-  }
-
-  cleanCache() {
-    this.current = null
-  }
-
-  async getCurrent() {
-    if (!this.current) {
-      this.current = (await this.query('SELECT * FROM block WHERE NOT fork ORDER BY number DESC LIMIT 1'))[0];
-    }
-    return Promise.resolve(this.current)
-  }
-
-  async getBlock(number:string | number) {
-    return (await this.query('SELECT * FROM block WHERE number = ? and NOT fork', [parseInt(String(number))]))[0];
-  }
-
-  async getAbsoluteBlock(number:number, hash:string) {
-    return (await this.query('SELECT * FROM block WHERE number = ? and hash = ?', [number, hash]))[0];
-  }
-
-  getBlocks(start:number, end:number) {
-    return this.query('SELECT * FROM block WHERE number BETWEEN ? and ? and NOT fork ORDER BY number ASC', [start, end]);
-  }
-
-  async lastBlockWithDividend() {
-    return (await this.query('SELECT * FROM block WHERE dividend > 0 and NOT fork ORDER BY number DESC LIMIT 1'))[0];
-  }
-
-  async lastBlockOfIssuer(issuer:string) {
-    return (await this.query('SELECT * FROM block WHERE issuer = ? and NOT fork ORDER BY number DESC LIMIT 1', [issuer]))[0]
-  }
-
-  async getCountOfBlocksIssuedBy(issuer:string) {
-    let res: any = await this.query('SELECT COUNT(*) as quantity FROM block WHERE issuer = ? and NOT fork', [issuer]);
-    return res[0].quantity;
-  }
-
-  getForkBlocks() {
-    return this.query('SELECT * FROM block WHERE fork ORDER BY number');
-  }
-
-  getPotentialForkBlocks(numberStart:number, medianTimeStart:number, maxNumber:number) {
-    return this.query('SELECT * FROM block WHERE fork AND number >= ? AND number <= ? AND medianTime >= ? ORDER BY number DESC', [numberStart, maxNumber, medianTimeStart]);
-  }
-
-  getPotentialRoots() {
-    return this.query('SELECT * FROM block WHERE fork AND number = ?', [0])
-  }
-
-  getDividendBlocks() {
-    return this.query('SELECT * FROM block WHERE dividend IS NOT NULL ORDER BY number');
-  }
-
-  async saveBunch(blocks:DBBlock[]) {
-    let queries = "INSERT INTO block (" + this.fields.join(',') + ") VALUES ";
-    for (let i = 0, len = blocks.length; i < len; i++) {
-      let block = blocks[i];
-      queries += this.toInsertValues(block);
-      if (i + 1 < len) {
-        queries += ",\n";
-      }
-    }
-    await this.exec(queries);
-    this.cleanCache();
-  }
-
-  async saveBlock(block:DBBlock) {
-    let saved = await this.saveBlockAs(block, IS_NOT_FORK);
-    if (!this.current || this.current.number < block.number) {
-      this.current = block;
-    }
-    return saved;
-  }
-
-  saveSideBlock(block:DBBlock) {
-    return this.saveBlockAs(block, IS_FORK)
-  }
-
-  private async saveBlockAs(block:DBBlock, fork:boolean) {
-    block.fork = fork;
-    return await this.saveEntity(block);
-  }
-
-  async setSideBlock(number:number, previousBlock:DBBlock) {
-    await this.query('UPDATE block SET fork = ? WHERE number = ?', [true, number]);
-    this.current = previousBlock;
-  }
-
-  getNextForkBlocks(number:number, hash:string) {
-    return this.query('SELECT * FROM block WHERE fork AND number = ? AND previousHash like ? ORDER BY number', [number + 1, hash]);
-  }
-}
diff --git a/app/lib/dal/sqliteDAL/CertDAL.ts b/app/lib/dal/sqliteDAL/CertDAL.ts
index 2db48d0aeb067ccaacdfb32fb4df4a240b473d70..7cc11df2ee72e677f0dce703f5c629ae5b4b676f 100644
--- a/app/lib/dal/sqliteDAL/CertDAL.ts
+++ b/app/lib/dal/sqliteDAL/CertDAL.ts
@@ -13,16 +13,16 @@
 
 import {SQLiteDriver} from "../drivers/SQLiteDriver"
 import {AbstractSQLite} from "./AbstractSQLite"
-import { SandBox } from './SandBox';
-import { DBDocument } from './DocumentDAL';
+import {SandBox} from './SandBox';
+import {DBDocument} from './DocumentDAL';
 
 const constants = require('../../constants');
 
 export interface DBCert extends DBDocument {
   linked:boolean
   written:boolean
-  written_block:null
-  written_hash:null
+  written_block:number|null
+  written_hash:string|null
   sig:string
   block_number:number
   block_hash:string
diff --git a/app/lib/dal/sqliteDAL/IdentityDAL.ts b/app/lib/dal/sqliteDAL/IdentityDAL.ts
index b87f98e8ddf4560fd717a9591ddadd0cbd422d7b..af22cf43e9588faa108ab29d184cb6eb52e7c56e 100644
--- a/app/lib/dal/sqliteDAL/IdentityDAL.ts
+++ b/app/lib/dal/sqliteDAL/IdentityDAL.ts
@@ -13,10 +13,11 @@
 
 import {AbstractSQLite} from "./AbstractSQLite"
 import {SQLiteDriver} from "../drivers/SQLiteDriver"
-import { SandBox } from './SandBox';
+import {SandBox} from './SandBox';
 import {IdentityDTO} from "../../dto/IdentityDTO"
 import {Cloneable} from "../../dto/Cloneable";
-import { DBDocument } from './DocumentDAL';
+import {DBDocument} from './DocumentDAL';
+
 const constants = require('../../constants');
 
 export abstract class DBIdentity implements Cloneable {
@@ -26,7 +27,19 @@ export abstract class DBIdentity implements Cloneable {
   }
 
   certs:any[] = []
-  signed:any[] = []
+  signed: {
+    idty: {
+      pubkey: string
+      uid: string
+      buid: string
+      sig: string
+      member: string
+      wasMember: string
+    }
+    block_number: number
+    block_hash: string
+    sig: string
+  }[] = []
 
   revoked: boolean
   currentMSN: null
@@ -47,7 +60,11 @@ export abstract class DBIdentity implements Cloneable {
   expires_on: number
 
   getTargetHash() {
-    return IdentityDTO.getTargetHash(this)
+    return IdentityDTO.getTargetHash({
+      pub: this.pubkey,
+      created_on: this.buid,
+      uid: this.uid
+    })
   }
 
   json() {
@@ -71,7 +88,7 @@ export abstract class DBIdentity implements Cloneable {
         "timestamp": this.buid
       },
       "revoked": this.revoked,
-      "revoked_on": this.revoked_on,
+      "revoked_on": parseInt(String(this.revoked_on)),
       "revocation_sig": this.revocation_sig,
       "self": this.sig,
       "others": others
@@ -157,7 +174,7 @@ export class ExistingDBIdentity extends DBIdentity {
   }
 }
 
-export interface DBSandboxIdentity extends DBIdentity,DBDocument {
+export interface DBSandboxIdentity extends DBDocument {
   certsCount: number
   ref_block: number
 }
@@ -254,6 +271,10 @@ export class IdentityDAL extends AbstractSQLite<DBIdentity> {
     })
   }
 
+  setRevoked(pubkey: string) {
+    return this.query('UPDATE ' + this.table + ' SET revoked = ? WHERE pubkey = ?', [true, pubkey])
+  }
+
   getByHash(hash:string) {
     return this.sqlFindOne({
       hash: hash
@@ -278,7 +299,7 @@ export class IdentityDAL extends AbstractSQLite<DBIdentity> {
 
   getPendingIdentities() {
     return this.sqlFind({
-      revocation_sig: { $null: false },
+      revocation_sig: { $null: true },
       revoked: false
     })
   }
diff --git a/app/lib/dal/sqliteDAL/Initiable.ts b/app/lib/dal/sqliteDAL/Initiable.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c81fd7b7bf6f46ed257381a2241f8564054284b1
--- /dev/null
+++ b/app/lib/dal/sqliteDAL/Initiable.ts
@@ -0,0 +1,5 @@
+
+export abstract class Initiable {
+  abstract init(): Promise<void>
+  abstract cleanCache(): void
+}
diff --git a/app/lib/dal/sqliteDAL/MembershipDAL.ts b/app/lib/dal/sqliteDAL/MembershipDAL.ts
index 825559f03ef20efdcf91c002293a1c2950fa0f77..ddadff48d9138f1bc567666eb79405fa918584b2 100644
--- a/app/lib/dal/sqliteDAL/MembershipDAL.ts
+++ b/app/lib/dal/sqliteDAL/MembershipDAL.ts
@@ -13,9 +13,10 @@
 
 import {SQLiteDriver} from "../drivers/SQLiteDriver";
 import {AbstractSQLite} from "./AbstractSQLite";
-import { SandBox } from './SandBox';
-import { DBDocument } from './DocumentDAL';
-const _ = require('underscore');
+import {SandBox} from './SandBox';
+import {DBDocument} from './DocumentDAL';
+import {Underscore} from "../../common-libs/underscore"
+
 const constants = require('../../constants');
 
 export interface DBMembership extends DBDocument {
@@ -127,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) {
@@ -146,7 +147,7 @@ export class MembershipDAL extends AbstractSQLite<DBMembership> {
     return this.query('SELECT * FROM sandbox_memberships LIMIT ' + (this.sandbox.maxSize), [])
   }
 
-  sandbox = new SandBox(constants.SANDBOX_SIZE_MEMBERSHIPS, this.getSandboxMemberships.bind(this), (compared:DBMembership, reference:DBMembership) => {
+  sandbox = new SandBox(constants.SANDBOX_SIZE_MEMBERSHIPS, this.getSandboxMemberships.bind(this), (compared:{ block_number: number, issuers: string[] }, reference:{ block_number: number, issuers: string[] }) => {
     if (compared.block_number < reference.block_number) {
       return -1;
     }
diff --git a/app/lib/dal/sqliteDAL/MetaDAL.ts b/app/lib/dal/sqliteDAL/MetaDAL.ts
index fe48511cb584fec8c4a98366dec77593d197b77c..53b7b49086d1d7f1a21ff53d8448f7985ca1be03 100644
--- a/app/lib/dal/sqliteDAL/MetaDAL.ts
+++ b/app/lib/dal/sqliteDAL/MetaDAL.ts
@@ -14,23 +14,10 @@
 import {AbstractSQLite} from "./AbstractSQLite"
 import {SQLiteDriver} from "../drivers/SQLiteDriver"
 import {ConfDTO} from "../../dto/ConfDTO"
-import {SindexEntry} from "../../indexer"
-import {hashf} from "../../common"
 import {TransactionDTO} from "../../dto/TransactionDTO"
-import {BlockDAL} from "./BlockDAL"
 import {IdentityDAL} from "./IdentityDAL"
-import {SIndexDAL} from "./index/SIndexDAL"
-import {WalletDAL} from "./WalletDAL"
-import {MIndexDAL} from "./index/MIndexDAL"
-import {DBBlock} from "../../db/DBBlock"
-import {IdentityDTO} from "../../dto/IdentityDTO"
-import {rawer} from "../../common-libs/index"
-import {CommonConstants} from "../../common-libs/constants"
-import {TxsDAL} from "./TxsDAL"
-
-const _ = require('underscore')
+
 const logger = require('../../logger').NewLogger('metaDAL');
-const constants = require('./../../constants');
 
 export interface DBMeta {
   id: number,
@@ -67,7 +54,71 @@ export class MetaDAL extends AbstractSQLite<DBMeta> {
   private migrations:any = {
 
     // Test
-    0: 'BEGIN; COMMIT;',
+    0: 'BEGIN;' +
+
+    // This table was initially created by BlockDAL, but now it has been removed so we keep it here
+    // to keep the unit tests work
+    'CREATE TABLE IF NOT EXISTS block (' +
+    'fork BOOLEAN NOT NULL,' +
+    'hash VARCHAR(64) NOT NULL,' +
+    'inner_hash VARCHAR(64) NOT NULL,' +
+    'signature VARCHAR(100) NOT NULL,' +
+    'currency VARCHAR(50) NOT NULL,' +
+    'issuer VARCHAR(50) NOT NULL,' +
+    'parameters VARCHAR(255),' +
+    'previousHash VARCHAR(64),' +
+    'previousIssuer VARCHAR(50),' +
+    'version INTEGER NOT NULL,' +
+    'membersCount INTEGER NOT NULL,' +
+    'monetaryMass VARCHAR(100) DEFAULT \'0\',' +
+    'UDTime DATETIME,' +
+    'medianTime DATETIME NOT NULL,' +
+    'dividend INTEGER DEFAULT \'0\',' +
+    'unitbase INTEGER NULL,' +
+    'time DATETIME NOT NULL,' +
+    'powMin INTEGER NOT NULL,' +
+    'number INTEGER NOT NULL,' +
+    'nonce INTEGER NOT NULL,' +
+    'transactions TEXT,' +
+    'certifications TEXT,' +
+    'identities TEXT,' +
+    'joiners TEXT,' +
+    'actives TEXT,' +
+    'leavers TEXT,' +
+    'revoked TEXT,' +
+    'excluded TEXT,' +
+    'created DATETIME DEFAULT NULL,' +
+    'updated DATETIME DEFAULT NULL,' +
+    'PRIMARY KEY (number,hash)' +
+    ');' +
+    'CREATE INDEX IF NOT EXISTS idx_block_hash ON block (hash);' +
+    'CREATE INDEX IF NOT EXISTS idx_block_fork ON block (fork);' +
+
+    // Same, but for Transactions
+    'CREATE TABLE IF NOT EXISTS txs (' +
+    'hash CHAR(64) NOT NULL,' +
+    'block_number INTEGER,' +
+    'locktime INTEGER NOT NULL,' +
+    'version INTEGER NOT NULL,' +
+    'currency VARCHAR(50) NOT NULL,' +
+    'comment VARCHAR(255) NOT NULL,' +
+    'time DATETIME,' +
+    'inputs TEXT NOT NULL,' +
+    'unlocks TEXT NOT NULL,' +
+    'outputs TEXT NOT NULL,' +
+    'issuers TEXT NOT NULL,' +
+    'signatures TEXT NOT NULL,' +
+    'recipients TEXT NOT NULL,' +
+    'written BOOLEAN NOT NULL,' +
+    'removed BOOLEAN NOT NULL,' +
+    'PRIMARY KEY (hash)' +
+    ');' +
+    'CREATE INDEX IF NOT EXISTS idx_txs_issuers ON txs (issuers);' +
+    'CREATE INDEX IF NOT EXISTS idx_txs_written ON txs (written);' +
+    'CREATE INDEX IF NOT EXISTS idx_txs_removed ON txs (removed);' +
+    'CREATE INDEX IF NOT EXISTS idx_txs_hash ON txs (hash);' +
+
+    'COMMIT;',
 
     // Test
     1: 'BEGIN;' +
@@ -106,7 +157,7 @@ export class MetaDAL extends AbstractSQLite<DBMeta> {
     'ALTER TABLE block ADD COLUMN issuersCount INTEGER NULL;' +
     'COMMIT;',
     12: async () => {
-      let blockDAL = new BlockDAL(this.driverCopy)
+      let blockDAL = new MetaDAL(this.driverCopy)
       await blockDAL.exec('ALTER TABLE block ADD COLUMN len INTEGER NULL;');
       await blockDAL.exec('ALTER TABLE txs ADD COLUMN len INTEGER NULL;');
     },
@@ -148,161 +199,12 @@ export class MetaDAL extends AbstractSQLite<DBMeta> {
     16: async () => {},
 
     17: async () => {
-      let blockDAL = new BlockDAL(this.driverCopy)
-      let sindexDAL = new SIndexDAL(this.driverCopy)
-      const blocks = await blockDAL.query('SELECT * FROM block WHERE NOT fork');
-      type AmountPerKey = {
-        amounts: {
-          amount: number
-          comment:string
-        }[],
-        sources: {
-          amount:number
-          base:number
-          identifier:string
-          pos:number,
-          conditions:string
-          block:DBBlock,
-          tx:string|null
-        }[]
-      }
-      const amountsPerKey:{ [pub:string]: AmountPerKey[] } = {}
-      const members = [];
-      for (const b of blocks) {
-        const amountsInForBlockPerKey: { [pub:string]: AmountPerKey } = {};
-        for (const idty of b.identities) {
-          members.push(IdentityDTO.fromInline(idty).pubkey)
-        }
-        if (b.dividend) {
-          for (const member of members) {
-            amountsInForBlockPerKey[member] = amountsInForBlockPerKey[member] || { amounts: [], sources: [] };
-            amountsInForBlockPerKey[member].amounts.push({ amount: b.dividend * Math.pow(10, b.unitbase), comment: 'Dividend' });
-            amountsInForBlockPerKey[member].sources.push({ amount: b.dividend, base: b.unitbase, identifier: member, pos: b.number, block: b, tx: null, conditions: 'SIG(' + member + ')' });
-          }
-        }
-        const txs = b.transactions
-        for (let i = 0; i < txs.length; i++) {
-          const tx = txs[i];
-          tx.hash = hashf(rawer.getTransaction(b.transactions[i]))
-          for (const input of tx.inputsAsObjects()) {
-            amountsInForBlockPerKey[tx.issuers[0]] = amountsInForBlockPerKey[tx.issuers[0]] || { amounts: [], sources: [] };
-            amountsInForBlockPerKey[tx.issuers[0]].amounts.push({ amount: -input.amount * Math.pow(10, input.base), comment: tx.comment || '######' });
-            amountsInForBlockPerKey[tx.issuers[0]].sources.push({
-              amount: input.amount,
-              base: input.base,
-              identifier: input.identifier,
-              pos: input.pos,
-              conditions: "",
-              block: b,
-              tx: tx.hash
-            })
-          }
-          const outputObjects = tx.outputsAsObjects()
-          for (let j = 0; j < outputObjects.length; j++) {
-            const output = outputObjects[j]
-            const conditions = output.conditions.match(/^SIG\((.+)\)$/);
-            if (conditions) {
-              amountsInForBlockPerKey[conditions[1]] = amountsInForBlockPerKey[conditions[1]] || { amounts: [], sources: [] };
-              amountsInForBlockPerKey[conditions[1]].amounts.push({ amount: output.amount * Math.pow(10, output.base), comment: tx.comment || '######' });
-              amountsInForBlockPerKey[conditions[1]].sources.push({
-                amount: output.amount,
-                base: output.base,
-                identifier: tx.hash,
-                pos: j,
-                conditions: output.conditions,
-                block: b,
-                tx: tx.hash
-              })
-            }
-          }
-        }
-        for (const key of Object.keys(amountsInForBlockPerKey)) {
-          amountsPerKey[key] = amountsPerKey[key] || [];
-          amountsPerKey[key].push(amountsInForBlockPerKey[key]);
-        }
-      }
-      const keysToSee = Object.keys(amountsPerKey);
-      const sourcesMovements: SindexEntry[] = [];
-      for (const key of keysToSee) {
-        const allCreates: any = {};
-        const allUpdates: any = {};
-        const amounts = amountsPerKey[key];
-        let balance = 0;
-        for (let j = 0; j < amounts.length; j++) {
-          const amountsInBlock = amounts[j].amounts;
-          for (let i = 0; i < amountsInBlock.length; i++) {
-            const a = amountsInBlock[i].amount;
-            const id = [amounts[j].sources[i].identifier, amounts[j].sources[i].pos].join('-');
-            if (a < 0) {
-              allUpdates[id] = amounts[j].sources[i];
-              delete allCreates[id];
-            } else {
-              allCreates[id] = amounts[j].sources[i];
-            }
-            balance += a;
-          }
-          if (balance > 0 && balance < 100) {
-            const sourcesToDelete = [];
-            for (const k of Object.keys(amountsPerKey)) {
-              for (const packet of amountsPerKey[k]) {
-                for (const src of packet.sources) {
-                  const id = [src.identifier, src.pos].join('-');
-                  if (src.conditions == 'SIG(' + key + ')' && allCreates[id]) {
-                    sourcesToDelete.push(src);
-                  }
-                }
-              }
-            }
-            const amountsToDelete = sourcesToDelete.map((src) => {
-              return {
-                amount: -src.amount * Math.pow(10, src.base),
-                comment: '--DESTRUCTION--'
-              };
-            });
-            amounts.splice(j + 1, 0, { amounts: amountsToDelete, sources: sourcesToDelete });
-          }
-        }
-        let amountMissing = 0;
-        await Promise.all(_.values(allCreates).map(async (src:any) => {
-          const exist = await sindexDAL.getSource(src.identifier, src.pos);
-          if (!exist || exist.consumed) {
-            amountMissing += src.amount;
-            const block = src.block;
-            sourcesMovements.push({
-              index: CommonConstants.I_INDEX,
-              op: CommonConstants.IDX_CREATE,
-              tx: src.tx,
-              identifier: src.identifier,
-              pos: src.pos,
-              unlock: null,
-              age: 0,
-              txObj: TransactionDTO.mock(),
-              created_on: null,
-              written_on: [block.number, block.hash].join('-'),
-              writtenOn: block.number,
-              written_time: block.medianTime,
-              locktime: src.locktime,
-              amount: src.amount,
-              base: src.base,
-              conditions: src.conditions,
-              consumed: false
-            });
-          }
-        }))
-        let amountNotDestroyed = 0;
-        await Promise.all(_.values(allUpdates).map(async (src:any) => {
-          const exist = await sindexDAL.getSource(src.identifier, src.pos);
-          if (exist && !exist.consumed) {
-            amountNotDestroyed += src.amount;
-          }
-        }))
-      }
-      await sindexDAL.insertBatch(sourcesMovements);
+      // This migration is now obsolete
     },
 
     18: 'BEGIN;' +
       // Add a `massReeval` column
-    'ALTER TABLE b_index ADD COLUMN massReeval VARCHAR(100) NOT NULL DEFAULT \'0\';' +
+    // 'ALTER TABLE b_index ADD COLUMN massReeval VARCHAR(100) NOT NULL DEFAULT \'0\';' +
     'COMMIT;',
 
     19: 'BEGIN;' +
@@ -314,33 +216,9 @@ export class MetaDAL extends AbstractSQLite<DBMeta> {
      * Feeds the table of wallets with balances
      */
     20: async () => {
-      let walletDAL = new WalletDAL(this.driverCopy)
-      let sindexDAL = new SIndexDAL(this.driverCopy)
-      const conditions = await sindexDAL.query('SELECT DISTINCT(conditions) FROM s_index')
-      for (const row of conditions) {
-        const wallet = {
-          conditions: row.conditions,
-          balance: 0
-        }
-        const amountsRemaining = await sindexDAL.getAvailableForConditions(row.conditions)
-        wallet.balance = amountsRemaining.reduce((sum:number, src:SindexEntry) => sum + src.amount * Math.pow(10, src.base), 0)
-        await walletDAL.saveWallet(wallet)
-      }
     },
 
-    /**
-     * Feeds the m_index.chainable_on
-     */
     21: async (conf:ConfDTO) => {
-      let blockDAL = new BlockDAL(this.driverCopy)
-      let mindexDAL = new MIndexDAL(this.driverCopy)
-      await mindexDAL.exec('ALTER TABLE m_index ADD COLUMN chainable_on INTEGER NULL;')
-      const memberships = await mindexDAL.query('SELECT * FROM m_index WHERE op = ?', [CommonConstants.IDX_CREATE])
-      for (const ms of memberships) {
-        const reference = await blockDAL.getBlock(parseInt(ms.written_on.split('-')[0]))
-        const updateQuery = 'UPDATE m_index SET chainable_on = ' + (reference.medianTime + conf.msPeriod) + ' WHERE pub = \'' + ms.pub + '\' AND op = \'CREATE\''
-        await mindexDAL.exec(updateQuery)
-      }
     },
 
     // Replay the wallet table feeding, because of a potential bug
@@ -349,41 +227,19 @@ export class MetaDAL extends AbstractSQLite<DBMeta> {
     },
 
     23: 'BEGIN;' +
-    // Add a `writtenOn` column for MISC Index
-    'ALTER TABLE m_index ADD COLUMN writtenOn INTEGER NOT NULL DEFAULT 0;' +
-    'ALTER TABLE i_index ADD COLUMN writtenOn INTEGER NOT NULL DEFAULT 0;' +
-    'ALTER TABLE s_index ADD COLUMN writtenOn INTEGER NOT NULL DEFAULT 0;' +
-    'ALTER TABLE c_index ADD COLUMN writtenOn INTEGER NOT NULL DEFAULT 0;' +
-    'CREATE INDEX IF NOT EXISTS idx_mindex_writtenOn ON m_index (writtenOn);' +
-    'CREATE INDEX IF NOT EXISTS idx_iindex_writtenOn ON i_index (writtenOn);' +
-    'CREATE INDEX IF NOT EXISTS idx_sindex_writtenOn ON s_index (writtenOn);' +
-    'CREATE INDEX IF NOT EXISTS idx_cindex_writtenOn ON c_index (writtenOn);' +
-    'UPDATE m_index SET writtenOn = CAST(written_on as integer);' +
-    'UPDATE i_index SET writtenOn = CAST(written_on as integer);' +
-    'UPDATE s_index SET writtenOn = CAST(written_on as integer);' +
-    'UPDATE c_index SET writtenOn = CAST(written_on as integer);' +
     'COMMIT;',
 
     /**
      * Feeds the m_index.chainable_on correctly
      */
     24: async (conf:ConfDTO) => {
-      let blockDAL = new BlockDAL(this.driverCopy)
-      let mindexDAL = new MIndexDAL(this.driverCopy)
-      const memberships = await mindexDAL.query('SELECT * FROM m_index')
-      for (const ms of memberships) {
-        const reference = await blockDAL.getBlock(parseInt(ms.written_on.split('-')[0]))
-        const msPeriod = conf.msWindow // It has the same value, as it was not defined on currency init
-        const updateQuery = 'UPDATE m_index SET chainable_on = ' + (reference.medianTime + msPeriod) + ' WHERE pub = \'' + ms.pub + '\' AND written_on = \'' + ms.written_on +  '\''
-        await mindexDAL.exec(updateQuery)
-      }
     },
 
     /**
      * Wrong transaction storage
      */
     25: async () => {
-      const txsDAL = new TxsDAL(this.driverCopy)
+      const txsDAL:any = new MetaDAL(this.driverCopy)
       const wrongTXS = await txsDAL.query('SELECT * FROM txs WHERE outputs LIKE ? OR inputs LIKE ?', ['%amount%', '%amount%'])
       let i = 1
       for (const tx of wrongTXS) {
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/dal/sqliteDAL/TxsDAL.ts b/app/lib/dal/sqliteDAL/TxsDAL.ts
deleted file mode 100644
index 278220cd13823032757bed038aad417e5adf4d1b..0000000000000000000000000000000000000000
--- a/app/lib/dal/sqliteDAL/TxsDAL.ts
+++ /dev/null
@@ -1,279 +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 {AbstractSQLite} from "./AbstractSQLite"
-import {SQLiteDriver} from "../drivers/SQLiteDriver"
-import {TransactionDTO} from "../../dto/TransactionDTO"
-import {SandBox} from "./SandBox"
-
-const _ = require('underscore');
-const moment = require('moment');
-const constants = require('../../constants');
-
-export class DBTx {
-  hash: string
-  block_number: number | null
-  locktime: number
-  version: number
-  currency: string
-  comment: string
-  blockstamp: string
-  blockstampTime: number | null
-  time: number | null
-  inputs: string[]
-  unlocks: string[]
-  outputs: string[]
-  issuers: string[]
-  signatures: string[]
-  recipients: string[]
-  written: boolean
-  removed: boolean
-  received: number
-  output_base: number
-  output_amount: number
-
-  static fromTransactionDTO(tx:TransactionDTO) {
-    const dbTx = new DBTx()
-    dbTx.hash = tx.hash
-    dbTx.locktime = tx.locktime
-    dbTx.version = tx.version
-    dbTx.currency = tx.currency
-    dbTx.blockstamp = tx.blockstamp
-    dbTx.blockstampTime = tx.blockstampTime
-    dbTx.comment = tx.comment || ""
-    dbTx.inputs = tx.inputs
-    dbTx.unlocks = tx.unlocks
-    dbTx.outputs = tx.outputs
-    dbTx.issuers = tx.issuers
-    dbTx.signatures = tx.signatures
-    dbTx.recipients = tx.outputsAsRecipients()
-    dbTx.written = false
-    dbTx.removed = false
-    dbTx.output_base = tx.output_base
-    dbTx.output_amount = tx.output_amount
-    return dbTx
-  }
-
-  static setRecipients(txs:DBTx[]) {
-    // Each transaction must have a good "recipients" field for future searchs
-    txs.forEach((tx) => tx.recipients = DBTx.outputs2recipients(tx))
-  }
-
-  static outputs2recipients(tx:DBTx) {
-    return tx.outputs.map(function(out) {
-      const recipent = out.match('SIG\\((.*)\\)')
-      return (recipent && recipent[1]) || 'UNKNOWN'
-    })
-  }
-}
-
-export class TxsDAL extends AbstractSQLite<DBTx> {
-
-  constructor(driver:SQLiteDriver) {
-    super(
-      driver,
-      'txs',
-      // PK fields
-      ['hash'],
-      // Fields
-      [
-        'hash',
-        'block_number',
-        'version',
-        'currency',
-        'comment',
-        'blockstamp',
-        'blockstampTime',
-        'locktime',
-        'received',
-        'time',
-        'written',
-        'removed',
-        'inputs',
-        'unlocks',
-        'outputs',
-        'issuers',
-        'signatures',
-        'recipients',
-        'output_base',
-        'output_amount'
-      ],
-      // Arrays
-      ['inputs','unlocks','outputs','issuers','signatures','recipients'],
-      // Booleans
-      ['written','removed'],
-      // BigIntegers
-      [],
-      // Transient
-      []
-    )
-  }
-
-  async init() {
-    await this.exec('BEGIN;' +
-      'CREATE TABLE IF NOT EXISTS ' + this.table + ' (' +
-      'hash CHAR(64) NOT NULL,' +
-      'block_number INTEGER,' +
-      'locktime INTEGER NOT NULL,' +
-      'version INTEGER NOT NULL,' +
-      'currency VARCHAR(50) NOT NULL,' +
-      'comment VARCHAR(255) NOT NULL,' +
-      'time DATETIME,' +
-      'inputs TEXT NOT NULL,' +
-      'unlocks TEXT NOT NULL,' +
-      'outputs TEXT NOT NULL,' +
-      'issuers TEXT NOT NULL,' +
-      'signatures TEXT NOT NULL,' +
-      'recipients TEXT NOT NULL,' +
-      'written BOOLEAN NOT NULL,' +
-      'removed BOOLEAN NOT NULL,' +
-      'PRIMARY KEY (hash)' +
-      ');' +
-      'CREATE INDEX IF NOT EXISTS idx_txs_issuers ON txs (issuers);' +
-      'CREATE INDEX IF NOT EXISTS idx_txs_written ON txs (written);' +
-      'CREATE INDEX IF NOT EXISTS idx_txs_removed ON txs (removed);' +
-      'CREATE INDEX IF NOT EXISTS idx_txs_hash ON txs (hash);' +
-      'COMMIT;')
-  }
-
-  getAllPending(versionMin:number): Promise<DBTx[]> {
-    return this.sqlFind({
-      written: false,
-      removed: false,
-      version: { $gte: versionMin }
-    })
-  }
-
-  getTX(hash:string): Promise<DBTx> {
-    return this.sqlFindOne({
-      hash: hash
-    })
-  }
-
-  async removeTX(hash:string) {
-    const tx = await this.sqlFindOne({
-      hash: hash
-    });
-    if (tx) {
-      tx.removed = true;
-      return this.saveEntity(tx);
-    }
-    return tx
-  }
-
-  addLinked(tx:TransactionDTO, block_number:number, time:number) {
-    const dbTx = DBTx.fromTransactionDTO(tx)
-    dbTx.block_number = block_number
-    dbTx.time = time
-    dbTx.received = moment().unix()
-    dbTx.written = true
-    dbTx.removed = false
-    dbTx.hash = tx.getHash()
-    return this.saveEntity(dbTx)
-  }
-
-  addPending(dbTx:DBTx) {
-    dbTx.received = moment().unix()
-    dbTx.written = false
-    dbTx.removed = false
-    return this.saveEntity(dbTx)
-  }
-
-  getLinkedWithIssuer(pubkey:string): Promise<DBTx[]> {
-    return this.sqlFind({
-      issuers: { $contains: pubkey },
-      written: true
-    })
-  }
-
-  async getLinkedWithRecipient(pubkey:string) {
-    const rows = await this.sqlFind({
-      recipients: { $contains: pubkey },
-      written: true
-    })
-    // Which does not contains the key as issuer
-    return _.filter(rows, (row:DBTx) => row.issuers.indexOf(pubkey) === -1);
-  }
-
-  getPendingWithIssuer(pubkey:string) {
-    return this.sqlFind({
-      issuers: { $contains: pubkey },
-      written: false,
-      removed: false
-    })
-  }
-
-  getPendingWithRecipient(pubkey:string) {
-    return this.sqlFind({
-      recipients: { $contains: pubkey },
-      written: false,
-      removed: false
-    })
-  }
-
-  insertBatchOfTxs(txs:DBTx[]) {
-    // // Be sure the recipients field are correctly updated
-    DBTx.setRecipients(txs);
-    const queries = [];
-    const insert = this.getInsertHead();
-    const values = txs.map((cert) => this.getInsertValue(cert));
-    if (txs.length) {
-      queries.push(insert + '\n' + values.join(',\n') + ';');
-    }
-    if (queries.length) {
-      this.exec(queries.join('\n'));
-    }
-  }
-
-  trimExpiredNonWrittenTxs(limitTime:number) {
-    return this.exec("DELETE FROM txs WHERE NOT written AND blockstampTime <= " + limitTime)
-  }
-
-  getTransactionByExtendedHash(hash:string) {
-    return this.query("SELECT * FROM txs WHERE hash = ? OR v4_hash = ? OR v5_hash = ?", [hash, hash, hash])
-  }
-
-  /**************************
-   * SANDBOX STUFF
-   */
-
-  getSandboxTxs() {
-    return this.query('SELECT * FROM sandbox_txs LIMIT ' + (this.sandbox.maxSize), [])
-  }
-
-  sandbox = new SandBox(constants.SANDBOX_SIZE_TRANSACTIONS, this.getSandboxTxs.bind(this), (compared:DBTx, reference:DBTx) => {
-    if (compared.output_base < reference.output_base) {
-      return -1;
-    }
-    else if (compared.output_base > reference.output_base) {
-      return 1;
-    }
-    else if (compared.output_amount > reference.output_amount) {
-      return -1;
-    }
-    else if (compared.output_amount < reference.output_amount) {
-      return 1;
-    }
-    else {
-      return 0;
-    }
-  })
-
-  getSandboxRoom() {
-    return this.sandbox.getSandboxRoom()
-  }
-
-  setSandboxSize(maxSize:number) {
-    this.sandbox.maxSize = maxSize
-  }
-}
diff --git a/app/lib/dal/sqliteDAL/WalletDAL.ts b/app/lib/dal/sqliteDAL/WalletDAL.ts
deleted file mode 100644
index 03644eac336e68f87d759b30d371e1285d08630c..0000000000000000000000000000000000000000
--- a/app/lib/dal/sqliteDAL/WalletDAL.ts
+++ /dev/null
@@ -1,69 +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 interface DBWallet {
-  conditions: string
-  balance: number
-}
-
-/**
- * Facility table saving the current state of a wallet.
- * @param driver SQL driver for making SQL requests.
- * @constructor
- */
-export class WalletDAL extends AbstractSQLite<DBWallet> {
-
-  constructor(driver:SQLiteDriver) {
-    super(
-      driver,
-      'wallet',
-      // PK fields
-      ['conditions'],
-      // Fields
-      [
-        'conditions',
-        'balance'
-      ],
-      // Arrays
-      [],
-      // Booleans
-      [],
-      // BigIntegers
-      ['monetaryMass'],
-      // Transient
-      []
-    )
-  }
-
-  async init() {
-    await this.exec('BEGIN;' +
-      'CREATE TABLE IF NOT EXISTS ' + this.table + ' (' +
-      'conditions TEXT NOT NULL,' +
-      'balance INTEGER NOT NULL,' +
-      'PRIMARY KEY (conditions)' +
-      ');' +
-      'CREATE INDEX IF NOT EXISTS wallet_balance ON wallet(balance);' +
-      'COMMIT;')
-  }
-
-  getWallet(conditions:string) {
-    return this.sqlFindOne({ conditions })
-  }
-
-  saveWallet(wallet:DBWallet) {
-    return this.saveEntity(wallet)
-  }
-}
diff --git a/app/lib/dal/sqliteDAL/index/BIndexDAL.ts b/app/lib/dal/sqliteDAL/index/BIndexDAL.ts
index ee205dd490d68e2d81495238c249b928a7ffd04e..2b8537825305fec4f2bf995754acb0681bb76dc8 100644
--- a/app/lib/dal/sqliteDAL/index/BIndexDAL.ts
+++ b/app/lib/dal/sqliteDAL/index/BIndexDAL.ts
@@ -94,7 +94,7 @@ export class BIndexDAL extends AbstractSQLite<DBHead> {
    * Get HEAD~n
    * @param n Position
    */
-  async head(n:number) {
+  async head(n:number): Promise<DBHead> {
     if (!n) {
       throw "Cannot read HEAD~0, which is the incoming block"
     }
diff --git a/app/lib/dal/sqliteDAL/index/CIndexDAL.ts b/app/lib/dal/sqliteDAL/index/CIndexDAL.ts
deleted file mode 100644
index d0c58259a37ae6cc151f61cc5921f40c8e6649fe..0000000000000000000000000000000000000000
--- a/app/lib/dal/sqliteDAL/index/CIndexDAL.ts
+++ /dev/null
@@ -1,151 +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 {AbstractIndex} from "../AbstractIndex"
-import {SQLiteDriver} from "../../drivers/SQLiteDriver"
-import {CindexEntry} from "../../../indexer"
-import {CommonConstants} from "../../../common-libs/constants"
-
-const constants = require('./../../../constants');
-const indexer         = require('../../../indexer').Indexer
-
-export class CIndexDAL extends AbstractIndex<CindexEntry> {
-
-  constructor(driver:SQLiteDriver) {
-    super(
-      driver,
-      'c_index',
-      // PK fields
-      ['op', 'issuer', 'receiver', 'written_on'],
-      // Fields
-      [
-        'op',
-        'issuer',
-        'receiver',
-        'created_on',
-        'written_on',
-        'writtenOn',
-        'sig',
-        'expires_on',
-        'expired_on',
-        'chainable_on',
-        'from_wid',
-        'to_wid'
-      ],
-      // Arrays
-      [],
-      // Booleans
-      [],
-      // BigIntegers
-      [],
-      // Transient
-      []
-    )
-  }
-
-  async init() {
-    await this.exec('BEGIN;' +
-      'CREATE TABLE IF NOT EXISTS ' + this.table + ' (' +
-      'op VARCHAR(10) NOT NULL,' +
-      'issuer VARCHAR(50) NOT NULL,' +
-      'receiver VARCHAR(50) NOT NULL,' +
-      'created_on VARCHAR(80) NOT NULL,' +
-      'written_on VARCHAR(80) NOT NULL,' +
-      'sig VARCHAR(100) NULL,' +
-      'expires_on INTEGER NULL,' +
-      'expired_on INTEGER NULL,' +
-      'chainable_on INTEGER NULL,' +
-      'from_wid INTEGER NULL,' +
-      'to_wid INTEGER NULL,' +
-      'PRIMARY KEY (op,issuer,receiver,written_on)' +
-      ');' +
-      'CREATE INDEX IF NOT EXISTS idx_cindex_issuer ON c_index (issuer);' +
-      'CREATE INDEX IF NOT EXISTS idx_cindex_receiver ON c_index (receiver);' +
-      'CREATE INDEX IF NOT EXISTS idx_cindex_chainable_on ON c_index (chainable_on);' +
-      'COMMIT;')
-  }
-
-  async reducablesFrom(from:string) {
-    const reducables = await this.query('SELECT * FROM ' + this.table + ' WHERE issuer = ? ORDER BY CAST(written_on as integer) ASC', [from]);
-    return indexer.DUP_HELPERS.reduceBy(reducables, ['issuer', 'receiver', 'created_on']);
-  }
-
-  async trimExpiredCerts(belowNumber:number) {
-    const toDelete = await this.query('SELECT * FROM ' + this.table + ' WHERE expired_on > ? AND CAST(written_on as int) < ?', [0, belowNumber])
-    for (const row of toDelete) {
-      await this.exec("DELETE FROM " + this.table + " " +
-        "WHERE issuer like '" + row.issuer + "' " +
-        "AND receiver = '" + row.receiver + "' " +
-        "AND created_on like '" + row.created_on + "'");
-    }
-  }
-
-  getWrittenOn(blockstamp:string) {
-    return this.sqlFind({ written_on: blockstamp })
-  }
-
-  findExpired(medianTime:number) {
-    return this.query('SELECT * FROM ' + this.table + ' c1 WHERE expires_on <= ? ' +
-      'AND NOT EXISTS (' +
-      ' SELECT * FROM c_index c2' +
-      ' WHERE c1.issuer = c2.issuer' +
-      ' AND c1.receiver = c2.receiver' +
-      ' AND c1.created_on = c2.created_on' +
-      ' AND c2.op = ?' +
-      ')', [medianTime, CommonConstants.IDX_UPDATE])
-  }
-
-  getValidLinksTo(receiver:string) {
-    return this.query('SELECT * FROM ' + this.table + ' c1 ' +
-      'WHERE c1.receiver = ? ' +
-      'AND c1.expired_on = 0 ' +
-      'AND NOT EXISTS (' +
-      ' SELECT * FROM c_index c2' +
-      ' WHERE c1.issuer = c2.issuer' +
-      ' AND c1.receiver = c2.receiver' +
-      ' AND c1.created_on = c2.created_on' +
-      ' AND c2.op = ?' +
-      ')', [receiver, CommonConstants.IDX_UPDATE])
-  }
-
-  getValidLinksFrom(issuer:string) {
-    return this.query('SELECT * FROM ' + this.table + ' c1 ' +
-      'WHERE c1.issuer = ? ' +
-      'AND c1.expired_on = 0 ' +
-      'AND NOT EXISTS (' +
-      ' SELECT * FROM c_index c2' +
-      ' WHERE c1.issuer = c2.issuer' +
-      ' AND c1.receiver = c2.receiver' +
-      ' AND c1.created_on = c2.created_on' +
-      ' AND c2.op = ?' +
-      ')', [issuer, CommonConstants.IDX_UPDATE])
-  }
-
-  async existsNonReplayableLink(issuer:string, receiver:string) {
-    const results = await this.query('SELECT * FROM ' + this.table + ' c1 ' +
-      'WHERE c1.issuer = ? ' +
-      'AND c1.receiver = ? ' +
-      'AND NOT EXISTS (' +
-      ' SELECT * FROM c_index c2' +
-      ' WHERE c1.issuer = c2.issuer' +
-      ' AND c1.receiver = c2.receiver' +
-      ' AND c1.created_on = c2.created_on' +
-      ' AND c2.op = ?' +
-      ')', [issuer, receiver, CommonConstants.IDX_UPDATE]);
-    return results.length > 0;
-  }
-
-  removeBlock(blockstamp:string) {
-    return this.exec('DELETE FROM ' + this.table + ' WHERE written_on = \'' + blockstamp + '\'')
-  }
-}
diff --git a/app/lib/dal/sqliteDAL/index/IIndexDAL.ts b/app/lib/dal/sqliteDAL/index/IIndexDAL.ts
deleted file mode 100644
index c945ea994bc11b7c84a497fb51459111d58e79e3..0000000000000000000000000000000000000000
--- a/app/lib/dal/sqliteDAL/index/IIndexDAL.ts
+++ /dev/null
@@ -1,182 +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 {AbstractIndex} from "../AbstractIndex";
-import {IindexEntry, Indexer} from "../../../indexer";
-
-const _ = require('underscore');
-
-export interface OldIindexEntry extends IindexEntry {
-  pubkey: string
-  buid: string | null
-  revocation_sig:string | null
-}
-
-export class IIndexDAL extends AbstractIndex<IindexEntry> {
-
-  constructor(driver:SQLiteDriver) {
-    super(
-      driver,
-      'i_index',
-      // PK fields
-      ['op', 'pub', 'created_on', 'written_on'],
-      // Fields
-      [
-        'op',
-        'uid',
-        'pub',
-        'hash',
-        'sig',
-        'created_on',
-        'written_on',
-        'writtenOn',
-        'member',
-        'wasMember',
-        'kick',
-        'wotb_id'
-      ],
-      // Arrays
-      [],
-      // Booleans
-      ['member', 'wasMember', 'kick'],
-      // BigIntegers
-      [],
-      // Transient
-      []
-    )
-  }
-
-  init() {
-    return this.exec('BEGIN;' +
-      'CREATE TABLE IF NOT EXISTS ' + this.table + ' (' +
-      'op VARCHAR(10) NOT NULL,' +
-      'uid VARCHAR(100) NULL,' +
-      'pub VARCHAR(50) NOT NULL,' +
-      'hash VARCHAR(80) NULL,' +
-      'sig VARCHAR(80) NULL,' +
-      'created_on VARCHAR(80) NULL,' +
-      'written_on VARCHAR(80) NOT NULL,' +
-      'member BOOLEAN NULL,' +
-      'wasMember BOOLEAN NULL,' +
-      'kick BOOLEAN NULL,' +
-      'wotb_id INTEGER NULL,' +
-      'PRIMARY KEY (op,pub,created_on,written_on)' +
-      ');' +
-      'CREATE INDEX IF NOT EXISTS idx_iindex_pub ON i_index (pub);' +
-      'COMMIT;')
-  }
-
-  async getMembers() {
-    // All those who has been subject to, or who are currently subject to kicking. Make one result per pubkey.
-    const pubkeys = await this.query('SELECT DISTINCT(pub) FROM ' + this.table);
-    // We get the full representation for each member
-    const reduced = await Promise.all(pubkeys.map(async (entry) => {
-      const reducable = await this.reducable(entry.pub);
-      return Indexer.DUP_HELPERS.reduce(reducable);
-    }));
-    // Filter on those to be kicked, return their pubkey
-    const filtered = _.filter(reduced, (entry:IindexEntry) => entry.member);
-    return filtered.map((t:IindexEntry) => this.toCorrectEntity(t))
-  }
-
-  getMembersPubkeys() {
-    return this.query('SELECT i1.pub ' +
-      'FROM i_index i1 ' +
-      'WHERE i1.member ' +
-      'AND CAST(i1.written_on as int) = (' +
-      ' SELECT MAX(CAST(i2.written_on as int)) ' +
-      ' FROM i_index i2 ' +
-      ' WHERE i1.pub = i2.pub ' +
-      ' AND i2.member IS NOT NULL' +
-      ')')
-  }
-
-  async getToBeKickedPubkeys() {
-    // All those who has been subject to, or who are currently subject to kicking. Make one result per pubkey.
-    const reducables = Indexer.DUP_HELPERS.reduceBy(await this.sqlFind({ kick: true }), ['pub']);
-    // We get the full representation for each member
-    const reduced = await Promise.all(reducables.map(async (entry) => {
-      const reducable = await this.reducable(entry.pub);
-      return Indexer.DUP_HELPERS.reduce(reducable);
-    }))
-    // Filter on those to be kicked, return their pubkey
-    return _.filter(reduced, (entry:IindexEntry) => entry.kick).map((entry:IindexEntry) => entry.pub);
-  }
-
-  async searchThoseMatching(search:string) {
-    const reducables = Indexer.DUP_HELPERS.reduceBy(await this.sqlFindLikeAny({
-        pub: "%" + search + "%",
-        uid: "%" + search + "%"
-      }), ['pub']);
-    // We get the full representation for each member
-    return await Promise.all(reducables.map(async (entry) => {
-      return this.toCorrectEntity(Indexer.DUP_HELPERS.reduce(await this.reducable(entry.pub)))
-    }))
-  }
-
-  getFromPubkey(pubkey:string) {
-    return this.entityOrNull('pub', pubkey)
-  }
-
-  getFromUID(uid:string) {
-    return this.entityOrNull('uid', uid)
-  }
-
-  getFromHash(hash:string) {
-    return this.entityOrNull('hash', hash, true)
-  }
-
-  reducable(pub:string) {
-    return this.query('SELECT * FROM ' + this.table + ' WHERE pub = ? ORDER BY CAST(written_on as integer) ASC', [pub])
-  }
-
-  removeBlock(blockstamp:string) {
-    return this.exec('DELETE FROM ' + this.table + ' WHERE written_on = \'' + blockstamp + '\'')
-  }
-
-  private async entityOrNull(field:string, value:any, retrieveOnField:boolean = false) {
-    let reducable = await this.query('SELECT * FROM ' + this.table + ' WHERE ' + field + ' = ?', [value]);
-    if (reducable.length) {
-      if (retrieveOnField) {
-        // Force full retrieval on `pub` field
-        reducable = await this.query('SELECT * FROM ' + this.table + ' WHERE pub = ? ORDER BY CAST(written_on as int) ASC', [reducable[0].pub]);
-      }
-      return this.toCorrectEntity(Indexer.DUP_HELPERS.reduce(reducable));
-    }
-    return null;
-  }
-
-  private toCorrectEntity(row:IindexEntry): OldIindexEntry {
-    // Old field
-    return {
-      pubkey: row.pub,
-      pub: row.pub,
-      buid: row.created_on,
-      revocation_sig: null,
-      uid: row.uid,
-      hash: row.hash,
-      sig: row.sig,
-      created_on: row.created_on,
-      member: row.member,
-      wasMember: row.wasMember,
-      kick: row.kick,
-      wotb_id: row.wotb_id,
-      age: row.age,
-      index: row.index,
-      op: row.op,
-      writtenOn: row.writtenOn,
-      written_on: row.written_on
-    }
-  }
-}
diff --git a/app/lib/dal/sqliteDAL/index/MIndexDAL.ts b/app/lib/dal/sqliteDAL/index/MIndexDAL.ts
deleted file mode 100644
index 2ff64db3b98dccf02f17ba0c788be2a6ca628fe0..0000000000000000000000000000000000000000
--- a/app/lib/dal/sqliteDAL/index/MIndexDAL.ts
+++ /dev/null
@@ -1,94 +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 {AbstractIndex} from "../AbstractIndex";
-import {Indexer, MindexEntry} from "../../../indexer";
-
-export class MIndexDAL extends AbstractIndex<MindexEntry> {
-
-  constructor(driver:SQLiteDriver) {
-    super(
-      driver,
-      'm_index',
-      // PK fields
-      ['op', 'pub', 'created_on', 'written_on'],
-      // Fields
-      [
-        'op',
-        'pub',
-        'created_on',
-        'written_on',
-        'writtenOn',
-        'expires_on',
-        'expired_on',
-        'revokes_on',
-        'revoked_on',
-        'chainable_on',
-        'leaving',
-        'revocation'
-      ],
-      // Arrays
-      [],
-      // Booleans
-      ['leaving'],
-      // BigIntegers
-      [],
-      // Transient
-      []
-    )
-  }
-
-  async init() {
-    await this.exec('BEGIN;' +
-      'CREATE TABLE IF NOT EXISTS ' + this.table + ' (' +
-      'op VARCHAR(10) NOT NULL,' +
-      'pub VARCHAR(50) NOT NULL,' +
-      'created_on VARCHAR(80) NOT NULL,' +
-      'written_on VARCHAR(80) NOT NULL,' +
-      'expires_on INTEGER NULL,' +
-      'expired_on INTEGER NULL,' +
-      'revokes_on INTEGER NULL,' +
-      'revoked_on INTEGER NULL,' +
-      'leaving BOOLEAN NULL,' +
-      'revocation VARCHAR(80) NULL,' +
-      'PRIMARY KEY (op,pub,created_on,written_on)' +
-      ');' +
-      'CREATE INDEX IF NOT EXISTS idx_mindex_pub ON m_index (pub);' +
-      'COMMIT;')
-  }
-
-  async getReducedMS(pub:string) {
-    const reducables = await this.reducable(pub);
-    if (reducables.length) {
-      return Indexer.DUP_HELPERS.reduce(reducables);
-    }
-    return null;
-  }
-
-  reducable(pub:string) {
-    return this.query('SELECT * FROM ' + this.table + ' WHERE pub = ? ORDER BY CAST(written_on as integer) ASC', [pub])
-}
-
-  async removeBlock(blockstamp:string) {
-    return this.exec('DELETE FROM ' + this.table + ' WHERE written_on = \'' + blockstamp + '\'')
-  }
-
-  async getRevokedPubkeys() {
-    // All those who has been revoked. Make one result per pubkey.
-    const revovedMemberships = await this.sqlFind({ revoked_on: { $null: false} });
-
-    // Filter on those to be revoked, return their pubkey
-    return revovedMemberships.map((entry:MindexEntry) => entry.pub);
-  }
-}
diff --git a/app/lib/dal/sqliteDAL/index/SIndexDAL.ts b/app/lib/dal/sqliteDAL/index/SIndexDAL.ts
deleted file mode 100644
index 13115dcec1233b67a8654b4552c80772b404e726..0000000000000000000000000000000000000000
--- a/app/lib/dal/sqliteDAL/index/SIndexDAL.ts
+++ /dev/null
@@ -1,142 +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 {Indexer, SindexEntry} from "../../../indexer"
-import {SQLiteDriver} from "../../drivers/SQLiteDriver"
-import {AbstractIndex} from "../AbstractIndex"
-import {CommonConstants} from "../../../common-libs/constants"
-const _ = require('underscore');
-const constants = require('../../../constants');
-
-export class SIndexDAL extends AbstractIndex<SindexEntry> {
-
-  constructor(driver:SQLiteDriver) {
-    super(
-      driver,
-      's_index',
-      // PK fields
-      ['op', 'identifier', 'pos', 'written_on'],
-      // Fields
-      [
-        'op',
-        'tx',
-        'identifier',
-        'pos',
-        'created_on',
-        'written_on',
-        'writtenOn',
-        'written_time',
-        'amount',
-        'base',
-        'locktime',
-        'consumed',
-        'conditions'
-      ],
-      // Arrays
-      [],
-      // Booleans
-      ['consumed'],
-      // BigIntegers
-      [],
-      // Transient
-      []
-    )
-  }
-
-  async init() {
-    await this.exec('BEGIN;' +
-      'CREATE TABLE IF NOT EXISTS ' + this.table + ' (' +
-      'op VARCHAR(10) NOT NULL,' +
-      'tx VARCHAR(80) NULL,' +
-      'identifier VARCHAR(64) NOT NULL,' +
-      'pos INTEGER NOT NULL,' +
-      'created_on VARCHAR(80) NULL,' +
-      'written_on VARCHAR(80) NOT NULL,' +
-      'written_time INTEGER NOT NULL,' +
-      'amount INTEGER NULL,' +
-      'base INTEGER NULL,' +
-      'locktime INTEGER NULL,' +
-      'consumed BOOLEAN NOT NULL,' +
-      'conditions TEXT,' +
-      'PRIMARY KEY (op,identifier,pos,written_on)' +
-      ');' +
-      'CREATE INDEX IF NOT EXISTS idx_sindex_identifier ON s_index (identifier);' +
-      'CREATE INDEX IF NOT EXISTS idx_sindex_pos ON s_index (pos);' +
-      'COMMIT;')
-  }
-
-  async removeBlock(blockstamp:string) {
-    await this.exec('DELETE FROM ' + this.table + ' WHERE written_on = \'' + blockstamp + '\'')
-  }
-
-  async getSource(identifier:string, pos:number) {
-    const reducable = await this.query('SELECT * FROM ' + this.table + ' s1 ' +
-      'WHERE s1.identifier = ? ' +
-      'AND s1.pos = ? ' +
-      'ORDER BY op ASC', [identifier, pos]);
-    if (reducable.length == 0) {
-      return null;
-    } else {
-      const src = Indexer.DUP_HELPERS.reduce(reducable);
-      src.type = src.tx ? 'T' : 'D';
-      return src;
-    }
-  }
-
-  async getUDSources(pubkey:string) {
-    const reducables = await this.query('SELECT * FROM ' + this.table + ' s1 ' +
-      'WHERE conditions = ? ' +
-      'AND s1.tx IS NULL ' +
-      'ORDER BY op ASC', ['SIG(' + pubkey + ')']);
-    const reduced = Indexer.DUP_HELPERS.reduceBy(reducables, ['identifier', 'pos']).map((src) => {
-      src.type = src.tx ? 'T' : 'D';
-      return src;
-    });
-    return _.sortBy(reduced, (row:SindexEntry) => row.type == 'D' ? 0 : 1);
-  }
-
-  getAvailableForPubkey(pubkey:string) {
-    return this.getAvailableForConditions('%SIG(' + pubkey + ')%')
-  }
-
-  async getAvailableForConditions(conditionsStr:string) {
-    const potentials = await this.query('SELECT * FROM ' + this.table + ' s1 ' +
-      'WHERE s1.op = ? ' +
-      'AND conditions LIKE ? ' +
-      'AND NOT EXISTS (' +
-      ' SELECT * ' +
-      ' FROM s_index s2 ' +
-      ' WHERE s2.identifier = s1.identifier ' +
-      ' AND s2.pos = s1.pos ' +
-      ' AND s2.op = ?' +
-      ') ' +
-      'ORDER BY CAST(SUBSTR(written_on, 0, INSTR(written_on, "-")) as number)', [CommonConstants.IDX_CREATE, conditionsStr, CommonConstants.IDX_UPDATE]);
-    const sources = potentials.map((src) => {
-      src.type = src.tx ? 'T' : 'D';
-      return src;
-    });
-    return _.sortBy(sources, (row:SindexEntry) => row.type == 'D' ? 0 : 1);
-  }
-
-  async trimConsumedSource(belowNumber:number) {
-    const toDelete = await this.query('SELECT * FROM ' + this.table + ' WHERE consumed AND CAST(written_on as int) < ?', [belowNumber]);
-    const queries = [];
-    for (const row of toDelete) {
-      const sql = "DELETE FROM " + this.table + " " +
-        "WHERE identifier like '" + row.identifier + "' " +
-        "AND pos = " + row.pos;
-      queries.push(sql);
-    }
-    await this.exec(queries.join(';\n'));
-  }
-}
diff --git a/app/lib/db/DBBlock.ts b/app/lib/db/DBBlock.ts
index 9e9a7d7c950a2fd60cc18867fb6c8381d678e5d4..05e54ba8fca03f753d2153772d1b9f01666a45b9 100644
--- a/app/lib/db/DBBlock.ts
+++ b/app/lib/db/DBBlock.ts
@@ -47,6 +47,8 @@ export class DBBlock {
   monetaryMass: number
   dividend: number | null
   UDTime: number
+  writtenOn: number
+  written_on: string
   wrong = false
 
   constructor(
@@ -66,7 +68,7 @@ export class DBBlock {
     dbb.previousHash = b.previousHash
     dbb.issuer = b.issuer
     dbb.previousIssuer = b.previousIssuer
-    dbb.dividend = b.dividend
+    dbb.dividend = (b.dividend === null || b.dividend === undefined ? b.dividend : parseInt(String(b.dividend)))
     dbb.time = b.time
     dbb.powMin = b.powMin
     dbb.unitbase = b.unitbase
@@ -90,6 +92,8 @@ export class DBBlock {
     dbb.nonce = b.nonce
     dbb.UDTime = b.UDTime
     dbb.monetaryMass = b.monetaryMass
+    dbb.writtenOn = b.number
+    dbb.written_on = [b.number, b.hash].join('-')
     return dbb
   }
 }
\ No newline at end of file
diff --git a/app/lib/db/DBHead.ts b/app/lib/db/DBHead.ts
index ab4e48fcf3d86e4c5721beac1e1adcee57830642..8c97197e4a4a2ffadf81210cfad40c52ddedfbbe 100644
--- a/app/lib/db/DBHead.ts
+++ b/app/lib/db/DBHead.ts
@@ -45,6 +45,8 @@ export class DBHead {
   dividend: number
   new_dividend: number | null
   issuerIsMember: boolean
+  written_on: string
+  writtenOn: number
 
   constructor(
   ) {}
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/db/DBTransaction.ts b/app/lib/db/DBTransaction.ts
deleted file mode 100644
index 4e5bb3ab32addad01f05db020e2d992944e2042d..0000000000000000000000000000000000000000
--- a/app/lib/db/DBTransaction.ts
+++ /dev/null
@@ -1,72 +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 {TransactionDTO} from "../dto/TransactionDTO"
-
-export class DBTransaction extends TransactionDTO {
-
-  constructor(
-    public version: number,
-    public currency: string,
-    public locktime: number,
-    public hash: string,
-    public blockstamp: string,
-    public issuers: string[],
-    public inputs: string[],
-    public outputs: string[],
-    public unlocks: string[],
-    public signatures: string[],
-    public comment: string,
-    public blockstampTime: number,
-    public written: boolean,
-    public removed: boolean,
-    public block_number: number,
-    public time: number,
-  ) {
-    super(
-      version,
-      currency,
-      locktime,
-      hash,
-      blockstamp,
-      blockstampTime,
-      issuers,
-      inputs,
-      outputs,
-      unlocks,
-      signatures,
-      comment
-    )
-  }
-
-  static fromTransactionDTO(dto:TransactionDTO, blockstampTime:number, written: boolean, removed: boolean, block_number:number, block_medianTime:number) {
-    return new DBTransaction(
-      dto.version,
-      dto.currency,
-      dto.locktime,
-      dto.hash,
-      dto.blockstamp,
-      dto.issuers,
-      dto.inputs,
-      dto.outputs,
-      dto.unlocks,
-      dto.signatures,
-      dto.comment || "",
-      blockstampTime,
-      written,
-      removed,
-      block_number,
-      block_medianTime
-    )
-  }
-}
\ No newline at end of file
diff --git a/app/lib/db/DBTx.ts b/app/lib/db/DBTx.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1d47b7bb07530f1733ea58adc1b39f2fa2808b59
--- /dev/null
+++ b/app/lib/db/DBTx.ts
@@ -0,0 +1,60 @@
+import {TransactionDTO} from "../dto/TransactionDTO"
+
+export class DBTx {
+  hash: string
+  block_number: number | null
+  locktime: number
+  version: number
+  currency: string
+  comment: string
+  blockstamp: string
+  blockstampTime: number | null
+  time: number | null
+  inputs: string[]
+  unlocks: string[]
+  outputs: string[]
+  issuers: string[]
+  signatures: string[]
+  recipients: string[]
+  written: boolean
+  removed: boolean
+  received: number
+  output_base: number
+  output_amount: number
+  written_on: string
+  writtenOn: number
+
+  static fromTransactionDTO(tx:TransactionDTO) {
+    const dbTx = new DBTx()
+    dbTx.hash = tx.hash
+    dbTx.locktime = tx.locktime
+    dbTx.version = tx.version
+    dbTx.currency = tx.currency
+    dbTx.blockstamp = tx.blockstamp
+    dbTx.blockstampTime = tx.blockstampTime
+    dbTx.comment = tx.comment || ""
+    dbTx.inputs = tx.inputs
+    dbTx.unlocks = tx.unlocks
+    dbTx.outputs = tx.outputs
+    dbTx.issuers = tx.issuers
+    dbTx.signatures = tx.signatures
+    dbTx.recipients = tx.outputsAsRecipients()
+    dbTx.written = false
+    dbTx.removed = false
+    dbTx.output_base = tx.output_base
+    dbTx.output_amount = tx.output_amount
+    return dbTx
+  }
+
+  static setRecipients(txs:DBTx[]) {
+    // Each transaction must have a good "recipients" field for future searchs
+    txs.forEach((tx) => tx.recipients = DBTx.outputs2recipients(tx))
+  }
+
+  static outputs2recipients(tx:DBTx) {
+    return tx.outputs.map(function(out) {
+      const recipent = out.match('SIG\\((.*)\\)')
+      return (recipent && recipent[1]) || 'UNKNOWN'
+    })
+  }
+}
diff --git a/app/lib/db/DBWallet.ts b/app/lib/db/DBWallet.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d59c617d685ce73a1a4d0d7dc0ba7bf0394b8f23
--- /dev/null
+++ b/app/lib/db/DBWallet.ts
@@ -0,0 +1,4 @@
+export interface DBWallet {
+  conditions: string
+  balance: number
+}
diff --git a/app/lib/db/OldIindexEntry.ts b/app/lib/db/OldIindexEntry.ts
new file mode 100644
index 0000000000000000000000000000000000000000..308969f906b983034a717c6503d54ac9ca1eee61
--- /dev/null
+++ b/app/lib/db/OldIindexEntry.ts
@@ -0,0 +1,7 @@
+import {IindexEntry} from "../indexer"
+
+export interface OldIindexEntry extends IindexEntry {
+  pubkey: string
+  buid: string | null
+  revocation_sig:string | null
+}
diff --git a/app/lib/debug/MonitorFlushedIndex.ts b/app/lib/debug/MonitorFlushedIndex.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f2d083ccef8a0488a4f4cce955fe77cd6cf92072
--- /dev/null
+++ b/app/lib/debug/MonitorFlushedIndex.ts
@@ -0,0 +1,52 @@
+// 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 {cliprogram} from "../common-libs/programOptions"
+import {IndexBatch} from "../dal/fileDAL"
+
+export const MonitorFlushedIndex = function () {
+  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
+    const original = descriptor.value
+    if (original.__proto__.constructor.name === "AsyncFunction") {
+      descriptor.value = async function (...args:any[]) {
+        const pub = cliprogram.syncTrace
+        if (pub) {
+          const batch: IndexBatch = args[0]
+          batch.iindex.forEach(e => {
+            if (e.pub === pub) {
+              console.log(JSON.stringify(e))
+            }
+          })
+          batch.mindex.forEach(e => {
+            if (e.pub === pub) {
+              console.log(JSON.stringify(e))
+            }
+          })
+          batch.cindex.forEach(e => {
+            if (e.issuer === pub || e.receiver === pub) {
+              console.log(JSON.stringify(e))
+            }
+          })
+          batch.sindex.forEach(e => {
+            if (e.conditions.indexOf(pub || '') !== -1) {
+              console.log(JSON.stringify(e))
+            }
+          })
+        }
+        return await original.apply(this, args)
+      }
+    } else {
+      throw Error("Monitoring a synchronous function is not allowed.")
+    }
+  }
+}
\ No newline at end of file
diff --git a/app/lib/debug/MonitorLokiExecutionTime.ts b/app/lib/debug/MonitorLokiExecutionTime.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0491951af3e646bba96c9cfcc8ef5f55f0cb2297
--- /dev/null
+++ b/app/lib/debug/MonitorLokiExecutionTime.ts
@@ -0,0 +1,41 @@
+// 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 {NewLogger} from "../logger"
+import {getMicrosecondsTime} from "../../ProcessCpuProfiler"
+import {OtherConstants} from "../other_constants"
+
+const theLogger = NewLogger()
+
+export const MonitorLokiExecutionTime = function (dumpFirstParam = false) {
+  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
+    if (OtherConstants.ENABLE_LOKI_MONITORING) {
+      const original = descriptor.value
+      if (original.__proto__.constructor.name === "AsyncFunction") {
+        descriptor.value = async function (...args:any[]) {
+          const that :any = this
+          const now = getMicrosecondsTime()
+          const result = await original.apply(this, args)
+          if (dumpFirstParam) {
+            theLogger.trace('[loki][%s][%s] => %sµs', that.collectionName, propertyKey, (getMicrosecondsTime() - now), args && args[0])
+          } else {
+            theLogger.trace('[loki][%s][%s] => %sµs', that.collectionName, propertyKey, (getMicrosecondsTime() - now))
+          }
+          return result
+        }
+      } else {
+        throw Error("Monitoring a Loki synchronous function is not allowed.")
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/app/lib/debug/MonitorSQLExecutionTime.ts b/app/lib/debug/MonitorSQLExecutionTime.ts
new file mode 100644
index 0000000000000000000000000000000000000000..65724c527347f3df256933cbf1c1dcf582edd44d
--- /dev/null
+++ b/app/lib/debug/MonitorSQLExecutionTime.ts
@@ -0,0 +1,39 @@
+// 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 {getDurationInMicroSeconds, getMicrosecondsTime} from "../../ProcessCpuProfiler"
+import {NewLogger} from "../logger"
+import {OtherConstants} from "../other_constants"
+
+const theLogger = NewLogger()
+
+export const MonitorSQLExecutionTime = function () {
+  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
+    if (OtherConstants.ENABLE_SQL_MONITORING) {
+      const original = descriptor.value
+      if (original.__proto__.constructor.name === "AsyncFunction") {
+        descriptor.value = async function (...args: any[]) {
+          const start = getMicrosecondsTime()
+          const sql: string = args[0]
+          const params: any[] = args[1]
+          const entities: any[] = await original.apply(this, args)
+          const duration = getDurationInMicroSeconds(start)
+          theLogger.trace('[sqlite][query] %s %s %sµs', sql, JSON.stringify(params || []), duration)
+          return entities
+        }
+      } else {
+        throw Error("Monitoring an SQL synchronous function is not allowed.")
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/app/lib/dto/BlockDTO.ts b/app/lib/dto/BlockDTO.ts
index dba24f303c178e302669905b1448f080f9744c66..7ee505e4e5b51873b6796d202c1a081df553bad7 100644
--- a/app/lib/dto/BlockDTO.ts
+++ b/app/lib/dto/BlockDTO.ts
@@ -32,7 +32,7 @@ export class BlockDTO implements Cloneable {
   previousHash: string
   issuer: string
   previousIssuer: string
-  dividend: number
+  dividend: number|null
   time: number
   powMin: number
   unitbase: number
diff --git a/app/lib/dto/CertificationDTO.ts b/app/lib/dto/CertificationDTO.ts
index 45c2d2d403635dfd673e3ea25d1c9a5a66d6d788..66b76c92d9df315a8267dfece93d8cf622e3f7c5 100644
--- a/app/lib/dto/CertificationDTO.ts
+++ b/app/lib/dto/CertificationDTO.ts
@@ -63,8 +63,8 @@ export class CertificationDTO extends ShortCertificationDTO implements Cloneable
   getTargetHash() {
     return IdentityDTO.getTargetHash({
       uid: this.idty_uid,
-      buid: this.idty_buid,
-      pubkey: this.idty_issuer
+      created_on: this.idty_buid,
+      pub: this.idty_issuer
     })
   }
 
diff --git a/app/lib/dto/ConfDTO.ts b/app/lib/dto/ConfDTO.ts
index eb9ccef3391badfa479b1ed7dc1fdb013be73f3f..a95feec6ae550a2be1290de75d47bdef7d8cceb5 100644
--- a/app/lib/dto/ConfDTO.ts
+++ b/app/lib/dto/ConfDTO.ts
@@ -12,8 +12,9 @@
 // GNU Affero General Public License for more details.
 
 import {CommonConstants} from "../common-libs/constants"
-import { ProxiesConf } from '../proxy';
-const _ = require('underscore');
+import {ProxiesConf} from '../proxy';
+import {Underscore} from "../common-libs/underscore"
+
 const constants = require('../constants');
 
 export interface Keypair {
@@ -215,6 +216,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/IdentityDTO.ts b/app/lib/dto/IdentityDTO.ts
index b1ed24d2ee40b3d646ee10bd176c4b4c9591b7d8..5671987b0c2801dd1f820cae2d821a408ec48048 100644
--- a/app/lib/dto/IdentityDTO.ts
+++ b/app/lib/dto/IdentityDTO.ts
@@ -18,16 +18,26 @@ import {DBIdentity, NewDBIdentity} from "../dal/sqliteDAL/IdentityDAL"
 const DEFAULT_DOCUMENT_VERSION = 10
 
 export interface HashableIdentity {
+  created_on: string
+  uid: string
+  pub: string
+}
+
+export interface BasicIdentity {
   buid: string
   uid: string
   pubkey: string
+  sig: string
 }
 
-export interface BasicIdentity {
+export interface BasicRevocableIdentity {
   buid: string
   uid: string
   pubkey: string
   sig: string
+  member: boolean
+  wasMember: boolean
+  expires_on: number
 }
 
 export class IdentityDTO {
@@ -85,7 +95,7 @@ export class IdentityDTO {
   }
 
   static getTargetHash(idty:HashableIdentity) {
-    return hashf(idty.uid + idty.buid + idty.pubkey)
+    return hashf(idty.uid + idty.created_on + idty.pub)
   }
 
   static fromJSONObject(obj:any) {
@@ -106,8 +116,8 @@ export class IdentityDTO {
       basic.buid,
       basic.uid,
       IdentityDTO.getTargetHash({
-        pubkey: basic.pubkey,
-        buid: basic.buid,
+        pub: basic.pubkey,
+        created_on: basic.buid,
         uid: basic.uid
       })
     )
@@ -120,8 +130,8 @@ export class IdentityDTO {
       revoc.idty_buid,
       revoc.idty_uid,
       IdentityDTO.getTargetHash({
-        pubkey: revoc.pubkey,
-        buid: revoc.idty_buid,
+        pub: revoc.pubkey,
+        created_on: revoc.idty_buid,
         uid: revoc.idty_uid
       })
     )
diff --git a/app/lib/dto/MembershipDTO.ts b/app/lib/dto/MembershipDTO.ts
index a3a564c03e34068acaf756d5ec2637a9ff41b94d..267106ab0d634bd17bf9162b771fcfcfda748db6 100644
--- a/app/lib/dto/MembershipDTO.ts
+++ b/app/lib/dto/MembershipDTO.ts
@@ -11,8 +11,8 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-import {IdentityDTO} from "./IdentityDTO"
 import * as moment from "moment"
+import {IdentityDTO} from "./IdentityDTO"
 import {Cloneable} from "./Cloneable";
 import {hashf} from "../common";
 
@@ -78,9 +78,9 @@ export class MembershipDTO implements Cloneable {
 
   getIdtyHash() {
     return IdentityDTO.getTargetHash({
-      buid: this.certts,
+      created_on: this.certts,
       uid: this.userid,
-      pubkey: this.issuer
+      pub: this.issuer
     })
   }
 
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/dto/TransactionDTO.ts b/app/lib/dto/TransactionDTO.ts
index b443b1a8024cef6475a1899be10a21eb77729ee0..3aefab836c37676a439d6adb2855a6c7eadc4f43 100644
--- a/app/lib/dto/TransactionDTO.ts
+++ b/app/lib/dto/TransactionDTO.ts
@@ -23,7 +23,7 @@ export class InputDTO implements BaseDTO {
   constructor(
     public amount: number,
     public base: number,
-    public type: string,
+    public type: 'T'|'D',
     public identifier: string,
     public pos: number,
     public raw: string
@@ -134,7 +134,7 @@ export class TransactionDTO implements Cloneable {
       return new InputDTO(
         parseInt(amount),
         parseInt(base),
-        type,
+        type as 'T'|'D',
         identifier,
         parseInt(pos),
         input
diff --git a/app/lib/indexer.ts b/app/lib/indexer.ts
index 8b05ab264857ddb9554e034957cdd1ffe0ee20ad..96fd89a6076dcf4af1713c7fb87e6c5a38c0567b 100644
--- a/app/lib/indexer.ts
+++ b/app/lib/indexer.ts
@@ -23,8 +23,12 @@ import {rawer, txunlock} from "./common-libs/index"
 import {CommonConstants} from "./common-libs/constants"
 import {MembershipDTO} from "./dto/MembershipDTO"
 import {UnlockMetadata} from "./common-libs/txunlock"
-
-const _               = require('underscore');
+import {FileDAL} from "./dal/fileDAL"
+import {DBBlock} from "./db/DBBlock"
+import {DBWallet} from "./db/DBWallet"
+import {Tristamp} from "./common/Tristamp"
+import {Underscore} from "./common-libs/underscore"
+import {DataErrors} from "./common-libs/errors"
 
 const constants       = CommonConstants
 
@@ -59,6 +63,22 @@ export interface MindexEntry extends IndexEntry {
   revokedIsMember?: boolean,
   alreadyRevoked?: boolean,
   revocationSigOK?: boolean,
+  created_on_ref?: { medianTime: number, number:number, hash:string }
+}
+
+export interface FullMindexEntry {
+  op: string
+  pub: string
+  created_on: string
+  written_on: string
+  expires_on: number
+  expired_on: null|number
+  revokes_on: number
+  revoked_on: null|number
+  leaving: boolean
+  revocation: null|string
+  chainable_on: number
+  writtenOn: number
 }
 
 export interface IindexEntry extends IndexEntry {
@@ -67,7 +87,7 @@ export interface IindexEntry extends IndexEntry {
   hash: string | null,
   sig: string | null,
   created_on: string | null,
-  member: boolean,
+  member: boolean|null,
   wasMember: boolean | null,
   kick: boolean | null,
   wotb_id: number | null,
@@ -79,6 +99,21 @@ export interface IindexEntry extends IndexEntry {
   hasToBeExcluded?: boolean,
 }
 
+export interface FullIindexEntry {
+  op: string
+  uid: string
+  pub: string
+  hash: string
+  sig: string
+  created_on: string
+  written_on: string
+  writtenOn: number
+  member: boolean
+  wasMember: boolean
+  kick: boolean
+  wotb_id: number
+}
+
 export interface CindexEntry extends IndexEntry {
   issuer: string,
   receiver: string,
@@ -98,9 +133,21 @@ export interface CindexEntry extends IndexEntry {
   toLeaver?: boolean,
   isReplay?: boolean,
   sigOK?: boolean,
+  created_on_ref?: { medianTime: number },
+}
+
+export interface FullCindexEntry {
+  issuer: string
+  receiver: string
+  created_on: number
+  sig: string
+  chainable_on: number
+  expires_on: number
+  expired_on: number
 }
 
 export interface SindexEntry extends IndexEntry {
+  srcType: 'T'|'D'
   tx: string | null,
   identifier: string,
   pos: number,
@@ -120,25 +167,97 @@ export interface SindexEntry extends IndexEntry {
   isTimeLocked?: boolean,
 }
 
+export interface FullSindexEntry {
+  tx: string | null
+  identifier: string
+  pos: number
+  created_on: string | null
+  written_time: number
+  locktime: number
+  unlock: string | null
+  amount: number
+  base: number
+  conditions: string
+  consumed: boolean
+}
+
+export interface SimpleTxInput {
+  conditions: string
+  consumed: boolean
+  written_time: number
+  amount: number
+  base: number
+}
+
+export interface BasedAmount {
+  amount: number
+  base: number
+}
+
+export interface SimpleSindexEntryForWallet {
+  op: string
+  srcType: 'T'|'D'
+  conditions: string
+  amount: number
+  base: number
+  identifier: string
+  pos: number
+}
+
+export interface SimpleTxEntryForWallet extends SimpleSindexEntryForWallet {
+  srcType: 'T'
+}
+
+export interface SimpleUdEntryForWallet extends SimpleSindexEntryForWallet {
+  srcType: 'D'
+}
+
 export interface Ranger {
-  (n:number, m:number, prop?:string): Promise<DBHead[]>
+  (n:number, m:number): Promise<DBHead[]>
 }
 
-function pushIindex(index: any[], entry: IindexEntry): void {
+export interface ExclusionByCert {
+  op: 'UPDATE'
+  pub: string
+  written_on: string
+  writtenOn: number
+  kick: true
+}
+
+function pushIindex(index: IndexEntry[], entry: IindexEntry): void {
   index.push(entry)
 }
 
-function pushMindex(index: any[], entry: MindexEntry): void {
+function pushMindex(index: IndexEntry[], entry: MindexEntry): void {
   index.push(entry)
 }
 
-function pushCindex(index: any[], entry: CindexEntry): void {
+function pushCindex(index: IndexEntry[], entry: CindexEntry): void {
   index.push(entry)
 }
 
+export interface AccountsGarbagingDAL {
+  getWallet: (conditions: string) => Promise<DBWallet>
+  saveWallet: (wallet: DBWallet) => Promise<void>
+  sindexDAL: {
+    getAvailableForConditions: (conditions: string) => Promise<SindexEntry[]>
+  }
+}
+
+export interface BlockchainBlocksDAL {
+  getBlock(number: number): Promise<BlockDTO>
+  getBlockByBlockstamp(blockstamp: string): Promise<BlockDTO>
+}
+
 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
@@ -188,7 +307,7 @@ export class Indexer {
     // Joiners (newcomer or join back)
     for (const inlineMS of block.joiners) {
       const ms = MembershipDTO.fromInline(inlineMS);
-      const matchesANewcomer = _.filter(index, (row: IindexEntry) => row.index == constants.I_INDEX && row.pub == ms.issuer).length > 0;
+      const matchesANewcomer = Underscore.filter(index, (row: IindexEntry) => row.index == constants.I_INDEX && row.pub == ms.issuer).length > 0;
       if (matchesANewcomer) {
         // Newcomer
         pushMindex(index, {
@@ -375,6 +494,7 @@ export class Indexer {
         index.push({
           index: constants.S_INDEX,
           op: constants.IDX_UPDATE,
+          srcType: input.type,
           tx: txHash,
           identifier: input.identifier,
           pos: input.pos,
@@ -399,6 +519,7 @@ export class Indexer {
         index.push({
           index: constants.S_INDEX,
           op: constants.IDX_CREATE,
+          srcType: 'T',
           tx: txHash,
           identifier: txHash,
           pos: i++,
@@ -420,27 +541,22 @@ export class Indexer {
     return index;
   }
 
-  static async quickCompleteGlobalScope(block: BlockDTO, conf: CurrencyConfDTO, bindex: DBHead[], iindex: IindexEntry[], mindex: MindexEntry[], cindex: CindexEntry[], dal: any) {
+  static async quickCompleteGlobalScope(block: BlockDTO, conf: CurrencyConfDTO, bindex: DBHead[], iindex: IindexEntry[], mindex: MindexEntry[], cindex: CindexEntry[], dal:FileDAL) {
 
-    function range(start: number, end: number, property = ""): any {
-      let theRange;
+    async function range(start: number, end: number) {
+      let theRange:DBHead[] = []
       end = Math.min(end, bindex.length);
       if (start == 1) {
         theRange = bindex.slice(-end);
       } else {
         theRange = bindex.slice(-end, -start + 1);
       }
-      theRange.reverse();
-      if (property) {
-        // Filter on a particular property
-        return theRange.map((b:any) => b[property]);
-      } else {
-        return theRange;
-      }
+      theRange.reverse()
+      return theRange
     }
 
     async function head(n:number) {
-      return range(n, n)[0];
+      return (await range(n, n))[0]
     }
 
     const HEAD = new DBHead()
@@ -456,7 +572,7 @@ export class Indexer {
     HEAD.powMin = block.powMin
     HEAD.unitBase = block.unitbase
     HEAD.membersCount = block.membersCount
-    HEAD.dividend = block.dividend
+    HEAD.dividend = block.dividend || 0
     HEAD.new_dividend = null
 
     const HEAD_1 = await head(1);
@@ -509,10 +625,14 @@ export class Indexer {
     // BR_G105
     await Indexer.ruleIndexCorrectCertificationExpiryDate(HEAD, cindex, dal);
 
+    // Cleaning
+    cindex.forEach(c => c.created_on_ref = undefined)
+    mindex.forEach(m => m.created_on_ref = undefined)
+
     return HEAD;
   }
 
-  static async completeGlobalScope(block: BlockDTO, conf: ConfDTO, index: IndexEntry[], dal: any) {
+  static async completeGlobalScope(block: BlockDTO, conf: ConfDTO, index: IndexEntry[], dal:FileDAL) {
 
     const iindex = Indexer.iindex(index);
     const mindex = Indexer.mindex(index);
@@ -562,9 +682,9 @@ export class Indexer {
 
     // BR_G03
     if (HEAD.number > 0) {
-      HEAD.issuerIsMember = reduce(await dal.iindexDAL.reducable(HEAD.issuer)).member;
+      HEAD.issuerIsMember = !!reduce(await dal.iindexDAL.reducable(HEAD.issuer)).member;
     } else {
-      HEAD.issuerIsMember = reduce(_.where(iindex, { pub: HEAD.issuer })).member;
+      HEAD.issuerIsMember = !!reduce(Underscore.where(iindex, { pub: HEAD.issuer })).member;
     }
 
     // BR_G04
@@ -591,11 +711,11 @@ export class Indexer {
 
     // BR_G10
     if (HEAD.number == 0) {
-      HEAD.membersCount = count(_.filter(iindex, (entry:IindexEntry) => entry.member === true));
+      HEAD.membersCount = count(Underscore.filter(iindex, (entry:IindexEntry) => entry.member === true));
     } else {
       HEAD.membersCount = HEAD_1.membersCount
-        + count(_.filter(iindex, (entry:IindexEntry) => entry.member === true))
-        - count(_.filter(iindex, (entry:IindexEntry) => entry.member === false));
+        + count(Underscore.filter(iindex, (entry:IindexEntry) => entry.member === true))
+        - count(Underscore.filter(iindex, (entry:IindexEntry) => entry.member === false));
     }
 
     // BR_G11
@@ -651,7 +771,7 @@ export class Indexer {
     // BR_G20
     await Promise.all(iindex.map(async (ENTRY: IindexEntry) => {
       if (ENTRY.op == constants.IDX_CREATE) {
-        ENTRY.uidUnique = count(await dal.iindexDAL.sqlFind({ uid: ENTRY.uid })) == 0;
+        ENTRY.uidUnique = count(await dal.iindexDAL.findByUid(ENTRY.uid as string)) == 0;
       } else {
         ENTRY.uidUnique = true;
       }
@@ -660,7 +780,7 @@ export class Indexer {
     // BR_G21
     await Promise.all(iindex.map(async (ENTRY: IindexEntry) => {
       if (ENTRY.op == constants.IDX_CREATE) {
-        ENTRY.pubUnique = count(await dal.iindexDAL.sqlFind({pub: ENTRY.pub})) == 0;
+        ENTRY.pubUnique = count(await dal.iindexDAL.findByPub(ENTRY.pub)) == 0;
       } else {
         ENTRY.pubUnique = true;
       }
@@ -671,7 +791,7 @@ export class Indexer {
       if (ENTRY.member !== false) {
         ENTRY.excludedIsMember = true;
       } else {
-        ENTRY.excludedIsMember = reduce(await dal.iindexDAL.reducable(ENTRY.pub)).member;
+        ENTRY.excludedIsMember = !!reduce(await dal.iindexDAL.reducable(ENTRY.pub)).member;
       }
     }))
 
@@ -684,7 +804,7 @@ export class Indexer {
     if (HEAD.number > 0) {
       await Promise.all(mindex.map(async (ENTRY: MindexEntry) => {
         if (ENTRY.revocation === null) {
-          const rows = await dal.mindexDAL.sqlFind({ pub: ENTRY.pub, chainable_on: { $gt: HEAD_1.medianTime }});
+          const rows = await dal.mindexDAL.findByPubAndChainableOnGt(ENTRY.pub, HEAD_1.medianTime)
           // This rule will be enabled on
           if (HEAD.medianTime >= 1498860000) {
             ENTRY.unchainables = count(rows);
@@ -701,7 +821,7 @@ export class Indexer {
     // BR_G36
     await Promise.all(iindex.map(async (ENTRY: IindexEntry) => {
       const isMarkedAsToKick = reduce(await dal.iindexDAL.reducable(ENTRY.pub)).kick;
-      const isBeingRevoked = count(_.filter(mindex, (m:MindexEntry) => m.isBeingRevoked && m.pub == ENTRY.pub)) == 1;
+      const isBeingRevoked = count(Underscore.filter(mindex, m => !!(m.isBeingRevoked && m.pub == ENTRY.pub))) == 1
       ENTRY.hasToBeExcluded = isMarkedAsToKick || isBeingRevoked;
     }))
 
@@ -725,14 +845,14 @@ export class Indexer {
     // BR_G24
     // Global testing, because of wotb
     const oneIsOutdistanced = await checkPeopleAreNotOudistanced(
-      _.filter(mindex, (entry: MindexEntry) => !entry.revoked_on).map((entry: MindexEntry) => entry.pub),
-      cindex.reduce((newLinks:any, c: CindexEntry) => {
+      Underscore.filter(mindex, (entry: MindexEntry) => !entry.revoked_on).map((entry: MindexEntry) => entry.pub),
+      cindex.reduce((newLinks, c: CindexEntry) => {
         newLinks[c.receiver] = newLinks[c.receiver] || [];
         newLinks[c.receiver].push(c.issuer);
         return newLinks;
-      }, {}),
+      }, <{ [k:string]: string[] }>{}),
       // Newcomers
-      _.where(iindex, { op: constants.IDX_CREATE }).map((entry: IindexEntry) => entry.pub),
+      Underscore.where(iindex, { op: constants.IDX_CREATE }).map((entry: IindexEntry) => entry.pub),
       conf,
       dal
     );
@@ -750,15 +870,15 @@ export class Indexer {
     }))
 
     // BR_G26
-    await Promise.all(_.filter(mindex, (entry: MindexEntry) => entry.op == constants.IDX_UPDATE && entry.expired_on === 0).map(async (ENTRY: MindexEntry) => {
+    await Promise.all(Underscore.filter(mindex, (entry: MindexEntry) => entry.op == constants.IDX_UPDATE && entry.expired_on === 0).map(async (ENTRY: MindexEntry) => {
       ENTRY.joinsTwice = reduce(await dal.iindexDAL.reducable(ENTRY.pub)).member == true;
     }))
 
     // BR_G27
     await Promise.all(mindex.map(async (ENTRY: MindexEntry) => {
       if (ENTRY.type == 'JOIN' || ENTRY.type == 'ACTIVE') {
-        const existing = count(await dal.cindexDAL.sqlFind({ receiver: ENTRY.pub, expired_on: 0 }))
-        const pending = count(_.filter(cindex, (c:CindexEntry) => c.receiver == ENTRY.pub && c.expired_on == 0))
+        const existing = count(await dal.cindexDAL.findByReceiverAndExpiredOn(ENTRY.pub, 0))
+        const pending = count(Underscore.filter(cindex, (c:CindexEntry) => c.receiver == ENTRY.pub && c.expired_on == 0))
         ENTRY.enoughCerts = (existing + pending) >= conf.sigQty;
       } else {
         ENTRY.enoughCerts = true;
@@ -768,7 +888,7 @@ export class Indexer {
     // BR_G28
     await Promise.all(mindex.map(async (ENTRY: MindexEntry) => {
       if (ENTRY.type == 'LEAVE') {
-        ENTRY.leaverIsMember = reduce(await dal.iindexDAL.reducable(ENTRY.pub)).member
+        ENTRY.leaverIsMember = !!reduce(await dal.iindexDAL.reducable(ENTRY.pub)).member
       } else {
         ENTRY.leaverIsMember = true;
       }
@@ -778,7 +898,7 @@ export class Indexer {
     await Promise.all(mindex.map(async (ENTRY: MindexEntry) => {
       if (ENTRY.type == 'ACTIVE') {
         const reducable = await dal.iindexDAL.reducable(ENTRY.pub)
-        ENTRY.activeIsMember = reduce(reducable).member;
+        ENTRY.activeIsMember = !!reduce(reducable).member;
       } else {
         ENTRY.activeIsMember = true;
       }
@@ -789,7 +909,7 @@ export class Indexer {
       if (!ENTRY.revoked_on) {
         ENTRY.revokedIsMember = true;
       } else {
-        ENTRY.revokedIsMember = reduce(await dal.iindexDAL.reducable(ENTRY.pub)).member
+        ENTRY.revokedIsMember = !!reduce(await dal.iindexDAL.reducable(ENTRY.pub)).member
       }
     }))
 
@@ -798,7 +918,7 @@ export class Indexer {
       if (!ENTRY.revoked_on) {
         ENTRY.alreadyRevoked = false;
       } else {
-        ENTRY.alreadyRevoked = reduce(await dal.mindexDAL.reducable(ENTRY.pub)).revoked_on
+        ENTRY.alreadyRevoked = !!(reduce(await dal.mindexDAL.reducable(ENTRY.pub)).revoked_on)
       }
     }))
 
@@ -817,7 +937,7 @@ export class Indexer {
     // BR_G38
     if (HEAD.number > 0) {
       await Promise.all(cindex.map(async (ENTRY: CindexEntry) => {
-        const rows = await dal.cindexDAL.sqlFind({ issuer: ENTRY.issuer, chainable_on: { $gt: HEAD_1.medianTime }});
+        const rows = await dal.cindexDAL.findByIssuerAndChainableOnGt(ENTRY.issuer, HEAD_1.medianTime)
         ENTRY.unchainables = count(rows);
       }))
     }
@@ -829,47 +949,56 @@ export class Indexer {
 
     // BR_G40
     await Promise.all(cindex.map(async (ENTRY: CindexEntry) => {
-      ENTRY.fromMember = reduce(await dal.iindexDAL.reducable(ENTRY.issuer)).member
+      ENTRY.fromMember = !!reduce(await dal.iindexDAL.reducable(ENTRY.issuer)).member
     }))
 
     // BR_G41
     await Promise.all(cindex.map(async (ENTRY: CindexEntry) => {
-      ENTRY.toMember = reduce(await dal.iindexDAL.reducable(ENTRY.receiver)).member
+      ENTRY.toMember = !!reduce(await dal.iindexDAL.reducable(ENTRY.receiver)).member
     }))
 
     // BR_G42
     await Promise.all(cindex.map(async (ENTRY: CindexEntry) => {
-      ENTRY.toNewcomer = count(_.where(iindex, { member: true, pub: ENTRY.receiver })) > 0;
+      ENTRY.toNewcomer = count(Underscore.where(iindex, { member: true, pub: ENTRY.receiver })) > 0;
     }))
 
     // BR_G43
     await Promise.all(cindex.map(async (ENTRY: CindexEntry) => {
-      ENTRY.toLeaver = reduce(await dal.mindexDAL.reducable(ENTRY.receiver)).leaving
+      ENTRY.toLeaver = !!(reduce(await dal.mindexDAL.reducable(ENTRY.receiver)).leaving)
     }))
 
     // BR_G44
     await Promise.all(cindex.map(async (ENTRY: CindexEntry) => {
-      const reducable = await dal.cindexDAL.sqlFind({ issuer: ENTRY.issuer, receiver: ENTRY.receiver })
+      const reducable = await dal.cindexDAL.findByIssuerAndReceiver(ENTRY.issuer, ENTRY.receiver)
       ENTRY.isReplay = count(reducable) > 0 && reduce(reducable).expired_on === 0
     }))
 
     // BR_G45
     await Promise.all(cindex.map(async (ENTRY: CindexEntry) => {
-      ENTRY.sigOK = await checkCertificationIsValid(block, ENTRY, async (block:BlockDTO,pub:string,dal:any) => {
+      ENTRY.sigOK = await checkCertificationIsValid(block, ENTRY, async (block:BlockDTO,pub:string,dal:FileDAL) => {
         let localInlineIdty = block.getInlineIdentity(pub);
         if (localInlineIdty) {
           return IdentityDTO.fromInline(localInlineIdty)
         }
-        return dal.getWrittenIdtyByPubkey(pub)
+        const idty = await dal.getWrittenIdtyByPubkeyForCertificationCheck(pub)
+        if (!idty) {
+          return null
+        }
+        return {
+          pubkey: idty.pub,
+          uid: idty.uid,
+          sig: idty.sig,
+          buid: idty.created_on
+        }
       }, conf, dal);
     }))
 
     // BR_G102
-    await Promise.all(_.where(sindex, { op: constants.IDX_UPDATE }).map(async (ENTRY: SindexEntry) => {
+    await Promise.all(Underscore.where(sindex, { op: constants.IDX_UPDATE }).map(async (ENTRY: SindexEntry) => {
       if (HEAD.number == 0 && ENTRY.created_on == '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855') {
         ENTRY.age = 0;
       } else {
-        let ref = await dal.getBlockByBlockstamp(ENTRY.created_on);
+        let ref = await dal.getAbsoluteValidBlockInForkWindowByBlockstamp(ENTRY.created_on as string);
         if (ref && blockstamp(ref.number, ref.hash) == ENTRY.created_on) {
           ENTRY.age = HEAD_1.medianTime - ref.medianTime;
         } else {
@@ -878,40 +1007,41 @@ export class Indexer {
       }
     }))
 
-    const getInputLocalFirstOrFallbackGlobally = async (sindex:SindexEntry[], ENTRY:SindexEntry) => {
-      let source = _.filter(sindex, (src:SindexEntry) =>
+    const getInputLocalFirstOrFallbackGlobally = async (sindex:SindexEntry[], ENTRY:SindexEntry): Promise<SimpleTxInput> => {
+      let source: SimpleTxInput|null = Underscore.filter(sindex, src =>
         src.identifier == ENTRY.identifier
         && src.pos == ENTRY.pos
-        && src.conditions
+        && src.conditions !== ''
         && src.op === constants.IDX_CREATE)[0];
       if (!source) {
-        const reducable = await dal.sindexDAL.sqlFind({
-          identifier: ENTRY.identifier,
-          pos: ENTRY.pos,
-          amount: ENTRY.amount,
-          base: ENTRY.base
-        });
+        const reducable = await dal.findByIdentifierPosAmountBase(
+          ENTRY.identifier,
+          ENTRY.pos,
+          ENTRY.amount,
+          ENTRY.base,
+          ENTRY.srcType === 'D'
+        );
         source = reduce(reducable)
       }
       return source
     }
 
     // BR_G46
-    await Promise.all(_.where(sindex, { op: constants.IDX_UPDATE }).map(async (ENTRY: SindexEntry) => {
+    await Promise.all(Underscore.where(sindex, { op: constants.IDX_UPDATE }).map(async (ENTRY: SindexEntry) => {
       const source = await getInputLocalFirstOrFallbackGlobally(sindex, ENTRY)
       ENTRY.conditions = source.conditions; // We valuate the input conditions, so we can map these records to a same account
-      ENTRY.available = source.consumed === false;
+      ENTRY.available = !source.consumed
     }))
 
     // BR_G47
-    await Promise.all(_.where(sindex, { op: constants.IDX_UPDATE }).map(async (ENTRY: SindexEntry) => {
+    await Promise.all(Underscore.where(sindex, { op: constants.IDX_UPDATE }).map(async (ENTRY: SindexEntry) => {
       const source = await getInputLocalFirstOrFallbackGlobally(sindex, ENTRY)
       ENTRY.conditions = source.conditions;
       ENTRY.isLocked = !txSourceUnlock(ENTRY, source, HEAD);
     }))
 
     // BR_G48
-    await Promise.all(_.where(sindex, { op: constants.IDX_UPDATE }).map(async (ENTRY: SindexEntry) => {
+    await Promise.all(Underscore.where(sindex, { op: constants.IDX_UPDATE }).map(async (ENTRY: SindexEntry) => {
       const source = await getInputLocalFirstOrFallbackGlobally(sindex, ENTRY)
       ENTRY.isTimeLocked = ENTRY.written_time - source.written_time < ENTRY.locktime;
     }))
@@ -933,7 +1063,7 @@ export class Indexer {
     if (HEAD.number == 0) {
       HEAD.issuersCount = 0;
     } else {
-      HEAD.issuersCount = count(uniq(await range(1, HEAD_1.issuersFrame, 'issuer'))); // TODO
+      HEAD.issuersCount = count(uniq(Underscore.pluck(await range(1, HEAD_1.issuersFrame), 'issuer')))
     }
   }
 
@@ -967,8 +1097,8 @@ export class Indexer {
   }
 
   // BR_G07
-  static async prepareAvgBlockSize(HEAD: DBHead, range: (n:number,m:number,s:string)=>Promise<number[]>) {
-    HEAD.avgBlockSize = average(await range(1, HEAD.issuersCount, 'bsize'))
+  static async prepareAvgBlockSize(HEAD: DBHead, range:Ranger) {
+    HEAD.avgBlockSize = average(Underscore.pluck(await range(1, HEAD.issuersCount), 'bsize'))
   }
 
   // BR_G09
@@ -1056,7 +1186,7 @@ export class Indexer {
   }
 
   // BR_G16
-  static async prepareSpeed(HEAD: DBHead, head: (n:number) => Promise<BlockDTO>, conf: CurrencyConfDTO) {
+  static async prepareSpeed(HEAD: DBHead, head: (n:number) => Promise<DBHead>, conf: CurrencyConfDTO) {
     if (HEAD.number == 0) {
       HEAD.speed = 0;
     } else {
@@ -1071,7 +1201,7 @@ export class Indexer {
   }
 
   // BR_G18
-  static async preparePersonalizedPoW(HEAD: DBHead, HEAD_1: DBHead, range: (n:number,m:number)=>Promise<BlockDTO>, conf: ConfDTO) {
+  static async preparePersonalizedPoW(HEAD: DBHead, HEAD_1: DBHead, range: (n:number,m:number)=>Promise<DBHead[]>, conf: ConfDTO) {
     let nbPersonalBlocksInFrame, medianOfBlocksInFrame, blocksOfIssuer;
     let nbPreviousIssuers = 0, nbBlocksSince = 0;
     if (HEAD.number == 0) {
@@ -1079,11 +1209,11 @@ export class Indexer {
       medianOfBlocksInFrame = 1;
     } else {
       const ranged = await range(1, HEAD_1.issuersFrame)
-      const blocksInFrame = _.filter(ranged, (b:BlockDTO) => b.number <= HEAD_1.number);
-      const issuersInFrame = blocksInFrame.map((b:BlockDTO) => b.issuer);
-      blocksOfIssuer = _.filter(blocksInFrame, (entry:BlockDTO) => entry.issuer == HEAD.issuer);
+      const blocksInFrame = Underscore.filter(ranged, (b:DBHead) => b.number <= HEAD_1.number)
+      const issuersInFrame = blocksInFrame.map(b => b.issuer)
+      blocksOfIssuer = Underscore.filter(blocksInFrame, entry => entry.issuer == HEAD.issuer)
       nbPersonalBlocksInFrame = count(blocksOfIssuer);
-      const blocksPerIssuerInFrame = uniq(issuersInFrame).map((issuer:string) => count(_.where(blocksInFrame, { issuer })));
+      const blocksPerIssuerInFrame = uniq(issuersInFrame).map((issuer:string) => count(Underscore.where(blocksInFrame, { issuer })));
       medianOfBlocksInFrame = Math.max(1, median(blocksPerIssuerInFrame));
       if (nbPersonalBlocksInFrame == 0) {
         nbPreviousIssuers = 0;
@@ -1108,12 +1238,12 @@ export class Indexer {
   }
 
   // BR_G19
-  static async prepareIdentitiesAge(iindex: IindexEntry[], HEAD: DBHead, HEAD_1: DBHead, conf: CurrencyConfDTO, dal: any) {
-    await Promise.all(_.where(iindex, { op: constants.IDX_CREATE }).map(async (ENTRY: IindexEntry) => {
+  static async prepareIdentitiesAge(iindex: IindexEntry[], HEAD: DBHead, HEAD_1: DBHead, conf: CurrencyConfDTO, dal:FileDAL) {
+    await Promise.all(Underscore.where(iindex, { op: constants.IDX_CREATE }).map(async (ENTRY: IindexEntry) => {
       if (HEAD.number == 0 && ENTRY.created_on == '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855') {
         ENTRY.age = 0;
       } else {
-        let ref = await dal.getBlockByBlockstamp(ENTRY.created_on);
+        let ref = await dal.getAbsoluteValidBlockInForkWindowByBlockstamp(ENTRY.created_on as string);
         if (ref && blockstamp(ref.number, ref.hash) == ENTRY.created_on) {
           ENTRY.age = HEAD_1.medianTime - ref.medianTime;
         } else {
@@ -1124,13 +1254,14 @@ export class Indexer {
   }
 
   // BR_G22
-  static async prepareMembershipsAge(mindex: MindexEntry[], HEAD: DBHead, HEAD_1: DBHead, conf: CurrencyConfDTO, dal: any) {
-    await Promise.all(_.filter(mindex, (entry: MindexEntry) => !entry.revoked_on).map(async (ENTRY:MindexEntry) => {
+  static async prepareMembershipsAge(mindex: MindexEntry[], HEAD: DBHead, HEAD_1: DBHead, conf: CurrencyConfDTO, dal:FileDAL) {
+    await Promise.all(Underscore.filter(mindex, (entry: MindexEntry) => !entry.revoked_on).map(async (ENTRY:MindexEntry) => {
       if (HEAD.number == 0 && ENTRY.created_on == '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855') {
         ENTRY.age = 0;
       } else {
-        let ref = await dal.getBlockByBlockstamp(ENTRY.created_on);
+        let ref = ENTRY.created_on_ref || await dal.getAbsoluteValidBlockInForkWindowByBlockstamp(ENTRY.created_on)
         if (ref && blockstamp(ref.number, ref.hash) == ENTRY.created_on) {
+          ENTRY.created_on_ref = ref
           ENTRY.age = HEAD_1.medianTime - ref.medianTime;
         } else {
           ENTRY.age = conf.msWindow + 1;
@@ -1140,13 +1271,16 @@ export class Indexer {
   }
 
   // BR_G37
-  static async prepareCertificationsAge(cindex: CindexEntry[], HEAD: DBHead, HEAD_1: DBHead, conf: CurrencyConfDTO, dal: any) {
+  static async prepareCertificationsAge(cindex: CindexEntry[], HEAD: DBHead, HEAD_1: DBHead, conf: CurrencyConfDTO, dal:FileDAL) {
     await Promise.all(cindex.map(async (ENTRY) => {
       if (HEAD.number == 0) {
         ENTRY.age = 0;
       } else {
-        let ref = await dal.getBlock(ENTRY.created_on)
+        let ref = ENTRY.created_on_ref || await dal.getTristampOf(ENTRY.created_on)
         if (ref) {
+          if (!ENTRY.created_on_ref) {
+            ENTRY.created_on_ref = ref
+          }
           ENTRY.age = HEAD_1.medianTime - ref.medianTime;
         } else {
           ENTRY.age = conf.sigWindow + 1;
@@ -1473,14 +1607,14 @@ export class Indexer {
   }
 
   // BR_G86
-  static async ruleToBeKickedArePresent(iindex: IindexEntry[], dal:any) {
+  static async ruleToBeKickedArePresent(iindex: IindexEntry[], dal:FileDAL) {
     const toBeKicked = await dal.iindexDAL.getToBeKickedPubkeys();
     for (const toKick of toBeKicked) {
-      if (count(_.where(iindex, { pub: toKick, isBeingKicked: true })) !== 1) {
+      if (count(Underscore.where(iindex, { pub: toKick, isBeingKicked: true })) !== 1) {
         return false;
       }
     }
-    const beingKicked = _.filter(iindex, (i:IindexEntry) => i.member === false);
+    const beingKicked = Underscore.filter(iindex, (i:IindexEntry) => i.member === false);
     for (const entry of beingKicked) {
       if (!entry.hasToBeExcluded) {
         return false;
@@ -1499,7 +1633,7 @@ export class Indexer {
 
   // BR_G87
   static ruleInputIsAvailable(sindex: SindexEntry[]) {
-    const inputs = _.where(sindex, { op: constants.IDX_UPDATE });
+    const inputs = Underscore.where(sindex, { op: constants.IDX_UPDATE });
     for (const ENTRY of inputs) {
       if (!ENTRY.available) {
         return false;
@@ -1510,7 +1644,7 @@ export class Indexer {
 
   // BR_G88
   static ruleInputIsUnlocked(sindex: SindexEntry[]) {
-    const inputs = _.where(sindex, { op: constants.IDX_UPDATE });
+    const inputs = Underscore.where(sindex, { op: constants.IDX_UPDATE });
     for (const ENTRY of inputs) {
       if (ENTRY.isLocked) {
         return false;
@@ -1521,7 +1655,7 @@ export class Indexer {
 
   // BR_G89
   static ruleInputIsTimeUnlocked(sindex: SindexEntry[]) {
-    const inputs = _.where(sindex, { op: constants.IDX_UPDATE });
+    const inputs = Underscore.where(sindex, { op: constants.IDX_UPDATE });
     for (const ENTRY of inputs) {
       if (ENTRY.isTimeLocked) {
         return false;
@@ -1532,9 +1666,9 @@ export class Indexer {
 
   // BR_G90
   static ruleOutputBase(sindex: SindexEntry[], HEAD_1: DBHead) {
-    const inputs = _.where(sindex, { op: constants.IDX_CREATE });
+    const inputs = Underscore.where(sindex, { op: constants.IDX_CREATE });
     for (const ENTRY of inputs) {
-      if (ENTRY.unitBase > HEAD_1.unitBase) {
+      if (ENTRY.base > HEAD_1.unitBase) {
         return false;
       }
     }
@@ -1542,42 +1676,32 @@ export class Indexer {
   }
 
   // BR_G91
-  static async ruleIndexGenDividend(HEAD: DBHead, local_iindex: IindexEntry[], dal: any) {
-    const dividends = [];
+  static async ruleIndexGenDividend(HEAD: DBHead, local_iindex: IindexEntry[], dal: FileDAL): Promise<SimpleUdEntryForWallet[]> {
+    // Create the newcomers first, as they will produce a dividend too
+    for (const newcomer of local_iindex) {
+      await dal.dividendDAL.createMember(newcomer.pub)
+    }
     if (HEAD.new_dividend) {
-      const members = (await dal.iindexDAL.getMembersPubkeys()).concat(local_iindex.filter(i => i.member))
-      for (const MEMBER of members) {
-        dividends.push({
-          op: 'CREATE',
-          identifier: MEMBER.pub,
-          pos: HEAD.number,
-          written_on: [HEAD.number, HEAD.hash].join('-'),
-          writtenOn: HEAD.number,
-          written_time: HEAD.medianTime,
-          amount: HEAD.dividend,
-          base: HEAD.unitBase,
-          locktime: null,
-          conditions: 'SIG(' + MEMBER.pub + ')',
-          consumed: false
-        });
-      }
+      return dal.updateDividend(HEAD.number, HEAD.new_dividend, HEAD.unitBase, local_iindex)
     }
-    return dividends;
+    return []
   }
 
   // BR_G106
-  static async ruleIndexGarbageSmallAccounts(HEAD: DBHead, sindex: SindexEntry[], dal: any) {
-    const garbages = [];
+  static async ruleIndexGarbageSmallAccounts(HEAD: DBHead, transactions: SindexEntry[], dividends: SimpleUdEntryForWallet[], dal:AccountsGarbagingDAL) {
+    let sindex: SimpleSindexEntryForWallet[] = transactions
+    sindex = sindex.concat(dividends)
+    const garbages: SindexEntry[] = [];
     const accounts = Object.keys(sindex.reduce((acc: { [k:string]: boolean }, src) => {
       acc[src.conditions] = true;
       return acc;
     }, {}));
-    const wallets: { [k:string]: Promise<any> } = accounts.reduce((map: { [k:string]: Promise<any> }, acc) => {
+    const wallets: { [k:string]: Promise<DBWallet> } = accounts.reduce((map: { [k:string]: Promise<DBWallet> }, acc) => {
       map[acc] = dal.getWallet(acc);
       return map;
     }, {});
     for (const account of accounts) {
-      const localAccountEntries = _.filter(sindex, (src:SindexEntry) => src.conditions == account);
+      const localAccountEntries = Underscore.filter(sindex, src => src.conditions == account)
       const wallet = await wallets[account];
       const balance = wallet.balance
       const variations = localAccountEntries.reduce((sum:number, src:SindexEntry) => {
@@ -1587,15 +1711,18 @@ export class Indexer {
           return sum - src.amount * Math.pow(10, src.base);
         }
       }, 0)
-      // console.log('Balance of %s = %s (%s)', account, balance, variations > 0 ? '+' + variations : variations)
-      if (balance + variations < constants.ACCOUNT_MINIMUM_CURRENT_BASED_AMOUNT * Math.pow(10, HEAD.unitBase)) {
+      if (balance + variations < 0) {
+        throw Error(DataErrors[DataErrors.NEGATIVE_BALANCE])
+      }
+      else if (balance + variations < constants.ACCOUNT_MINIMUM_CURRENT_BASED_AMOUNT * Math.pow(10, HEAD.unitBase)) {
         const globalAccountEntries = await dal.sindexDAL.getAvailableForConditions(account)
         for (const src of localAccountEntries.concat(globalAccountEntries)) {
-          const sourceBeingConsumed = _.filter(sindex, (entry:SindexEntry) => entry.op === 'UPDATE' && entry.identifier == src.identifier && entry.pos == src.pos).length > 0;
+          const sourceBeingConsumed = Underscore.filter(sindex, entry => entry.op === 'UPDATE' && entry.identifier == src.identifier && entry.pos == src.pos).length > 0;
           if (!sourceBeingConsumed) {
             garbages.push({
+              index: 'SINDEX',
               op: 'UPDATE',
-              tx: src.tx,
+              srcType: 'T',
               identifier: src.identifier,
               pos: src.pos,
               amount: src.amount,
@@ -1604,7 +1731,17 @@ export class Indexer {
               writtenOn: HEAD.number,
               written_time: HEAD.medianTime,
               conditions: src.conditions,
-              consumed: true // It is now consumed
+              consumed: true, // It is now consumed
+
+              // TODO: change types to avoid casting
+              tx: (src as SindexEntry).tx,
+              created_on: (src as SindexEntry).created_on,
+              locktime: null as any,
+
+              // TODO: make these fields being not required using good types
+              unlock: null,
+              txObj: {} as TransactionDTO,
+              age: 0,
             });
           }
         }
@@ -1614,7 +1751,7 @@ export class Indexer {
   }
 
   // BR_G92
-  static async ruleIndexGenCertificationExpiry(HEAD: DBHead, dal:any) {
+  static async ruleIndexGenCertificationExpiry(HEAD: DBHead, dal:FileDAL) {
     const expiries = [];
     const certs = await dal.cindexDAL.findExpired(HEAD.medianTime);
     for (const CERT of certs) {
@@ -1632,12 +1769,12 @@ export class Indexer {
   }
 
   // BR_G93
-  static async ruleIndexGenMembershipExpiry(HEAD: DBHead, dal:any) {
+  static async ruleIndexGenMembershipExpiry(HEAD: DBHead, dal:FileDAL) {
     const expiries = [];
 
-    const memberships: MindexEntry[] = reduceBy(await dal.mindexDAL.sqlFind({ expires_on: { $lte: HEAD.medianTime }, revokes_on: { $gt: HEAD.medianTime} }), ['pub']);
+    const memberships: MindexEntry[] = reduceBy(await dal.mindexDAL.findExpiresOnLteAndRevokesOnGt(HEAD.medianTime), ['pub']);
     for (const POTENTIAL of memberships) {
-      const MS = await dal.mindexDAL.getReducedMS(POTENTIAL.pub);
+      const MS = await dal.mindexDAL.getReducedMS(POTENTIAL.pub) as FullMindexEntry // We are sure because `memberships` already comes from the MINDEX
       const hasRenewedSince = MS.expires_on > HEAD.medianTime;
       if (!MS.expired_on && !hasRenewedSince) {
         expiries.push({
@@ -1654,11 +1791,11 @@ export class Indexer {
   }
 
   // BR_G94
-  static async ruleIndexGenExclusionByMembership(HEAD: DBHead, mindex: MindexEntry[], dal:any) {
+  static async ruleIndexGenExclusionByMembership(HEAD: DBHead, mindex: MindexEntry[], dal:FileDAL) {
     const exclusions = [];
-    const memberships = _.filter(mindex, (entry: MindexEntry) => entry.expired_on);
+    const memberships = Underscore.filter(mindex, entry => !!entry.expired_on)
     for (const MS of memberships) {
-      const idty = await dal.iindexDAL.getFromPubkey(MS.pub);
+      const idty = await dal.iindexDAL.getFullFromPubkey(MS.pub);
       if (idty.member) {
         exclusions.push({
           op: 'UPDATE',
@@ -1673,17 +1810,18 @@ export class Indexer {
   }
 
   // BR_G95
-  static async ruleIndexGenExclusionByCertificatons(HEAD: DBHead, cindex: CindexEntry[], iindex: IindexEntry[], conf: ConfDTO, dal: any) {
-    const exclusions = [];
-    const expiredCerts = _.filter(cindex, (c: CindexEntry) => c.expired_on > 0);
+  static async ruleIndexGenExclusionByCertificatons(HEAD: DBHead, cindex: CindexEntry[], iindex: IindexEntry[], conf: ConfDTO, dal:FileDAL) {
+    const exclusions: ExclusionByCert[] = [];
+    const expiredCerts = Underscore.filter(cindex, (c: CindexEntry) => c.expired_on > 0);
     for (const CERT of expiredCerts) {
-      const just_expired = _.filter(cindex, (c: CindexEntry) => c.receiver == CERT.receiver && c.expired_on > 0);
-      const just_received = _.filter(cindex, (c: CindexEntry) => c.receiver == CERT.receiver && c.expired_on == 0);
+      const just_expired = Underscore.filter(cindex, (c: CindexEntry) => c.receiver == CERT.receiver && c.expired_on > 0);
+      const just_received = Underscore.filter(cindex, (c: CindexEntry) => c.receiver == CERT.receiver && c.expired_on == 0);
       const non_expired_global = await dal.cindexDAL.getValidLinksTo(CERT.receiver);
       if ((count(non_expired_global) - count(just_expired) + count(just_received)) < conf.sigQty) {
-        const isInExcluded = _.filter(iindex, (i: IindexEntry) => i.member === false && i.pub === CERT.receiver)[0];
-        const idty = await dal.iindexDAL.getFromPubkey(CERT.receiver);
-        if (!isInExcluded && idty.member) {
+        const isInExcluded = Underscore.filter(iindex, (i: IindexEntry) => i.member === false && i.pub === CERT.receiver)[0]
+        const isInKicked = Underscore.filter(exclusions, e => e.pub === CERT.receiver)[0]
+        const idty = await dal.iindexDAL.getFullFromPubkey(CERT.receiver)
+        if (!isInExcluded && !isInKicked && idty.member) {
           exclusions.push({
             op: 'UPDATE',
             pub: CERT.receiver,
@@ -1698,11 +1836,11 @@ export class Indexer {
   }
 
   // BR_G96
-  static async ruleIndexGenImplicitRevocation(HEAD: DBHead, dal:any) {
+  static async ruleIndexGenImplicitRevocation(HEAD: DBHead, dal:FileDAL) {
     const revocations = [];
-    const pending = await dal.mindexDAL.sqlFind({ revokes_on: { $lte: HEAD.medianTime}, revoked_on: { $null: true } })
+    const pending = await dal.mindexDAL.findRevokesOnLteAndRevokedOnIsNull(HEAD.medianTime)
     for (const MS of pending) {
-      const REDUCED = reduce(await dal.mindexDAL.sqlFind({ pub: MS.pub }))
+      const REDUCED = (await dal.mindexDAL.getReducedMS(MS.pub)) as FullMindexEntry
       if (REDUCED.revokes_on <= HEAD.medianTime && !REDUCED.revoked_on) {
         revocations.push({
           op: 'UPDATE',
@@ -1718,18 +1856,14 @@ export class Indexer {
   }
 
   // BR_G104
-  static async ruleIndexCorrectMembershipExpiryDate(HEAD: DBHead, mindex: MindexEntry[], dal:any) {
+  static async ruleIndexCorrectMembershipExpiryDate(HEAD: DBHead, mindex: MindexEntry[], dal:FileDAL) {
     for (const MS of mindex) {
       if (MS.type == 'JOIN' || MS.type == 'ACTIVE') {
         let basedBlock = { medianTime: 0 };
         if (HEAD.number == 0) {
           basedBlock = HEAD;
         } else {
-          if (HEAD.currency === 'gtest') {
-            basedBlock = await dal.getBlockByBlockstamp(MS.created_on);
-          } else {
-            basedBlock = await dal.getBlockByBlockstamp(MS.created_on);
-          }
+          basedBlock = MS.created_on_ref || await dal.getAbsoluteValidBlockInForkWindowByBlockstamp(MS.created_on) || basedBlock
         }
         if (MS.expires_on === null) {
           MS.expires_on = 0
@@ -1744,61 +1878,57 @@ export class Indexer {
   }
 
   // BR_G105
-  static async ruleIndexCorrectCertificationExpiryDate(HEAD: DBHead, cindex: CindexEntry[], dal:any) {
+  static async ruleIndexCorrectCertificationExpiryDate(HEAD: DBHead, cindex: CindexEntry[], dal:FileDAL) {
     for (const CERT of cindex) {
       let basedBlock = { medianTime: 0 };
       if (HEAD.number == 0) {
         basedBlock = HEAD;
       } else {
-        if (HEAD.currency === 'gtest') {
-          basedBlock = await dal.getBlock(CERT.created_on);
-        } else {
-          basedBlock = await dal.getBlock(CERT.created_on);
-        }
+        basedBlock = CERT.created_on_ref || ((await dal.getTristampOf(CERT.created_on)) as DBBlock) // We are sure at this point in the rules
       }
       CERT.expires_on += basedBlock.medianTime;
     }
   }
 
   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 = {
 
-    reduce: reduce,
+    reduce,
     reduceBy: reduceBy,
     getMaxBlockSize: (HEAD: DBHead) => Math.max(500, Math.ceil(1.1 * HEAD.avgBlockSize)),
     checkPeopleAreNotOudistanced
   }
 }
 
-function count(range:any[]) {
+function count<T>(range:T[]) {
   return range.length;
 }
 
-function uniq(range:any[]) {
-  return _.uniq(range);
+function uniq(range:string[]) {
+  return Underscore.uniq(range)
 }
 
 function average(values:number[]) {
@@ -1834,44 +1964,46 @@ function blockstamp(aNumber: number, aHash: string) {
   return [aNumber, aHash].join('-');
 }
 
-function reduce(records: any[]) {
-  return records.reduce((obj:any, record) => {
-    const keys = Object.keys(record);
+function reduce<T>(records: T[]): T {
+  return records.reduce((obj:T, record) => {
+    const keys = Object.keys(record) as (keyof T)[]
     for (const k of keys) {
       if (record[k] !== undefined && record[k] !== null) {
         obj[k] = record[k];
+      } else if (record[k] === null && obj[k] === undefined) {
+        // null overrides undefined
+        (obj[k] as any) = null
       }
     }
-    return obj;
-  }, {});
+    return obj
+  }, <T>{})
 }
 
-function reduceBy(reducables: IndexEntry[], properties: string[]): any[] {
-  const reduced = reducables.reduce((map: any, entry: any) => {
-    const id = properties.map((prop) => entry[prop]).join('-');
-    map[id] = map[id] || [];
-    map[id].push(entry);
-    return map;
-  }, {});
-  return _.values(reduced).map((value: SindexEntry[]) => Indexer.DUP_HELPERS.reduce(value));
+function reduceBy<T extends IndexEntry>(reducables: T[], properties: (keyof T)[]): T[] {
+  const reduced: { [k:string]: T[] } = reducables.reduce((map, entry) => {
+    const id = properties.map((prop) => entry[prop]).join('-')
+    map[id] = map[id] || []
+    map[id].push(entry)
+    return map
+  }, <{ [k:string]: T[] }>{})
+  return Underscore.values(reduced).map(value => Indexer.DUP_HELPERS.reduce(value))
 }
 
-async function checkPeopleAreNotOudistanced (pubkeys: string[], newLinks: any, newcomers: string[], conf: ConfDTO, dal: any) {
+async function checkPeopleAreNotOudistanced (pubkeys: string[], newLinks: { [k:string]: string[] }, newcomers: string[], conf: ConfDTO, dal:FileDAL) {
   // let wotb = dal.wotb;
   let wotb = dal.wotb.memCopy();
   let current = await dal.getCurrentBlockOrNull();
   let membersCount = current ? current.membersCount : 0;
-  // TODO: make a temporary copy of the WoT in RAM
   // We add temporarily the newcomers to the WoT, to integrate their new links
-  let nodesCache = newcomers.reduce((map: any, pubkey) => {
+  let nodesCache = newcomers.reduce((map, pubkey) => {
     let nodeID = wotb.addNode();
     map[pubkey] = nodeID;
     wotb.setEnabled(false, nodeID); // These are not members yet
     return map;
-  }, {});
+  }, <{ [k:string]: number }>{});
   // Add temporarily the links to the WoT
   let tempLinks = [];
-  let toKeys = _.keys(newLinks);
+  let toKeys = Underscore.keys(newLinks)
   for (const toKey of toKeys) {
     let toNode = await getNodeIDfromPubkey(nodesCache, toKey, dal);
     for (const fromKey of newLinks[toKey]) {
@@ -1899,32 +2031,32 @@ async function checkPeopleAreNotOudistanced (pubkeys: string[], newLinks: any, n
   return error ? true : false;
 }
 
-async function getNodeIDfromPubkey(nodesCache: any, pubkey: string, dal: any) {
+async function getNodeIDfromPubkey(nodesCache: { [k:string]: number }, pubkey: string, dal:FileDAL) {
   let toNode = nodesCache[pubkey];
   // Eventually cache the target nodeID
   if (toNode === null || toNode === undefined) {
-    let idty = await dal.getWrittenIdtyByPubkey(pubkey);
-    toNode = idty.wotb_id;
-    nodesCache[pubkey] = toNode;
+    let idty = await dal.getWrittenIdtyByPubkeyForWotbID(pubkey)
+    toNode = idty.wotb_id
+    nodesCache[pubkey] = toNode
   }
   return toNode;
 }
 
-async function sigCheckRevoke(entry: MindexEntry, dal: any, currency: string) {
+async function sigCheckRevoke(entry: MindexEntry, dal: FileDAL, currency: string) {
   try {
     let pubkey = entry.pub, sig = entry.revocation || "";
-    let idty = await dal.getWrittenIdtyByPubkey(pubkey);
+    let idty = await dal.getWrittenIdtyByPubkeyForRevocationCheck(pubkey);
     if (!idty) {
       throw Error("A pubkey who was never a member cannot be revoked");
     }
-    if (idty.revoked) {
+    if (idty.revoked_on) {
       throw Error("A revoked identity cannot be revoked again");
     }
     let rawRevocation = rawer.getOfficialRevocation({
       currency: currency,
-      issuer: idty.pubkey,
+      issuer: idty.pub,
       uid: idty.uid,
-      buid: idty.buid,
+      buid: idty.created_on,
       sig: idty.sig,
       revocation: ''
     });
@@ -1940,22 +2072,28 @@ async function sigCheckRevoke(entry: MindexEntry, dal: any, currency: string) {
 
 
 
-async function checkCertificationIsValid (block: BlockDTO, cert: CindexEntry, findIdtyFunc: (b:BlockDTO,to:string,dal:any)=>Promise<IdentityDTO>, conf: ConfDTO, dal: any) {
+async function checkCertificationIsValid (block: BlockDTO, cert: CindexEntry, findIdtyFunc: (b:BlockDTO,to:string,dal:FileDAL)=>Promise<{
+  pubkey:string
+  uid:string
+  buid:string
+  sig:string
+}|null>, conf: ConfDTO, dal:FileDAL) {
   if (block.number == 0 && cert.created_on != 0) {
     throw Error('Number must be 0 for root block\'s certifications');
   } else {
     try {
-      let basedBlock = new BlockDTO()
-      basedBlock.hash = constants.SPECIAL_HASH
-
+      let basedBlock:Tristamp|null = {
+        number: 0,
+        hash: constants.SPECIAL_HASH,
+        medianTime: 0
+      }
       if (block.number != 0) {
-        try {
-          basedBlock = await dal.getBlock(cert.created_on);
-        } catch (e) {
-          throw Error('Certification based on an unexisting block');
+        basedBlock = await dal.getTristampOf(cert.created_on)
+        if (!basedBlock) {
+          throw Error('Certification based on an unexisting block')
         }
       }
-      let idty = await findIdtyFunc(block, cert.receiver, dal)
+      const idty = await findIdtyFunc(block, cert.receiver, dal)
       let current = block.number == 0 ? null : await dal.getCurrentBlockOrNull();
       if (!idty) {
         throw Error('Identity does not exist for certified');
@@ -1967,8 +2105,8 @@ async function checkCertificationIsValid (block: BlockDTO, cert: CindexEntry, fi
         throw Error('Rejected certification: certifying its own self-certification has no meaning');
       else {
         const buid = [cert.created_on, basedBlock.hash].join('-');
-        idty.currency = conf.currency;
-        const raw = rawer.getOfficialCertification(_.extend(idty, {
+        const raw = rawer.getOfficialCertification({
+          currency: conf.currency,
           idty_issuer: idty.pubkey,
           idty_uid: idty.uid,
           idty_buid: idty.buid,
@@ -1976,7 +2114,7 @@ async function checkCertificationIsValid (block: BlockDTO, cert: CindexEntry, fi
           issuer: cert.issuer,
           buid: buid,
           sig: ''
-        }));
+        })
         const verified = verify(raw, cert.sig, cert.issuer);
         if (!verified) {
           throw constants.ERRORS.WRONG_SIGNATURE_FOR_CERT
@@ -1989,7 +2127,7 @@ async function checkCertificationIsValid (block: BlockDTO, cert: CindexEntry, fi
   }
 }
 
-function txSourceUnlock(ENTRY:SindexEntry, source:SindexEntry, HEAD: DBHead) {
+function txSourceUnlock(ENTRY:SindexEntry, source:{ conditions: string, written_time: number}, HEAD: DBHead) {
   const tx = ENTRY.txObj;
   const unlockParams:string[] = TransactionDTO.unlock2params(ENTRY.unlock || '')
   const unlocksMetadata:UnlockMetadata = {}
diff --git a/app/lib/logger.ts b/app/lib/logger.ts
index 0fe2865b849f4ea81e889697798118c1ab5f3fd6..f4d4f35babb0ce7e12c6b0454283e256f2cc2eb4 100644
--- a/app/lib/logger.ts
+++ b/app/lib/logger.ts
@@ -11,11 +11,11 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
-const moment = require('moment');
+import * as moment from "moment"
+import {Directory} from "./system/directory"
+
 const path = require('path');
 const winston = require('winston');
-const directory = require('../lib/system/directory');
 
 /***************
  * CALLBACK LOGGER
@@ -151,11 +151,11 @@ logger.unmute = () => {
 /**
  * Default logging path
  */
-logger.addHomeLogs(directory.INSTANCE_HOME)
+logger.addHomeLogs(Directory.INSTANCE_HOME)
 
 /**
 * Convenience function to get logger directly
 */
-export function NewLogger() {
+export function NewLogger(name?:string) {
   return logger
 }
diff --git a/app/lib/other_constants.ts b/app/lib/other_constants.ts
index 203afe23d6bcac3053657be600b52b927e58431c..2b0139b508162b43c0d3948f0738687386b8d16b 100644
--- a/app/lib/other_constants.ts
+++ b/app/lib/other_constants.ts
@@ -14,10 +14,15 @@
 export const OtherConstants = {
 
   MUTE_LOGS_DURING_UNIT_TESTS: true,
+  SQL_TRACES: false,
 
   BC_EVENT: {
     SWITCHED: 'switched',
     HEAD_CHANGED: 'newHEAD',
     RESOLUTION_DONE: 'resolution_done'
-  }
+  },
+
+  ENABLE_LOKI_MONITORING: false,
+  ENABLE_SQL_MONITORING: false,
+  TRACE_BALANCES: false
 }
\ No newline at end of file
diff --git a/app/lib/rules/global_rules.ts b/app/lib/rules/global_rules.ts
index 3bc3d5417591fea6df8b84d6e1ff7290786e6669..57721cfb1b7bfc6be0f7c18cc6c1da27815769f7 100644
--- a/app/lib/rules/global_rules.ts
+++ b/app/lib/rules/global_rules.ts
@@ -21,10 +21,9 @@ import {rawer, txunlock} from "../common-libs/index"
 import {CommonConstants} from "../common-libs/constants"
 import {IdentityDTO} from "../dto/IdentityDTO"
 import {hashf} from "../common"
-import {Indexer} from "../indexer"
-import {DBTx} from "../dal/sqliteDAL/TxsDAL"
-
-const _ = require('underscore')
+import {Indexer, SimpleTxInput} from "../indexer"
+import {DBTx} from "../db/DBTx"
+import {Tristamp} from "../common/Tristamp"
 
 const constants      = CommonConstants
 
@@ -76,16 +75,16 @@ export const GLOBAL_RULES_FUNCTIONS = {
     let current = await dal.getCurrentBlockOrNull();
     for (const obj of block.identities) {
       let idty = IdentityDTO.fromInline(obj);
-      let found = await dal.getWrittenIdtyByUID(idty.uid);
+      let found = await dal.getWrittenIdtyByUIDForExistence(idty.uid)
       if (found) {
         throw Error('Identity already used');
       }
       // Because the window rule does not apply on initial certifications
       if (current && idty.buid != constants.SPECIAL_BLOCK) {
         // From DUP 0.5: we fully check the blockstamp
-        const basedBlock = await dal.getBlockByBlockstamp(idty.buid);
+        const basedBlock = await dal.getAbsoluteValidBlockInForkWindowByBlockstamp(idty.buid) || { medianTime: 0 }
         // Check if writable
-        let duration = current.medianTime - parseInt(basedBlock.medianTime);
+        let duration = current.medianTime - basedBlock.medianTime
         if (duration > conf.idtyWindow) {
           throw Error('Identity is too old and cannot be written');
         }
@@ -102,7 +101,7 @@ export const GLOBAL_RULES_FUNCTIONS = {
       const outputs = tx.outputsAsObjects()
       let unlocks:any = {};
       let sumOfInputs = 0;
-      let maxOutputBase = current.unitbase;
+      let maxOutputBase = current && current.unitbase || 0;
       for (const theUnlock of tx.unlocks) {
         let sp = theUnlock.split(':');
         let index = parseInt(sp[0]);
@@ -110,7 +109,7 @@ export const GLOBAL_RULES_FUNCTIONS = {
       }
       for (let k = 0, len2 = inputs.length; k < len2; k++) {
         let src = inputs[k];
-        let dbSrc = await dal.getSource(src.identifier, src.pos);
+        let dbSrc: SimpleTxInput|null = await dal.getSource(src.identifier, src.pos, src.type === 'D');
         logger.debug('Source %s:%s:%s:%s = %s', src.amount, src.base, src.identifier, src.pos, dbSrc && dbSrc.consumed);
         if (!dbSrc) {
           // For chained transactions which are checked on sandbox submission, we accept them if there is already
@@ -182,17 +181,21 @@ export const GLOBAL_RULES_FUNCTIONS = {
 export const GLOBAL_RULES_HELPERS = {
 
   // Functions used in an external context too
-  checkMembershipBlock: (ms:any, current:DBBlock, conf:ConfDTO, dal:FileDAL) => checkMSTarget(ms, current ? { number: current.number + 1} : { number: 0 }, conf, dal),
+  checkMembershipBlock: (ms:any, current:DBBlock|null, conf:ConfDTO, dal:FileDAL) => checkMSTarget(ms, current ? { number: current.number + 1} : { number: 0 }, conf, dal),
 
-  checkCertificationIsValid: (cert:any, current:BlockDTO, findIdtyFunc:any, conf:ConfDTO, dal:FileDAL) => {
-    return checkCertificationIsValid(current ? current : { number: 0, currency: '' }, cert, findIdtyFunc, conf, dal)
+  checkCertificationIsValidInSandbox: (cert:any, current:BlockDTO, findIdtyFunc:any, conf:ConfDTO, dal:FileDAL) => {
+    return checkCertificationShouldBeValid(current ? current : { number: 0, currency: '' }, cert, findIdtyFunc, conf, dal)
   },
 
-  checkCertificationIsValidForBlock: (cert:any, block:{ number:number, currency:string }, findIdtyFunc:(b:{ number:number, currency:string }, pubkey:string, dal:FileDAL) => Promise<any>, conf:ConfDTO, dal:FileDAL) => {
-    return checkCertificationIsValid(block, cert, findIdtyFunc, conf, dal)
+  checkCertificationIsValidForBlock: (cert:any, block:{ number:number, currency:string }, findIdtyFunc:(b:{ number:number, currency:string }, pubkey:string, dal:FileDAL) => Promise<{
+    pubkey:string
+    uid:string
+    buid:string
+    sig:string}|null>, conf:ConfDTO, dal:FileDAL) => {
+    return checkCertificationShouldBeValid(block, cert, findIdtyFunc, conf, dal)
   },
 
-  isOver3Hops: async (member:any, newLinks:any, newcomers:string[], current:DBBlock, conf:ConfDTO, dal:FileDAL) => {
+  isOver3Hops: async (member:any, newLinks:any, newcomers:string[], current:DBBlock|null, conf:ConfDTO, dal:FileDAL) => {
     if (!current) {
       return Promise.resolve(false);
     }
@@ -203,9 +206,9 @@ export const GLOBAL_RULES_HELPERS = {
     }
   },
 
-  checkExistsUserID: (uid:string, dal:FileDAL) => dal.getWrittenIdtyByUID(uid),
+  checkExistsUserID: (uid:string, dal:FileDAL) => dal.getWrittenIdtyByUIDForExistence(uid),
 
-  checkExistsPubkey: (pub:string, dal:FileDAL) => dal.getWrittenIdtyByPubkey(pub),
+  checkExistsPubkey: (pub:string, dal:FileDAL) => dal.getWrittenIdtyByPubkeyForExistence(pub),
 
   checkSingleTransaction: (
     tx:TransactionDTO,
@@ -220,7 +223,7 @@ export const GLOBAL_RULES_HELPERS = {
   checkTxBlockStamp: async (tx:TransactionDTO, dal:FileDAL) => {
     const number = parseInt(tx.blockstamp.split('-')[0])
     const hash = tx.blockstamp.split('-')[1];
-    const basedBlock = await dal.getBlockByNumberAndHashOrNull(number, hash);
+    const basedBlock = await dal.getAbsoluteValidBlockInForkWindow(number, hash)
     if (!basedBlock) {
       throw "Wrong blockstamp for transaction";
     }
@@ -249,11 +252,9 @@ async function checkMSTarget (ms:any, block:any, conf:ConfDTO, dal:FileDAL) {
   else if (block.number == 0) {
     return null; // Valid for root block
   } else {
-    let basedBlock;
-    try {
-      basedBlock = await dal.getBlockByNumberAndHash(ms.number, ms.fpr);
-    } catch (e) {
-      throw Error('Membership based on an unexisting block');
+    const basedBlock = await dal.getAbsoluteValidBlockInForkWindow(ms.number, ms.fpr)
+    if (!basedBlock) {
+      throw Error('Membership based on an unexisting block')
     }
     let current = await dal.getCurrentBlockOrNull();
     if (current && current.medianTime > basedBlock.medianTime + conf.msValidity) {
@@ -263,21 +264,27 @@ async function checkMSTarget (ms:any, block:any, conf:ConfDTO, dal:FileDAL) {
   }
 }
 
-async function checkCertificationIsValid (block:{ number:number, currency:string }, cert:any, findIdtyFunc:(b:{ number:number, currency:string }, pubkey:string, dal:FileDAL) => Promise<any>, conf:ConfDTO, dal:FileDAL) {
+async function checkCertificationShouldBeValid (block:{ number:number, currency:string }, cert:any, findIdtyFunc:(b:{ number:number, currency:string }, pubkey:string, dal:FileDAL) => Promise<{
+  pubkey:string
+  uid:string
+  buid:string
+  sig:string
+}|null>, conf:ConfDTO, dal:FileDAL) {
   if (block.number == 0 && cert.block_number != 0) {
     throw Error('Number must be 0 for root block\'s certifications');
   } else {
-    let basedBlock:any = {
-      hash: constants.SPECIAL_HASH
-    };
+    let basedBlock:Tristamp|null = {
+      number: 0,
+      hash: constants.SPECIAL_HASH,
+      medianTime: 0
+    }
     if (block.number != 0) {
-      try {
-        basedBlock = await dal.getBlock(cert.block_number);
-      } catch (e) {
+      basedBlock = await dal.getTristampOf(cert.block_number)
+      if (!basedBlock) {
         throw Error('Certification based on an unexisting block');
       }
       try {
-        const issuer = await dal.getWrittenIdtyByPubkey(cert.from)
+        const issuer = await dal.getWrittenIdtyByPubkeyForIsMember(cert.from)
         if (!issuer || !issuer.member) {
           throw Error('Issuer is not a member')
         }
@@ -299,8 +306,8 @@ async function checkCertificationIsValid (block:{ number:number, currency:string
       const buid = [cert.block_number, basedBlock.hash].join('-');
       if (cert.block_hash && buid != [cert.block_number, cert.block_hash].join('-'))
         throw Error('Certification based on an unexisting block buid. from ' + cert.from.substring(0,8) + ' to ' + idty.pubkey.substring(0,8));
-      idty.currency = conf.currency;
-      const raw = rawer.getOfficialCertification(_.extend(idty, {
+      const raw = rawer.getOfficialCertification({
+        currency: conf.currency,
         idty_issuer: idty.pubkey,
         idty_uid: idty.uid,
         idty_buid: idty.buid,
@@ -308,7 +315,7 @@ async function checkCertificationIsValid (block:{ number:number, currency:string
         issuer: cert.from,
         buid: buid,
         sig: ''
-      }));
+      })
       const verified = verify(raw, cert.sig, cert.from);
       if (!verified) {
         throw constants.ERRORS.WRONG_SIGNATURE_FOR_CERT
diff --git a/app/lib/rules/local_rules.ts b/app/lib/rules/local_rules.ts
index bec4b70c7424835917b1d20340aa64c1da997fe9..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++
@@ -524,7 +522,7 @@ export const LOCAL_RULES_HELPERS = {
     }
   },
 
-  getMaxPossibleVersionNumber: async (current:DBBlock) => {
+  getMaxPossibleVersionNumber: async (current:DBBlock|null) => {
     // Looking at current blockchain, find what is the next maximum version we can produce
 
     // 1. We follow previous block's version
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/lib/system/directory.ts b/app/lib/system/directory.ts
index 1dffb23d07035b38568a353abb118d2ce9cf6d05..f30eec2e48e03ccc4fddde860156278c68805275 100644
--- a/app/lib/system/directory.ts
+++ b/app/lib/system/directory.ts
@@ -11,69 +11,164 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
+import * as path from "path"
+import * as fs from 'fs'
 import {SQLiteDriver} from "../dal/drivers/SQLiteDriver"
 import {CFSCore} from "../dal/fileDALs/CFSCore"
-import {WoTBObject} from "../wot"
+import {WoTBInstance, WoTBObject} from "../wot"
+import {FileDALParams} from "../dal/fileDAL"
+import {LokiJsDriver} from "../dal/drivers/LokiJsDriver"
+import {cliprogram} from "../common-libs/programOptions"
 
-const opts = require('optimist').argv;
-const path = require('path');
+const opts = cliprogram
 const qfs  = require('q-io/fs');
-const fs   = require('fs');
 
 const DEFAULT_DOMAIN = "duniter_default";
 const DEFAULT_HOME = (process.platform == 'win32' ? process.env.USERPROFILE : process.env.HOME) + '/.config/duniter/';
 
-const getLogsPath = (profile:string, directory:string|null = null) => path.join(getHomePath(profile, directory), 'duniter.log');
+const getLogsPath = (profile:string|undefined, directory:string|null = null) => path.join(getHomePath(profile, directory), 'duniter.log');
 
-const getHomePath = (profile:string|null, directory:string|null = null) => path.normalize(getUserHome(directory) + '/') + getDomain(profile);
+const getHomePath = (profile:string|null|undefined, directory:string|null = null) => path.normalize(getUserHome(directory) + '/') + getDomain(profile);
 
 const getUserHome = (directory:string|null = null) => (directory || DEFAULT_HOME);
 
 const getDomain = (profile:string|null = null) => (profile || DEFAULT_DOMAIN);
 
-const dir = module.exports = {
+export interface FileSystem {
+  fsExists(file:string): Promise<boolean>
+  fsReadFile(file:string): Promise<string>
+  fsUnlink(file:string): Promise<boolean>
+  fsList(dir:string): Promise<string[]>
+  fsWrite(file:string, content:string): Promise<void>
+  fsMakeDirectory(dir:string): Promise<void>
+  fsRemoveTree(dir:string): Promise<void>
+  fsStreamTo(file: string, iterator: IterableIterator<string>): Promise<void>
+}
+
+class QioFileSystem implements FileSystem {
+
+  constructor(private qio:any, private isMemory:boolean = false) {}
+
+  async fsExists(file:string) {
+    return this.qio.exists(file)
+  }
+
+  async fsReadFile(file:string) {
+    return this.qio.read(file)
+  }
+
+  async fsUnlink(file:string) {
+    return this.qio.remove(file)
+  }
+
+  async fsList(dir: string): Promise<string[]> {
+    if (!(await this.qio.exists(dir))) {
+      return []
+    }
+    return this.qio.list(dir)
+  }
+
+  fsWrite(file: string, content: string): Promise<void> {
+    return this.qio.write(file, content)
+  }
+
+  async fsStreamTo(file: string, iterator: IterableIterator<string>): Promise<void> {
+    if (this.isMemory) {
+      for (const line of iterator) {
+        await this.qio.append(file, line)
+      }
+    } else {
+      // Use NodeJS streams for faster writing
+      let wstream = fs.createWriteStream(file)
+      await new Promise(async (res, rej) => {
+        // When done, return
+        wstream.on('close', (err:any) => {
+          if (err) return rej(err)
+          res()
+        })
+        // Write each line
+        for (const line of iterator) {
+          wstream.write(line + "\n")
+        }
+        // End the writing
+        wstream.end()
+      })
+    }
+  }
+
+  fsMakeDirectory(dir: string): Promise<void> {
+    return this.qio.makeTree(dir)
+  }
+
+  async fsRemoveTree(dir: string): Promise<void> {
+    return this.qio.removeTree(dir)
+  }
+}
+
+export const RealFS = (): FileSystem => {
+  return new QioFileSystem(qfs)
+}
+
+export const MemFS = (initialTree:{ [folder:string]: { [file:string]: string }} = {}): FileSystem => {
+  return new QioFileSystem(require('q-io/fs-mock')(initialTree), true)
+}
+
+export const Directory = {
 
   INSTANCE_NAME: getDomain(opts.mdb),
   INSTANCE_HOME: getHomePath(opts.mdb, opts.home),
   INSTANCE_HOMELOG_FILE: getLogsPath(opts.mdb, opts.home),
   DUNITER_DB_NAME: 'duniter',
+  LOKI_DB_DIR: 'loki',
   WOTB_FILE: 'wotb.bin',
 
   getHome: (profile:string|null = null, directory:string|null = null) => getHomePath(profile, directory),
 
   getHomeFS: async (isMemory:boolean, theHome:string, makeTree = true) => {
-    const home = theHome || dir.getHome();
-    const params:any = {
-      home: home
-    };
-    if (isMemory) {
-      params.fs = require('q-io/fs-mock')({});
-    } else {
-      params.fs = qfs;
+    const home = theHome || Directory.getHome()
+    const params = {
+      home: home,
+      fs: isMemory ? MemFS() : RealFS()
     }
     if (makeTree) {
-      await params.fs.makeTree(home)
+      await params.fs.fsMakeDirectory(home)
     }
     return params;
   },
 
-  getHomeParams: async (isMemory:boolean, theHome:string) => {
-    const params:any = await dir.getHomeFS(isMemory, theHome)
+  getHomeParams: async (isMemory:boolean, theHome:string): Promise<FileDALParams> => {
+    const params = await Directory.getHomeFS(isMemory, theHome)
     const home = params.home;
+    let dbf: () => SQLiteDriver
+    let dbf2: () => LokiJsDriver
+    let wotb: WoTBInstance
     if (isMemory) {
-      params.dbf = () => new SQLiteDriver(':memory:');
-      params.wotb = WoTBObject.memoryInstance();
+
+      // Memory DB
+      dbf = () => new SQLiteDriver(':memory:');
+      dbf2 = () => new LokiJsDriver()
+      wotb = WoTBObject.memoryInstance();
+
     } else {
-      const sqlitePath = path.join(home, dir.DUNITER_DB_NAME + '.db');
-      params.dbf = () => new SQLiteDriver(sqlitePath);
-      const wotbFilePath = path.join(home, dir.WOTB_FILE);
+
+      // File DB
+      const sqlitePath = path.join(home, Directory.DUNITER_DB_NAME + '.db');
+      dbf = () => new SQLiteDriver(sqlitePath);
+      const wotbFilePath = path.join(home, Directory.WOTB_FILE);
       let existsFile = await qfs.exists(wotbFilePath)
       if (!existsFile) {
         fs.closeSync(fs.openSync(wotbFilePath, 'w'));
       }
-      params.wotb = WoTBObject.fileInstance(wotbFilePath);
+      dbf2 = () => new LokiJsDriver(path.join(home, Directory.LOKI_DB_DIR))
+      wotb = WoTBObject.fileInstance(wotbFilePath);
+    }
+    return {
+      home: params.home,
+      fs: params.fs,
+      dbf,
+      dbf2,
+      wotb
     }
-    return params;
   },
 
   createHomeIfNotExists: async (fileSystem:any, theHome:string) => {
diff --git a/app/lib/wot.ts b/app/lib/wot.ts
index b535ca68e81e533af1f52581e946e27825d92a3f..a3a68b2dd8642ef21fa7e6612d33a2ad52875de2 100644
--- a/app/lib/wot.ts
+++ b/app/lib/wot.ts
@@ -13,6 +13,169 @@
 
 const wotb = require('wotb');
 
+export interface WoTBInstance {
+
+  readonly instanceID:number
+  readonly filePath:string
+
+  /**
+   * Gets this instance ID.
+   * @returns {number} The instance technical ID.
+   */
+  getId(): number
+
+  /**
+   * Makes a memory copy of the WoT instance, and returns this new instance.
+   * @returns {WoTBInstance} The new memory instance.
+   */
+  memCopy(): WoTBInstance
+
+  /**
+   * Remove the WoT from the computer's memory.
+   */
+  clear(): void
+
+  /**
+   * Returns a dump of the WoT as a string.
+   * @returns {string} The dump.
+   */
+  dumpWoT(): string
+
+  /**
+   * Makes a dump of the WoT on standard output.
+   */
+  showGraph(): void
+
+  /**
+   * Removes any node and certification from the WoT.
+   */
+  resetWoT(): void
+
+  /**
+   * Gets the total number of nodes in the WoT, enabled or not.
+   * @returns {number} The total of nodes ever added to the WoT.
+   */
+  getWoTSize(): number
+
+  /**
+   * Add a node and returns its wotb_id.
+   * @returns {number} The new node identifier.
+   */
+  addNode(): number
+
+  /**
+   * Remove the lastly added node from the WoT, as well as the certifications it received.
+   */
+  removeNode(): void
+
+  /**
+   * Sets the maximum number of certifications a node can emit.
+   * @param {number} max The maximum number of emitted certifications.
+   */
+  setMaxCert(max:number): void
+
+  /**
+   * Gets the maximum number of certifications a node can emit in the WoT.
+   * @returns {number} The maximum's value.
+   */
+  getMaxCert(): number
+
+  /**
+   * Tells wether a node is enabled or not (= member or not).
+   * @param node Node's ID.
+   * @returns {boolean} True if enabled, false otherwise.
+   */
+  isEnabled(node:number): boolean
+
+  /**
+   * Enables or disables a node.
+   * @param enabled True to enable, False to disable.
+   * @param node The node to change.
+   */
+  setEnabled(enabled:boolean, node:number): void
+
+  /**
+   * Tells wether a link exists from a member to another.
+   * @param from The emitting node.
+   * @param to The receiving node.
+   * @returns {boolean}
+   */
+  existsLink(from:number, to:number): boolean
+
+  /**
+   * Adds a link from a node to another.
+   * @param from The emitting node.
+   * @param to The receiving node.
+   * @returns {boolean} True if the link was added, false otherwise (for example if it from exceeded the maximum quota).
+   */
+  addLink(from:number, to:number): boolean
+
+  /**
+   * Removes a link from a node to another. Returns the new number of links issued to the destination node.
+   * @param from Issuer.
+   * @param to Receiver.
+   * @returns {number} The new number of links reaching Receiver.
+   */
+  removeLink(from:number, to:number): number
+
+  /**
+   * Tells wether a node is outdistanced from the WoT.
+   * @param {number} node The node we want to test.
+   * @param {number} d_min The minimum number of both issued and received certifications to be considered a sentry.
+   * @param {number} k_max The maximum distance from the sentries to the node.
+   * @param {number} x_percent The percentage of sentries to reach to not be considered outdistanced.
+   * @returns {boolean} True is the node is outdistanced, false otherwise.
+   */
+  isOutdistanced(node:number, d_min:number, k_max:number, x_percent:number): boolean
+
+  /**
+   * Gives details about the distance of a node from the WoT.
+   * @param {number} node The node we want to test.
+   * @param {number} d_min The minimum number of both issued and received certifications to be considered a sentry.
+   * @param {number} k_max The maximum distance from the sentries to the node.
+   * @param {number} x_percent The percentage of sentries to reach to not be considered outdistanced.
+   * @returns {{nbSuccess: number; nbSentries: number; nbReached: number; isOutdistanced: boolean}} The number of reached sentries, the number of sentries, the number of reached members, the distance test.
+   */
+  detailedDistance(node:number, d_min:number, k_max:number, x_percent:number): {
+    nbSuccess: number
+    nbSentries: number
+    nbReached: number
+    isOutdistanced: boolean
+  }
+
+  /**
+   * Returns the sentries of the WoT.
+   * @param {number} d_min The minimum number of both issued and received certifications to be considered a sentry.
+   * @returns {number} An array of node ID (= array of integers).
+   */
+  getSentries(d_min:number): number[]
+
+  /**
+   * Returns the non-sentires of the WoT.
+   * @param {number} d_min The minimum number of both issued and received certifications to be considered a sentry.
+   * @returns {number} An array of node ID (= array of integers).
+   */
+  getNonSentries(d_min:number): number[]
+
+  /**
+   * Returns the non-members of the WoT.
+   * @returns {number} An array of node ID (= array of integers).
+   */
+  getDisabled(): number[]
+
+  /**
+   * Returns the list of existing paths from a node to another, using a maximum of k_max steps.
+   * @param {number} from The departure node.
+   * @param {number} to The arrival node.
+   * @param {number} k_max The maximum number of steps allowed for reaching the arrival node from departure node.
+   * @returns {number[][]} A list of paths. Example of paths from ID 5 to ID 189 using k_max 4
+   *   [0] = [5, 822, 333, 12, 189]
+   *   [1] = [5, 29, 189]
+   *   [2] = [5, 189]
+   */
+  getPaths(from:number, to:number, k_max:number): number[][]
+}
+
 export interface WoTBInterface {
   fileInstance: (filepath:string) => any
   memoryInstance: () => any
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..575ab3eb05369d70d38d08a9398394769eacabff 100644
--- a/app/modules/bma/lib/bma.ts
+++ b/app/modules/bma/lib/bma.ts
@@ -24,12 +24,11 @@ import {UDBinding} from "./controllers/uds"
 import {PeerDTO} from "../../../lib/dto/PeerDTO"
 import {BlockDTO} from "../../../lib/dto/BlockDTO"
 import {OtherConstants} from "../../../lib/other_constants"
+import {WebSocketServer} from "../../../lib/common-libs/websocket"
 
-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 = [];
@@ -110,7 +109,7 @@ export const bma = function(server:Server, interfaces:NetworkInterface[], httpLo
 
   }, (httpServer:any) => {
 
-    let currentBlock = {};
+    let currentBlock:any = {};
     let wssBlock = new WebSocketServer({
       server: httpServer,
       path: '/ws/block'
@@ -129,18 +128,16 @@ export const bma = function(server:Server, interfaces:NetworkInterface[], httpLo
       logger && logger.error(error);
     });
 
-    wssBlock.on('connection', function connection(ws:any) {
-      co(function *() {
-        try {
-          currentBlock = yield server.dal.getCurrentBlockOrNull();
-          if (currentBlock) {
-            const blockDTO:BlockDTO = BlockDTO.fromJSONObject(currentBlock)
-            ws.send(JSON.stringify(block2HttpBlock(blockDTO)))
-          }
-        } catch (e) {
-          logger.error(e);
+    wssBlock.on('connection', async function connection(ws:any) {
+      try {
+        currentBlock = await server.dal.getCurrentBlockOrNull();
+        if (currentBlock) {
+          const blockDTO:BlockDTO = BlockDTO.fromJSONObject(currentBlock)
+          ws.send(JSON.stringify(block2HttpBlock(blockDTO)))
         }
-      });
+      } catch (e) {
+        logger.error(e);
+      }
     });
 
     wssHeads.on('connection', async (ws:any) => {
@@ -152,16 +149,17 @@ export const bma = function(server:Server, interfaces:NetworkInterface[], httpLo
         }
       }
     })
-    wssHeads.broadcast = (data:any) => wssHeads.clients.forEach((client:any) => client.send(data));
+    const wssHeadsBroadcast = (data:any) => wssHeads.clients.forEach((client:any) => client.send(data));
 
-    wssBlock.broadcast = (data:any) => wssBlock.clients.forEach((client:any) => {
+    const wssBlockBroadcast = (data:any) => wssBlock.clients.forEach((client:any) => {
       try {
         client.send(data);
       } catch (e) {
         logger && logger.error('error on ws: %s', e);
       }
     });
-    wssPeer.broadcast = (data:any) => wssPeer.clients.forEach((client:any) => client.send(data));
+
+    const wssPeerBroadcast = (data:any) => wssPeer.clients.forEach((client:any) => client.send(data));
 
     // Forward current HEAD change
     server
@@ -171,7 +169,7 @@ export const bma = function(server:Server, interfaces:NetworkInterface[], httpLo
             // Broadcast block
             currentBlock = e.block;
             const blockDTO:BlockDTO = BlockDTO.fromJSONObject(currentBlock)
-            wssBlock.broadcast(JSON.stringify(block2HttpBlock(blockDTO)))
+            wssBlockBroadcast(JSON.stringify(block2HttpBlock(blockDTO)))
           } catch (e) {
             logger && logger.error('error on ws mapSync:', e);
           }
@@ -193,11 +191,11 @@ export const bma = function(server:Server, interfaces:NetworkInterface[], httpLo
               signature: peerDTO.signature,
               raw: peerDTO.getRaw()
             }
-            wssPeer.broadcast(JSON.stringify(peerResult));
+            wssPeerBroadcast(JSON.stringify(peerResult));
           }
           // Broadcast heads
           else if (data.ws2p === 'heads' && data.added.length) {
-            wssHeads.broadcast(JSON.stringify(data.added));
+            wssHeadsBroadcast(JSON.stringify(data.added));
           }
         } catch (e) {
           logger && logger.error('error on ws mapSync:', e);
diff --git a/app/modules/bma/lib/controllers/blockchain.ts b/app/modules/bma/lib/controllers/blockchain.ts
index 0a0afd8c50023b85029350426aa9b7d59a8f5122..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"
@@ -28,8 +27,10 @@ import {
   HttpParameters,
   HttpStat
 } 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');
 
@@ -118,9 +119,53 @@ export class BlockchainBinding extends AbstractController {
     const params = ParametersService.getCountAndFrom(req);
     const count = parseInt(params.count);
     const from = parseInt(params.from);
-    let blocks = await this.BlockchainService.blocksBetween(from, count);
+    let blocks: any[] = await this.BlockchainService.blocksBetween(from, count);
     blocks = blocks.map((b:any) => toJson.block(b));
-    return blocks;
+    return blocks.map(b => ({
+      version: b.version,
+      currency: b.currency,
+      number: b.number,
+      issuer: b.issuer,
+      issuersFrame: b.issuersFrame,
+      issuersFrameVar: b.issuersFrameVar,
+      issuersCount: b.issuersCount,
+      parameters: b.parameters,
+      membersCount: b.membersCount,
+      monetaryMass: b.monetaryMass,
+      powMin: b.powMin,
+      time: b.time,
+      medianTime: b.medianTime,
+      dividend: b.dividend,
+      unitbase: b.unitbase,
+      hash: b.hash,
+      previousHash: b.previousHash,
+      previousIssuer: b.previousIssuer,
+      identities: b.identities,
+      certifications: b.certifications,
+      joiners: b.joiners,
+      actives: b.actives,
+      leavers: b.leavers,
+      revoked: b.revoked,
+      excluded: b.excluded,
+      transactions: b.transactions.map((t:TransactionDTO) => ({
+        version: t.version,
+        currency: t.currency,
+        comment: t.comment,
+        locktime: t.locktime,
+        signatures: t.signatures,
+        outputs: t.outputs,
+        inputs: t.inputs,
+        unlocks: t.unlocks,
+        blockstamp: t.blockstamp,
+        blockstampTime: t.blockstampTime,
+        issuers: t.issuers,
+        hash: t.hash,
+      })),
+      nonce: b.nonce,
+      inner_hash: b.inner_hash,
+      signature: b.signature,
+      raw: b.raw,
+    }))
   }
 
   async current(): Promise<HttpBlock> {
@@ -132,7 +177,7 @@ export class BlockchainBinding extends AbstractController {
   async hardship(req:any): Promise<HttpHardship> {
     let nextBlockNumber = 0;
     const search = await ParametersService.getSearchP(req);
-    const idty = await this.IdentityService.findMemberWithoutMemberships(search);
+    const idty = await this.server.dal.getWrittenIdtyByPubkeyOrUidForIsMemberAndPubkey(search);
     if (!idty) {
       throw BMAConstants.ERRORS.NO_MATCHING_IDENTITY;
     }
@@ -143,7 +188,7 @@ export class BlockchainBinding extends AbstractController {
     if (current) {
       nextBlockNumber = current ? current.number + 1 : 0;
     }
-    const difficulty = await this.server.getBcContext().getIssuerPersonalizedDifficulty(idty.pubkey);
+    const difficulty = await this.server.getBcContext().getIssuerPersonalizedDifficulty(idty.pub);
     return {
       "block": nextBlockNumber,
       "level": difficulty
@@ -151,13 +196,16 @@ export class BlockchainBinding extends AbstractController {
   }
 
   async difficulties(): Promise<HttpDifficulties> {
-    const current = await this.server.dal.getCurrentBlockOrNull();
+    const current = await this.server.dal.getCurrentBlockOrNull()
+    if (!current) {
+      throw Error(DataErrors[DataErrors.BLOCKCHAIN_NOT_INITIALIZED_YET])
+    }
     const number = (current && current.number) || 0;
     const issuers = await this.server.dal.getUniqueIssuersBetween(number - 1 - current.issuersFrame, number - 1);
     const difficulties = [];
     for (const issuer of issuers) {
-      const member = await this.server.dal.getWrittenIdtyByPubkey(issuer);
-      const difficulty = await this.server.getBcContext().getIssuerPersonalizedDifficulty(member.pubkey);
+      const member = await this.server.dal.getWrittenIdtyByPubkeyForUidAndPubkey(issuer);
+      const difficulty = await this.server.getBcContext().getIssuerPersonalizedDifficulty(member.pub);
       difficulties.push({
         uid: member.uid,
         level: difficulty
@@ -165,18 +213,18 @@ export class BlockchainBinding extends AbstractController {
     }
     return {
       "block": number + 1,
-      "levels": _.sortBy(difficulties, (diff:any) => diff.level)
+      "levels": Underscore.sortBy(difficulties, (diff:any) => diff.level)
     };
   }
 
   async memberships(req:any): Promise<HttpMemberships> {
     const search = await ParametersService.getSearchP(req);
-    const idty:any = await this.IdentityService.findMember(search);
+    const { idty, memberships } = await this.IdentityService.findMember(search);
     const json = {
       pubkey: idty.pubkey,
       uid: idty.uid,
       sigDate: idty.buid,
-      memberships: idty.memberships.map((msObj:any) => {
+      memberships: memberships.map((msObj:any) => {
         const ms = MembershipDTO.fromJSONObject(msObj);
         return {
           version: ms.version,
@@ -188,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 068993fc12aedcbb21ac75e2a53ea2940eb4e297..3706b8daabdf7dd4fe2f0272906aae57e2e789da 100644
--- a/app/modules/bma/lib/controllers/transactions.ts
+++ b/app/modules/bma/lib/controllers/transactions.ts
@@ -13,13 +13,12 @@
 
 import {AbstractController} from "./AbstractController";
 import {ParametersService} from "../parameters";
-import {Source} from "../entity/source";
 import {BMAConstants} from "../constants";
 import {TransactionDTO} from "../../../../lib/dto/TransactionDTO";
 import {HttpSources, HttpTransaction, HttpTxHistory, HttpTxOfHistory, HttpTxPending} from "../dtos";
-import {DBTx} from "../../../../lib/dal/sqliteDAL/TxsDAL";
+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 {
@@ -45,15 +44,11 @@ export class TransactionBinding extends AbstractController {
   async getSources(req:any): Promise<HttpSources> {
     const pubkey = await ParametersService.getPubkeyP(req);
     const sources = await this.server.dal.getAvailableSourcesByPubkey(pubkey);
-    const result:any = {
-      "currency": this.conf.currency,
-      "pubkey": pubkey,
-      "sources": []
-    };
-    sources.forEach(function (src:any) {
-      result.sources.push(new Source(src).json());
-    });
-    return result;
+    return {
+      currency: this.conf.currency,
+      pubkey,
+      sources
+    }
   }
 
   async getByHash(req:any): Promise<HttpTransaction> {
@@ -96,9 +91,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 +104,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,21 +115,32 @@ 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;
     });
   }
 
   async getPending(): Promise<HttpTxPending> {
     const pending = await this.server.dal.getTransactionsPending();
-    const res = {
-      "currency": this.conf.currency,
-      "pending": pending
-    };
-    pending.map(function(tx:any, index:number) {
-      pending[index] = _.omit(TransactionDTO.fromJSONObject(tx).json(), 'currency', 'raw');
-    });
-    return res;
+    return {
+      currency: this.conf.currency,
+      pending: pending.map(t => {
+        const tx = TransactionDTO.fromJSONObject(t)
+        return {
+          version: tx.version,
+          issuers: tx.issuers,
+          inputs: tx.inputs,
+          unlocks: tx.unlocks,
+          outputs: tx.outputs,
+          comment: tx.comment,
+          locktime: tx.locktime,
+          blockstamp: tx.blockstamp,
+          blockstampTime: tx.blockstampTime,
+          signatures: tx.signatures,
+          hash: tx.hash
+        }
+      })
+    }
   }
 
   private async getFilteredHistory(pubkey:string, filter:any): Promise<HttpTxHistory> {
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 5e8a8c54431f58b18da88994bd4cf45306486c5c..6a5e8bb23b2d1eea8ad43c1e918f15ec4dcc18b6 100644
--- a/app/modules/bma/lib/controllers/wot.ts
+++ b/app/modules/bma/lib/controllers/wot.ts
@@ -11,25 +11,32 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-import { IindexEntry } from './../../../../lib/indexer';
 import {AbstractController} from "./AbstractController";
 import {BMAConstants} from "../constants";
 import {DBIdentity} from "../../../../lib/dal/sqliteDAL/IdentityDAL";
-import { IdentityForRequirements } from '../../../../service/BlockchainService';
+import {IdentityForRequirements} from '../../../../service/BlockchainService';
 import {
   HttpCert,
-  HttpCertIdentity, HttpCertifications,
+  HttpCertIdentity,
+  HttpCertification,
+  HttpCertifications,
   HttpIdentity,
   HttpIdentityRequirement,
   HttpLookup,
   HttpMembers,
   HttpMembershipList,
   HttpRequirements,
-  HttpResult, HttpSimpleIdentity
+  HttpResult,
+  HttpSimpleIdentity
 } from "../dtos";
+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');
 
 const ParametersService = require('../parameters').ParametersService
 
@@ -39,33 +46,33 @@ 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
     for (const idty of identities) {
-      const certs = await this.server.dal.certsToTarget(idty.pubkey, idty.getTargetHash());
+      const certs: any[] = await this.server.dal.certsToTarget(idty.pubkey, idty.getTargetHash());
       const validCerts = [];
       for (const cert of certs) {
-        const member = await this.IdentityService.getWrittenByPubkey(cert.from);
+        const member = await this.server.dal.getWrittenIdtyByPubkeyForUidAndIsMemberAndWasMember(cert.from);
         if (member) {
           cert.uids = [member.uid];
           cert.isMember = member.member;
           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]);
-        cert.idty = await this.server.dal.getIdentityByHashOrNull(cert.target);
+        const cert = Underscore.clone(signed[j]);
+        cert.idty = await this.server.dal.getGlobalIdentityByHashForLookup(cert.target)
         if (cert.idty) {
           validSigned.push(cert);
         } else {
@@ -77,7 +84,7 @@ export class WOTBinding extends AbstractController {
     if (identities.length == 0) {
       throw BMAConstants.ERRORS.NO_MATCHING_IDENTITY;
     }
-    const resultsByPubkey:any = {};
+    const resultsByPubkey:Map<HttpIdentity> = {};
     identities.forEach((identity) => {
       const copy = DBIdentity.copyFromExisting(identity)
       const jsoned = copy.json();
@@ -94,7 +101,7 @@ export class WOTBinding extends AbstractController {
     });
     return {
       partial: false,
-      results: _.values(resultsByPubkey)
+      results: Underscore.values(resultsByPubkey)
     };
   }
 
@@ -109,49 +116,38 @@ export class WOTBinding extends AbstractController {
 
   async certifiersOf(req:any): Promise<HttpCertifications> {
     const search = await ParametersService.getSearchP(req);
-    const idty = await this.IdentityService.findMemberWithoutMemberships(search);
-    const certs = await this.server.dal.certsToTarget(idty.pubkey, idty.getTargetHash());
-    idty.certs = [];
+    const idty = (await this.server.dal.getWrittenIdtyByPubkeyOrUIdForHashingAndIsMember(search)) as FullIindexEntry
+    const certs = await this.server.dal.certsToTarget(idty.pub, IdentityDTO.getTargetHash(idty))
+    const theCerts:HttpCertification[] = [];
     for (const cert of certs) {
-      const certifier = await this.server.dal.getWrittenIdtyByPubkey(cert.from);
+      const certifier = await this.server.dal.getWrittenIdtyByPubkeyForUidAndMemberAndCreatedOn(cert.from);
       if (certifier) {
-        cert.uid = certifier.uid;
-        cert.isMember = certifier.member;
-        cert.sigDate = certifier.buid;
-        cert.wasMember = true; // As we checked if(certified)
-        if (!cert.cert_time) {
-          let certBlock = await this.server.dal.getBlock(cert.block_number);
-          cert.cert_time = {
+        let certBlock = await this.server.dal.getBlockWeHaveItForSure(cert.block_number)
+        theCerts.push({
+          pubkey: cert.from,
+          uid: certifier.uid,
+          isMember: certifier.member,
+          wasMember: true, // a member is necessarily certified by members
+          cert_time: {
             block: certBlock.number,
             medianTime: certBlock.medianTime
-          };
-        }
-        idty.certs.push(cert);
+          },
+          sigDate: certifier.created_on,
+          written: (cert.written_block !== null && cert.written_hash) ? {
+            number: cert.written_block,
+            hash: cert.written_hash
+          } : null,
+          signature: cert.sig
+        })
       }
     }
-    const json:any = {
-      pubkey: idty.pubkey,
+    return {
+      pubkey: idty.pub,
       uid: idty.uid,
-      sigDate: idty.buid,
+      sigDate: idty.created_on,
       isMember: idty.member,
-      certifications: []
-    };
-    idty.certs.forEach(function(cert){
-      json.certifications.push({
-        pubkey: cert.from,
-        uid: cert.uid,
-        isMember: cert.isMember,
-        wasMember: cert.wasMember,
-        cert_time: cert.cert_time,
-        sigDate: cert.sigDate,
-        written: cert.linked ? {
-          number: cert.written_block,
-          hash: cert.written_hash
-        } : null,
-        signature: cert.sig
-      });
-    });
-    return json;
+      certifications: theCerts
+    }
   }
 
   async requirements(req:any): Promise<HttpRequirements> {
@@ -168,29 +164,23 @@ export class WOTBinding extends AbstractController {
 
   async requirementsOfPending(req:any): Promise<HttpRequirements> {
     const minsig = ParametersService.getMinSig(req)
-    let identities:IdentityForRequirements[] = await this.server.dal.idtyDAL.query(
+    let identities:IdentityForRequirements[] = (await this.server.dal.idtyDAL.query(
       'SELECT i.*, count(c.sig) as nbSig ' +
       'FROM idty i, cert c ' +
       'WHERE c.target = i.hash group by i.hash having nbSig >= ?',
-      minsig)
-    const members:IdentityForRequirements[] = (await this.server.dal.idtyDAL.query(
-      'SELECT i.*, count(c.sig) as nbSig ' +
-      'FROM i_index i, cert c ' +
-      'WHERE c.`to` = i.pub group by i.pub having nbSig >= ?',
-      minsig)).map((i:IindexEntry):IdentityForRequirements => {
-        return {
-          hash: i.hash || "",
-          member: i.member || false,
-          wasMember: i.wasMember || false,
-          pubkey: i.pub,
-          uid: i.uid || "",
-          buid: i.created_on || "",
-          sig: i.sig || "",
-          revocation_sig: "",
-          revoked: false,
-          revoked_on: 0
-        }
-      })
+      [minsig])).map(i => ({
+      hash: i.hash || "",
+      member: i.member || false,
+      wasMember: i.wasMember || false,
+      pubkey: i.pubkey,
+      uid: i.uid || "",
+      buid: i.buid || "",
+      sig: i.sig || "",
+      revocation_sig: i.revocation_sig,
+      revoked: i.revoked,
+      revoked_on: i.revoked_on ? 1 : 0
+    }))
+    const members = await this.server.dal.findReceiversAbove(minsig)
     identities = identities.concat(members)
     const all = await this.BlockchainService.requirementsOfIdentities(identities, false);
     if (!all || !all.length) {
@@ -203,63 +193,53 @@ export class WOTBinding extends AbstractController {
 
   async certifiedBy(req:any): Promise<HttpCertifications> {
     const search = await ParametersService.getSearchP(req);
-    const idty = await this.IdentityService.findMemberWithoutMemberships(search);
-    const certs = await this.server.dal.certsFrom(idty.pubkey);
-    idty.certs = [];
+    const idty = (await this.server.dal.getWrittenIdtyByPubkeyOrUIdForHashingAndIsMember(search)) as FullIindexEntry
+    const certs = await this.server.dal.certsFrom(idty.pub);
+    const theCerts:HttpCertification[] = [];
     for (const cert of certs) {
-      const certified = await this.server.dal.getWrittenIdtyByPubkey(cert.to);
+      const certified = await this.server.dal.getWrittenIdtyByPubkeyForUidAndMemberAndCreatedOn(cert.to);
       if (certified) {
-        cert.uid = certified.uid;
-        cert.isMember = certified.member;
-        cert.sigDate = certified.buid;
-        cert.wasMember = true; // As we checked if(certified)
-        if (!cert.cert_time) {
-          let certBlock = await this.server.dal.getBlock(cert.block_number);
-          cert.cert_time = {
+        let certBlock = await this.server.dal.getBlockWeHaveItForSure(cert.block_number)
+        theCerts.push({
+          pubkey: cert.to,
+          uid: certified.uid,
+          isMember: certified.member,
+          wasMember: true, // a member is necessarily certified by members
+          cert_time: {
             block: certBlock.number,
             medianTime: certBlock.medianTime
-          };
-        }
-        idty.certs.push(cert);
+          },
+          sigDate: certified.created_on,
+          written: (cert.written_block !== null && cert.written_hash) ? {
+            number: cert.written_block,
+            hash: cert.written_hash
+          } : null,
+          signature: cert.sig
+        })
       }
     }
-    const json:any = {
-      pubkey: idty.pubkey,
+    return {
+      pubkey: idty.pub,
       uid: idty.uid,
-      sigDate: idty.buid,
+      sigDate: idty.created_on,
       isMember: idty.member,
-      certifications: []
-    };
-    idty.certs.forEach((cert) => json.certifications.push({
-        pubkey: cert.to,
-        uid: cert.uid,
-        isMember: cert.isMember,
-        wasMember: cert.wasMember,
-        cert_time: cert.cert_time,
-        sigDate: cert.sigDate,
-        written: cert.linked ? {
-          number: cert.written_block,
-          hash: cert.written_hash
-        } : null,
-        signature: cert.sig
-      })
-    );
-    return json;
+      certifications: theCerts
+    }
   }
 
   async identityOf(req:any): Promise<HttpSimpleIdentity> {
     let search = await ParametersService.getSearchP(req);
-    let idty = await this.IdentityService.findMemberWithoutMemberships(search);
+    const idty = await this.server.dal.getWrittenIdtyByPubkeyOrUIdForHashingAndIsMember(search)
     if (!idty) {
-      throw 'Identity not found';
+      throw constants.ERRORS.NO_MEMBER_MATCHING_PUB_OR_UID;
     }
     if (!idty.member) {
       throw 'Not a member';
     }
     return {
-      pubkey: idty.pubkey,
+      pubkey: idty.pub,
       uid: idty.uid,
-      sigDate: idty.buid
+      sigDate: idty.created_on
     };
   }
 
@@ -298,20 +278,20 @@ export class WOTBinding extends AbstractController {
   async pendingMemberships(): Promise<HttpMembershipList> {
     const memberships = await this.server.dal.findNewcomers();
     const json = {
-      memberships: memberships.map((ms:any) => {
+      memberships: memberships.map((ms:DBMembership) => {
         return {
           pubkey: ms.issuer,
           uid: ms.userid,
-          version: ms.version || 0,
+          version: 10,
           currency: this.server.conf.currency,
           membership: ms.membership,
-          blockNumber: parseInt(ms.blockNumber),
+          blockNumber: ms.blockNumber,
           blockHash: ms.blockHash,
           written: (!ms.written_number && ms.written_number !== 0) ? null : ms.written_number
         };
       })
     };
-    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 f37c5139fd4da215ba1e516f7b48cd11eb75a7e4..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: {
@@ -125,16 +125,14 @@ export interface HttpMemberships {
   pubkey: string
   uid: string
   sigDate: string
-  memberships: [
-    {
-      version: number
-      currency: string
-      membership: string
-      blockNumber: number
-      blockHash: string
-      written: number
-    }
-  ]
+  memberships: {
+    version: number
+    currency: string
+    membership: string
+    blockNumber: number
+    blockHash: string
+    written: number
+  }[]
 }
 
 export const MembershipList = {
@@ -153,18 +151,16 @@ export const MembershipList = {
 };
 
 export interface HttpMembershipList {
-  memberships: [
-    {
-      pubkey: string
-      uid: string
-      version: number
-      currency: string
-      membership: string
-      blockNumber: number
-      blockHash: string
-      written: number
-    }
-  ]
+  memberships: {
+    pubkey: string
+    uid: string
+    version: number
+    currency: string
+    membership: string
+    blockNumber: number
+    blockHash: string
+    written: number|null
+  }[]
 }
 
 export const TransactionOfBlock = {
@@ -186,17 +182,16 @@ export const TransactionOfBlock = {
 export interface HttpTransactionOfBlock {
   version: number
   currency: string
-  comment: string
   locktime: number
-  signatures: string[]
-  outputs: string[]
-  inputs: string[]
-  unlocks: string[]
-  block_number: number
+  hash: string
   blockstamp: string
   blockstampTime: number
-  time: number
   issuers: string[]
+  inputs: string[]
+  outputs: string[]
+  unlocks: string[]
+  signatures: string[]
+  comment: string
 }
 
 export const Block = {
@@ -246,7 +241,7 @@ export interface HttpBlock {
   powMin: number
   time: number
   medianTime: number
-  dividend: number
+  dividend: number|null
   unitbase: number
   hash: string
   previousHash: string
@@ -303,10 +298,9 @@ export function block2HttpBlock(blockDTO:BlockDTO): HttpBlock {
         outputs: tx.outputs,
         inputs: tx.inputs,
         unlocks: tx.unlocks,
-        block_number: tx.blockNumber,
+        hash: tx.hash,
         blockstamp: tx.blockstamp,
         blockstampTime: tx.blockstampTime,
-        time: tx.blockstampTime
       }
     }),
     nonce: blockDTO.nonce,
@@ -406,7 +400,7 @@ export const Peers = {
 };
 
 export interface HttpPeers {
-  peers: DBPeer2[]
+  peers: JSONDBPeer[]
 }
 
 export interface HttpWS2PInfo {
@@ -440,7 +434,7 @@ export interface HttpMerkleOfPeers {
   leaves: string[]
   leaf: {
     hash: string
-    value: DBPeer2
+    value: JSONDBPeer
   }
 }
 
@@ -486,9 +480,9 @@ export interface HttpUID {
     timestamp: string
   },
   self: string,
-  revocation_sig: string,
+  revocation_sig: string|null,
   revoked: boolean,
-  revoked_on: number,
+  revoked_on: number|null,
   others: HttpOther[]
 }
 
@@ -712,7 +706,7 @@ export interface HttpCertification {
   written: {
     number: number
     hash: string
-  }
+  } | null
   signature: string
 }
 
@@ -774,6 +768,18 @@ export interface HttpTransaction {
   hash: string
 }
 
+export interface HttpTransactionPending {
+  version: number
+  issuers: string[]
+  inputs: string[]
+  unlocks: string[]
+  outputs: string[]
+  comment: string
+  locktime: number
+  signatures: string[]
+  hash: string
+}
+
 export const Source = {
   "type": String,
   "noffset": Number,
@@ -869,7 +875,7 @@ export const TxPending = {
 
 export interface HttpTxPending {
   currency: string
-  pending: HttpTransaction[]
+  pending: HttpTransactionPending[]
 }
 
 export const UD = {
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/parameters.ts b/app/modules/bma/lib/parameters.ts
index fed7b661e6b9f33fda042444a1ada168a7764a52..3db765af14be26c83ebc4ce899d08953667618ba 100644
--- a/app/modules/bma/lib/parameters.ts
+++ b/app/modules/bma/lib/parameters.ts
@@ -62,7 +62,7 @@ export class ParametersService {
     return req.params.hash;
   };
 
-  static getMinSig(req:any){
+  static getMinSig(req:any): number {
     if(!req.params.minsig){
       return 4 // Default value
     }
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 e37bd9258cac3b72fc67dcc3b47566a3abc827a5..0442cb20a68a968f896705e89cd4957b2de1fed7 100644
--- a/app/modules/config.ts
+++ b/app/modules/config.ts
@@ -15,6 +15,8 @@
 import {ConfDTO} from "../lib/dto/ConfDTO"
 import {Server} from "../../server"
 import {CommonConstants} from "../lib/common-libs/constants"
+import {Directory} from "../lib/system/directory"
+import {Underscore} from "../lib/common-libs/underscore"
 
 module.exports = {
   duniter: {
@@ -35,6 +37,98 @@ module.exports = {
       desc: 'Register configuration in database',
       // The command does nothing particular, it just stops the process right after configuration phase is over
       onConfiguredExecute: (server:Server, conf:ConfDTO) => Promise.resolve(conf)
+    }, {
+      name: 'parse-logs',
+      desc: 'Extract data from logs.',
+      logs: true,
+      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 = Underscore.uniq(
+          lines
+          .map(l => l.match(/: (\[\w+\](\[\w+\])*)/))
+          .filter(l => l)
+          .map((l:string[]) => l[1])
+        )
+        console.log(aggregates)
+        const results = aggregates.map((a:string) => {
+          return {
+            name: a,
+            time: lines
+              .filter(l => l.match(new RegExp(a
+                .replace(/\[/g, '\\[')
+                .replace(/\]/g, '\\]')
+              )))
+              .map(l => {
+                const m = l.match(/ (\d+)(\.\d+)?(ms|µs)( \d+)?$/)
+                if (!m) {
+                  throw Error('Wrong match')
+                }
+                return m
+              })
+              .map(match => {
+                return {
+                  qty: parseInt(match[1]),
+                  unit: match[3],
+                }
+              })
+              .reduce((sumMicroSeconds, entry) => {
+                return sumMicroSeconds + (entry.qty * (entry.unit === 'ms' ? 1000 : 1))
+              }, 0) / 1000000
+          }
+        })
+        const root:Tree = {
+          name: 'root',
+          leaves: {}
+        }
+        for (const r of results) {
+          recursiveReduce(root, r.name, r.time)
+        }
+        recursiveDump(root)
+      }
     }]
   }
 }
+
+interface Leaf {
+  name:string
+  value:number
+}
+
+interface Tree {
+  name:string
+  leaves: { [k:string]: Tree|Leaf }
+}
+
+function recursiveReduce(tree:Tree, path:string, duration:number) {
+  if (path.match(/\]\[/)) {
+    const m = (path.match(/^(\[\w+\])(\[.+)/) as string[])
+    const key = m[1]
+    if (!tree.leaves[key]) {
+      tree.leaves[key] = {
+        name: key,
+        leaves: {}
+      }
+    }
+    recursiveReduce(tree.leaves[key] as Tree, m[2], duration)
+  } else {
+    tree.leaves[path] = {
+      name: path,
+      value: duration
+    }
+  }
+}
+
+function recursiveDump(tree:Tree, level = -1) {
+  if (level >= 0) {
+    console.log("  ".repeat(level), tree.name)
+  }
+  for (const k of Object.keys(tree.leaves)) {
+    const element = tree.leaves[k]
+    if ((<Tree>element).leaves) {
+      recursiveDump(<Tree>element, level + 1)
+    } else {
+      console.log("  ".repeat(level + 1), (<Leaf>element).name, (<Leaf>element).value + 's')
+    }
+  }
+}
\ No newline at end of file
diff --git a/app/modules/crawler/index.ts b/app/modules/crawler/index.ts
index 8eff8439a3633275c32dcc25c4b45f99524e6ad7..2d72d7b411e6751aa1d118c79c3178925db994ed 100644
--- a/app/modules/crawler/index.ts
+++ b/app/modules/crawler/index.ts
@@ -21,6 +21,11 @@ import {rawer} from "../../lib/common-libs/index"
 import {PeerDTO} from "../../lib/dto/PeerDTO"
 import {Buid} from "../../lib/common-libs/buid"
 import {BlockDTO} from "../../lib/dto/BlockDTO"
+import {Directory} from "../../lib/system/directory"
+import {FileDAL} from "../../lib/dal/fileDAL"
+import {RemoteSynchronizer} from "./lib/sync/RemoteSynchronizer"
+import {AbstractSynchronizer} from "./lib/sync/AbstractSynchronizer"
+import {LocalPathSynchronizer} from "./lib/sync/LocalPathSynchronizer"
 
 export const CrawlerDependency = {
   duniter: {
@@ -31,9 +36,9 @@ 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) => {
+      pullBlocks: async (server:Server, pubkey = "") => {
         const crawler = new Crawler(server, server.conf, server.logger);
         return crawler.pullBlocks(server, pubkey);
       },
@@ -44,17 +49,28 @@ export const CrawlerDependency = {
       },
 
       synchronize: (server:Server, onHost:string, onPort:number, upTo:number, chunkLength:number) => {
-        const remote = new Synchroniser(server, onHost, onPort);
-        const syncPromise = remote.sync(upTo, chunkLength)
+        const strategy = new RemoteSynchronizer(onHost, onPort, server)
+        const remote = new Synchroniser(server, strategy)
+        const syncPromise = (async () => {
+          await server.dal.disableChangesAPI()
+          await remote.sync(upTo, chunkLength)
+          await server.dal.enableChangesAPI()
+        })()
         return {
           flow: remote,
-          syncPromise: syncPromise
+          syncPromise
         };
       },
 
+      /**
+       * Used by duniter-ui
+       * @param {Server} server
+       * @param {string} onHost
+       * @param {number} onPort
+       * @returns {Promise<any>}
+       */
       testForSync: (server:Server, onHost:string, onPort:number) => {
-        const remote = new Synchroniser(server, onHost, onPort);
-        return remote.test();
+        return RemoteSynchronizer.test(onHost, onPort)
       }
     },
 
@@ -63,24 +79,25 @@ export const CrawlerDependency = {
       { value: '--nocautious',    desc: 'Do not check blocks validity during sync.'},
       { value: '--cautious',      desc: 'Check blocks validity during sync (overrides --nocautious option).'},
       { value: '--nopeers',       desc: 'Do not retrieve peers during sync.'},
+      { value: '--nosources',     desc: 'Do not parse sources (UD, TX) during sync (debug purposes).'},
+      { value: '--nosbx',         desc: 'Do not retrieve sandboxes during sync.'},
       { value: '--onlypeers',     desc: 'Will only try to sync peers.'},
       { value: '--slow',          desc: 'Download slowly the blokchcain (for low connnections).'},
+      { value: '--readfilesystem',desc: 'Also read the filesystem to speed up block downloading.'},
       { value: '--minsig <minsig>', desc: 'Minimum pending signatures count for `crawl-lookup`. Default is 5.'}
     ],
 
     cli: [{
-      name: 'sync [host] [port] [to]',
+      name: 'sync [source] [to]',
       desc: 'Synchronize blockchain from a remote Duniter node',
       preventIfRunning: true,
-      onDatabaseExecute: async (server:Server, conf:ConfDTO, program:any, params:any) => {
-        const host = params[0];
-        const port = params[1];
-        const to   = params[2];
-        if (!host) {
-          throw 'Host is required.';
-        }
-        if (!port) {
-          throw 'Port is required.';
+      onDatabaseExecute: async (server:Server, conf:ConfDTO, program:any, params:any): Promise<any> => {
+        const source = params[0]
+        const to     = params[1]
+        const HOST_PATTERN = /^[^:/]+(:[0-9]{1,5})?$/
+        const FILE_PATTERN = /^(\/.+)$/
+        if (!source || !(source.match(HOST_PATTERN) || source.match(FILE_PATTERN))) {
+          throw 'Source of sync is required. (either a host:port or a file path)'
         }
         let cautious;
         if (program.nocautious) {
@@ -89,19 +106,35 @@ export const CrawlerDependency = {
         if (program.cautious) {
           cautious = true;
         }
-        const onHost = host;
-        const onPort = port;
         const upTo = parseInt(to);
         const chunkLength = 0;
         const interactive = !program.nointeractive;
         const askedCautious = cautious;
-        const nopeers = program.nopeers;
         const noShufflePeers = program.noshuffle;
-        const remote = new Synchroniser(server, onHost, onPort, interactive === true, program.slow === true);
+
+        let otherDAL = undefined
+        if (program.readfilesystem) {
+          const dbName = program.mdb;
+          const dbHome = program.home;
+          const home = Directory.getHome(dbName, dbHome);
+          const params = await Directory.getHomeParams(false, home)
+          otherDAL = new FileDAL(params)
+        }
+
+        let strategy: AbstractSynchronizer
+        if (source.match(HOST_PATTERN)) {
+          const sp = source.split(':')
+          const onHost = sp[0]
+          const onPort = parseInt(sp[1] ? sp[1] : '443') // Defaults to 443
+          strategy = new RemoteSynchronizer(onHost, onPort, server, noShufflePeers === true, otherDAL)
+        } else {
+          strategy = new LocalPathSynchronizer(source, server)
+        }
         if (program.onlypeers === true) {
-          return remote.syncPeers(nopeers, true, onHost, onPort)
+          return strategy.syncPeers(true)
         } else {
-          return remote.sync(upTo, chunkLength, askedCautious, nopeers, noShufflePeers === true)
+          const remote = new Synchroniser(server, strategy, interactive === true)
+          return remote.sync(upTo, chunkLength, askedCautious)
         }
       }
     }, {
@@ -146,7 +179,7 @@ export const CrawlerDependency = {
         const toPort = params[4];
         const logger = server.logger;
         try {
-          const peers = fromHost && fromPort ? [{ endpoints: [['BASIC_MERKLED_API', fromHost, fromPort].join(' ')] }] : await server.dal.peerDAL.query('SELECT * FROM peer WHERE status = ?', ['UP'])
+          const peers = fromHost && fromPort ? [{ endpoints: [['BASIC_MERKLED_API', fromHost, fromPort].join(' ')] }] : await server.dal.peerDAL.withUPStatus()
           // Memberships
           for (const p of peers) {
             const peer = PeerDTO.fromJSONObject(p)
@@ -299,7 +332,7 @@ export const CrawlerDependency = {
         const fromPort = params[3]
         const logger = server.logger;
         try {
-          const peers = fromHost && fromPort ? [{ endpoints: [['BASIC_MERKLED_API', fromHost, fromPort].join(' ')] }] : await server.dal.peerDAL.query('SELECT * FROM peer WHERE status = ?', ['UP'])
+          const peers = fromHost && fromPort ? [{ endpoints: [['BASIC_MERKLED_API', fromHost, fromPort].join(' ')] }] : await server.dal.peerDAL.withUPStatus()
           // Memberships
           for (const p of peers) {
             const peer = PeerDTO.fromJSONObject(p)
@@ -331,7 +364,7 @@ export const CrawlerDependency = {
           // Membership
           let rawMS
           for (const theMS of pendingMSS) {
-            console.log('New membership pending for %s', theMS.uid);
+            console.log('New membership pending for %s', theMS.userid);
             try {
               rawMS = rawer.getMembership({
                 currency: 'g1',
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 8766c226c9386d33d6342ad73cd24745248b4f71..0a0acbfa89d2bfacae717a12cab6344b59f03fbc 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).
@@ -52,7 +51,7 @@ export class Crawler extends stream.Transform implements DuniterService {
     this.sandboxCrawler = new SandboxCrawler(server, conf, logger)
   }
 
-  pullBlocks(server:Server, pubkey:string) {
+  pullBlocks(server:Server, pubkey = "") {
     return this.blockCrawler.pullBlocks(server, pubkey)
   }
 
@@ -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') {
@@ -345,7 +344,7 @@ export class BlockCrawler {
     this.syncBlockFifo.kill();
   }
 
-  pullBlocks(server:Server, pubkey:string) {
+  pullBlocks(server:Server, pubkey = "") {
     return this.syncBlock(server, pubkey)
   }
 
@@ -364,22 +363,22 @@ export class BlockCrawler {
     }
 
     try {
-      let current = await server.dal.getCurrentBlockOrNull();
+      let current: DBBlock|null = await server.dal.getCurrentBlockOrNull();
       if (current) {
         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);
@@ -406,7 +405,7 @@ export class BlockCrawler {
                 return Promise.resolve([node])
               }
               async getLocalBlock(number: number): Promise<DBBlock> {
-                return server.dal.getBlock(number)
+                return server.dal.getBlockWeHaveItForSure(number)
               }
               async getRemoteBlock(thePeer: any, number: number): Promise<BlockDTO> {
                 let block = null;
@@ -429,7 +428,7 @@ export class BlockCrawler {
                   }
                   this.crawler.pullingEvent(server, 'applying', {number: block.number, last: this.lastDownloaded && this.lastDownloaded.number});
                   if (addedBlock) {
-                    current = addedBlock;
+                    current = DBBlock.fromBlockDTO(addedBlock);
                     // Emit block events (for sharing with the network) only in forkWindowSize
                     if (nodeCurrent && nodeCurrent.number - addedBlock.number < server.conf.forksize) {
                       server.streamPush(addedBlock);
diff --git a/app/modules/crawler/lib/garbager.ts b/app/modules/crawler/lib/garbager.ts
index f748a63a66320d97dfb3e6f5729efa73bd56b74d..852d33187eb872fe9b768b9c50c12690dae73f09 100644
--- a/app/modules/crawler/lib/garbager.ts
+++ b/app/modules/crawler/lib/garbager.ts
@@ -16,5 +16,5 @@ import {Server} from "../../../../server"
 
 export const cleanLongDownPeers = async (server:Server, now:number) => {
   const first_down_limit = now - CrawlerConstants.PEER_LONG_DOWN * 1000;
-  await server.dal.peerDAL.query('DELETE FROM peer WHERE first_down < ' + first_down_limit)
+  await server.dal.peerDAL.removePeersDownBefore(first_down_limit)
 }
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/sandbox.ts b/app/modules/crawler/lib/sandbox.ts
index 58d3d79a7a1f6bde1b4a37ebf106dcdff4d392c5..f4a53218089179c38b3fd8e93268afa260823986 100644
--- a/app/modules/crawler/lib/sandbox.ts
+++ b/app/modules/crawler/lib/sandbox.ts
@@ -54,29 +54,38 @@ export const pullSandboxToLocalServer = async (currency:string, fromHost:any, to
   if (res) {
     const docs = getDocumentsTree(currency, res)
 
+    let t = 0
+    let T = docs.identities.length + docs.certifications.length + docs.revocations.length + docs.memberships.length
+
     for (let i = 0; i < docs.identities.length; i++) {
       const idty = docs.identities[i];
       watcher && watcher.writeStatus('Identity ' + (i+1) + '/' + docs.identities.length)
+      watcher && watcher.sbxPercent((t++) / T * 100)
       await submitIdentityToServer(idty, toServer, notify, logger)
     }
 
     for (let i = 0; i < docs.revocations.length; i++) {
       const idty = docs.revocations[i];
       watcher && watcher.writeStatus('Revocation ' + (i+1) + '/' + docs.revocations.length)
+      watcher && watcher.sbxPercent((t++) / T * 100)
       await submitRevocationToServer(idty, toServer, notify, logger)
     }
 
     for (let i = 0; i < docs.certifications.length; i++) {
       const cert = docs.certifications[i];
       watcher && watcher.writeStatus('Certification ' + (i+1) + '/' + docs.certifications.length)
+      watcher && watcher.sbxPercent((t++) / T * 100)
       await submitCertificationToServer(cert, toServer, notify, logger)
     }
 
     for (let i = 0; i < docs.memberships.length; i++) {
       const ms = docs.memberships[i];
       watcher && watcher.writeStatus('Membership ' + (i+1) + '/' + docs.memberships.length)
+      watcher && watcher.sbxPercent((t++) / T * 100)
       await submitMembershipToServer(ms, toServer, notify, logger)
     }
+
+    watcher && watcher.sbxPercent(100)
   }
 }
 
diff --git a/app/modules/crawler/lib/sync.ts b/app/modules/crawler/lib/sync.ts
index efdafcf78ea942b4c77a904359ae576bfb335c52..3bf8cc58d9d40700ae55402dadb2926fa7a2a062 100644
--- a/app/modules/crawler/lib/sync.ts
+++ b/app/modules/crawler/lib/sync.ts
@@ -11,73 +11,53 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-import {CrawlerConstants} from "./constants"
 import * as stream from "stream"
+import * as moment from "moment"
 import {Server} from "../../../../server"
 import {PeerDTO} from "../../../lib/dto/PeerDTO"
 import {FileDAL} from "../../../lib/dal/fileDAL"
 import {BlockDTO} from "../../../lib/dto/BlockDTO"
-import {connect} from "./connect"
-import {Contacter} from "./contacter"
-import {pullSandboxToLocalServer} from "./sandbox"
 import {tx_cleaner} from "./tx_cleaner"
 import {AbstractDAO} from "./pulling"
 import {DBBlock} from "../../../lib/db/DBBlock"
 import {BlockchainService} from "../../../service/BlockchainService"
-import {rawer} from "../../../lib/common-libs/index"
-import {dos2unix} from "../../../lib/common-libs/dos2unix"
-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 {cliprogram} from "../../../lib/common-libs/programOptions"
+import {EventWatcher, LoggerWatcher, MultimeterWatcher, Watcher} from "./sync/Watcher"
+import {ChunkGetter} from "./sync/ChunkGetter"
+import {AbstractSynchronizer} from "./sync/AbstractSynchronizer"
 
-const util         = require('util');
-const _            = require('underscore');
-const moment       = require('moment');
-const multimeter   = require('multimeter');
-const makeQuerablePromise = require('querablep');
-
-const CONST_BLOCKS_CHUNK = 250;
 const EVAL_REMAINING_INTERVAL = 1000;
-const INITIAL_DOWNLOAD_SLOTS = 1;
 
 export class Synchroniser extends stream.Duplex {
 
-  private watcher:Watcher
+  private watcher:EventWatcher
   private speed = 0
   private blocksApplied = 0
-  private contacterOptions:any
 
   constructor(
     private server:Server,
-    private host:string,
-    private port:number,
-    interactive = false,
-    private slowOption = false) {
+    private syncStrategy: AbstractSynchronizer,
+    interactive = false) {
 
     super({ objectMode: true })
 
     // Wrapper to also push event stream
-    this.watcher = new EventWatcher(
-      interactive ? new MultimeterWatcher() : new LoggerWatcher(this.logger),
-      (pct:number, innerWatcher:Watcher) => {
-        if (pct !== undefined && innerWatcher.downloadPercent() < pct) {
-          this.push({ download: pct });
-        }
-      },
-      (pct:number, innerWatcher:Watcher) => {
-        if (pct !== undefined && innerWatcher.appliedPercent() < pct) {
-          this.push({ applied: pct });
-        }
-      }
-    )
+    this.watcher = new EventWatcher(interactive ? new MultimeterWatcher() : new LoggerWatcher(this.logger))
+    this.watcher.onEvent('downloadChange', (pct: number) => this.push({ download: pct }))
+    this.watcher.onEvent('storageChange',  (pct: number) => this.push({ saved: pct }))
+    this.watcher.onEvent('appliedChange',  (pct: number) => this.push({ applied: pct }))
+    this.watcher.onEvent('sbxChange',      (pct: number) => this.push({ sandbox: pct }))
+    this.watcher.onEvent('peersChange',    (pct: number) => this.push({ peersSync: pct }))
+
+    this.syncStrategy.setWatcher(this.watcher)
 
     if (interactive) {
       this.logger.mute();
     }
-
-    this.contacterOptions = {
-      timeout: CrawlerConstants.SYNC_LONG_TIMEOUT
-    }
   }
 
   get conf(): ConfDTO {
@@ -117,22 +97,10 @@ export class Synchroniser extends stream.Duplex {
     }
   }
 
-  async test() {
-    const peering = await Contacter.fetchPeer(this.host, this.port, this.contacterOptions);
-    const node = await connect(PeerDTO.fromJSONObject(peering));
-    return node.getCurrent();
-  }
-
-  async sync(to:number, chunkLen:number, askedCautious = false, nopeers = false, noShufflePeers = false) {
+  async sync(to:number, chunkLen:number, askedCautious = false) {
 
     try {
-
-      const peering = await Contacter.fetchPeer(this.host, this.port, this.contacterOptions);
-
-      let peer = PeerDTO.fromJSONObject(peering);
-      this.logger.info("Try with %s %s", peer.getURL(), peer.pubkey.substr(0, 6));
-      let node:any = await connect(peer);
-      node.pubkey = peer.pubkey;
+      await this.syncStrategy.init()
       this.logger.info('Sync started.');
 
       const fullSync = !to;
@@ -141,57 +109,30 @@ export class Synchroniser extends stream.Duplex {
       // Blockchain headers
       //============
       this.logger.info('Getting remote blockchain info...');
-      this.watcher.writeStatus('Connecting to ' + this.host + '...');
-      const lCurrent:DBBlock = await this.dal.getCurrentBlockOrNull();
+      const lCurrent:DBBlock|null = await this.dal.getCurrentBlockOrNull();
       const localNumber = lCurrent ? lCurrent.number : -1;
-      let rCurrent:BlockDTO
+      let rCurrent:BlockDTO|null
       if (isNaN(to)) {
-        rCurrent = await node.getCurrent();
+        rCurrent = await this.syncStrategy.getCurrent();
+        if (!rCurrent) {
+          throw 'Remote does not have a current block. Sync aborted.'
+        }
       } else {
-        rCurrent = await node.getBlock(to);
+        rCurrent = await this.syncStrategy.getBlock(to)
+        if (!rCurrent) {
+          throw 'Remote does not have a target block. Sync aborted.'
+        }
       }
       to = rCurrent.number || 0
 
-      //=======
-      // Peers (just for P2P download)
-      //=======
-      let peers:PeerDTO[] = [];
-      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 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) => {
-            if(merkle.leaves().indexOf(leaf) == -1){
-              leavesToAdd.push(leaf);
-            }
-          });
-          peers = await Promise.all(leavesToAdd.map(async (leaf) => {
-            try {
-              const json3 = await getPeers({ "leaf": leaf });
-              const jsonEntry = json3.leaf.value;
-              const endpoint = jsonEntry.endpoints[0];
-              this.watcher.writeStatus('Peer ' + endpoint);
-              return jsonEntry;
-            } catch (e) {
-              this.logger.warn("Could not get peer of leaf %s, continue...", leaf);
-              return null;
-            }
-          }))
-        }
-        else {
-          this.watcher.writeStatus('Peers already known');
-        }
+      const rootBlock = await this.syncStrategy.getBlock(0)
+      if (!rootBlock) {
+        throw 'Could not get root block. Sync aborted.'
       }
+      await this.BlockchainService.saveParametersForRootBlock(rootBlock)
+      await this.server.reloadConf()
 
-      if (!peers.length) {
-        peers.push(peer);
-      }
-      peers = peers.filter((p) => p);
+      await this.syncStrategy.initWithKnownLocalAndToAndCurrency(to, localNumber, rCurrent.currency)
 
       //============
       // Blockchain
@@ -200,12 +141,20 @@ 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 downloader = new P2PDownloader(rCurrent.currency, localNumber, to, rCurrent.hash, shuffledPeers, this.watcher, this.logger, hashf, this.dal, this.slowOption);
+      const downloader = new ChunkGetter(
+        localNumber,
+        to,
+        rCurrent.hash,
+        this.syncStrategy,
+        this.dal,
+        !cautious,
+        this.watcher)
 
-      downloader.start();
+      const startp = downloader.start()
 
       let lastPullBlock:BlockDTO|null = null;
+      let syncStrategy = this.syncStrategy
+      let node = this.syncStrategy.getPeer()
 
       let dao = new (class extends AbstractDAO {
 
@@ -218,7 +167,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) {
@@ -256,19 +205,22 @@ export class Synchroniser extends stream.Duplex {
           return [node]
         }
         async getLocalBlock(number: number): Promise<DBBlock> {
-          return this.dal.getBlock(number)
+          return this.dal.getBlockWeHaveItForSure(number)
         }
         async getRemoteBlock(thePeer: PeerDTO, number: number): Promise<BlockDTO> {
           let block = null;
           try {
-            block = await node.getBlock(number);
+            block = await syncStrategy.getBlock(number)
+            if (!block) {
+              throw 'Could not get remote block'
+            }
             tx_cleaner(block.transactions);
           } catch (e) {
             if (e.httpCode != 404) {
               throw e;
             }
           }
-          return block;
+          return block as BlockDTO
         }
         async applyMainBranch(block: BlockDTO): Promise<boolean> {
           const addedBlock = await this.BlockchainService.submitBlock(block, true)
@@ -283,45 +235,52 @@ export class Synchroniser extends stream.Duplex {
         }
         // Tells wether given peer is a member peer
         async isMemberPeer(thePeer: PeerDTO): Promise<boolean> {
-          let idty = await this.dal.getWrittenIdtyByPubkey(thePeer.pubkey);
+          let idty = await this.dal.getWrittenIdtyByPubkeyForIsMember(thePeer.pubkey);
           return (idty && idty.member) || false;
         }
-        downloadBlocks(thePeer: PeerDTO, fromNumber: number, count?: number | undefined): Promise<BlockDTO[]> {
+        async downloadBlocks(thePeer: PeerDTO, fromNumber: number, count?: number | undefined): Promise<BlockDTO[]> {
           // Note: we don't care about the particular peer asked by the method. We use the network instead.
           const numberOffseted = fromNumber - (localNumber + 1);
-          const targetChunk = Math.floor(numberOffseted / CONST_BLOCKS_CHUNK);
+          const targetChunk = Math.floor(numberOffseted / CommonConstants.CONST_BLOCKS_CHUNK);
           // Return the download promise! Simple.
-          return downloader.getChunk(targetChunk);
+          return (await downloader.getChunk(targetChunk))()
         }
 
       })(this.server, this.watcher, this.dal, this.BlockchainService)
 
       const logInterval = setInterval(() => this.logRemaining(to), EVAL_REMAINING_INTERVAL);
-      await dao.pull(this.conf, this.logger)
+      await Promise.all([
+        dao.pull(this.conf, this.logger),
+        await startp // In case of errors, will stop the process
+      ])
 
       // Finished blocks
       this.watcher.downloadPercent(100.0);
+      this.watcher.storagePercent(100.0);
       this.watcher.appliedPercent(100.0);
 
       if (logInterval) {
         clearInterval(logInterval);
       }
 
-      // Save currency parameters given by root block
-      const rootBlock = await this.server.dal.getBlock(0);
-      await this.BlockchainService.saveParametersForRootBlock(rootBlock);
       this.server.dal.blockDAL.cleanCache();
 
-      //=======
-      // Sandboxes
-      //=======
-      this.watcher.writeStatus('Synchronizing the sandboxes...');
-      await pullSandboxToLocalServer(this.conf.currency, node, this.server, this.server.logger, this.watcher, 1, false)
+      if (!cliprogram.nosbx) {
+        //=======
+        // Sandboxes
+        //=======
+        await this.syncStrategy.syncSandbox()
+      }
 
-      //=======
-      // Peers
-      //=======
-      await this.syncPeers(nopeers, fullSync, this.host, this.port, to)
+      if (!cliprogram.nopeers) {
+        //=======
+        // Peers
+        //=======
+        await this.syncStrategy.syncPeers(fullSync, to)
+      }
+
+      // Trim the loki data
+      await this.server.dal.loki.flushAndTrimData()
 
       this.watcher.end();
       this.push({ sync: true });
@@ -333,668 +292,4 @@ export class Synchroniser extends stream.Duplex {
       throw err;
     }
   }
-
-  async syncPeers(nopeers:boolean, fullSync:boolean, host:string, port:number, to?:number) {
-    if (!nopeers && fullSync) {
-
-      const peering = await Contacter.fetchPeer(host, port, this.contacterOptions);
-
-      let peer = PeerDTO.fromJSONObject(peering);
-      this.logger.info("Try with %s %s", peer.getURL(), peer.pubkey.substr(0, 6));
-      let node:any = await connect(peer);
-      node.pubkey = peer.pubkey;
-      this.logger.info('Sync started.');
-
-      this.watcher.writeStatus('Peers...');
-      await this.syncPeer(node);
-      const merkle = await this.dal.merkleForPeers();
-      const getPeers = 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) => {
-          if(merkle.leaves().indexOf(leaf) == -1){
-            leavesToAdd.push(leaf);
-          }
-        });
-        for (const leaf of leavesToAdd) {
-          try {
-            const json3 = await getPeers({ "leaf": leaf });
-            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.signature = sign;
-            this.watcher.writeStatus('Peer ' + entry.pubkey);
-            await this.PeeringService.submitP(entry, false, to === undefined);
-          } catch (e) {
-            this.logger.warn(e);
-          }
-        }
-      }
-      else {
-        this.watcher.writeStatus('Peers already known');
-      }
-    }
-  }
-
-  //============
-  // Peer
-  //============
-  private async syncPeer (node:any) {
-
-    // Global sync vars
-    const remotePeer = PeerDTO.fromJSONObject({});
-    let remoteJsonPeer:any = {};
-    const json = await node.getPeer();
-    remotePeer.version = json.version
-    remotePeer.currency = json.currency
-    remotePeer.pubkey = json.pub
-    remotePeer.endpoints = json.endpoints
-    remotePeer.blockstamp = json.block
-    remotePeer.signature = json.signature
-    const entry = remotePeer.getRawUnsigned();
-    const signature = dos2unix(remotePeer.signature);
-    // Parameters
-    if(!(entry && signature)){
-      throw 'Requires a peering entry + signature';
-    }
-
-    remoteJsonPeer = json;
-    remoteJsonPeer.pubkey = json.pubkey;
-    let signatureOK = this.PeeringService.checkPeerSignature(remoteJsonPeer);
-    if (!signatureOK) {
-      this.watcher.writeStatus('Wrong signature for peer #' + remoteJsonPeer.pubkey);
-    }
-    try {
-      await this.PeeringService.submitP(remoteJsonPeer);
-    } catch (err) {
-      if (err.indexOf !== undefined && err.indexOf(CrawlerConstants.ERRORS.NEWER_PEER_DOCUMENT_AVAILABLE.uerr.message) !== -1 && err != CrawlerConstants.ERROR.PEER.UNKNOWN_REFERENCE_BLOCK) {
-        throw err;
-      }
-    }
-  }
-}
-
-class NodesMerkle {
-
-  private depth:number
-  private nodesCount:number
-  private leavesCount:number
-  private merkleRoot:string
-
-  constructor(json:any) {
-    this.depth = json.depth
-    this.nodesCount = json.nodesCount
-    this.leavesCount = json.leavesCount
-    this.merkleRoot = json.root;
-  }
-
-  // var i = 0;
-  // this.levels = [];
-  // while(json && json.levels[i]){
-  //   this.levels.push(json.levels[i]);
-  //   i++;
-  // }
-
-  root() {
-    return this.merkleRoot
-  }
-}
-
-interface Watcher {
-  writeStatus(str: string): void
-  downloadPercent(pct?: number): number
-  appliedPercent(pct?: number): number
-  end(): void
-}
-
-class EventWatcher implements Watcher {
-
-  constructor(
-    private innerWatcher:Watcher,
-    private beforeDownloadPercentHook: (pct:number, innerWatcher:Watcher) => void,
-    private beforeAppliedPercentHook: (pct:number, innerWatcher:Watcher) => void) {
-  }
-
-  writeStatus(str: string): void {
-    this.innerWatcher.writeStatus(str)
-  }
-
-  downloadPercent(pct?: number): number {
-    this.beforeDownloadPercentHook(pct || 0, this.innerWatcher)
-    return this.innerWatcher.downloadPercent(pct)
-  }
-
-  appliedPercent(pct?: number): number {
-    this.beforeAppliedPercentHook(pct || 0, this.innerWatcher)
-    return this.innerWatcher.appliedPercent(pct)
-  }
-
-  end(): void {
-    this.innerWatcher.end()
-  }
-}
-
-class MultimeterWatcher implements Watcher {
-
-  private xPos:number
-  private yPos:number
-  private multi:any
-  private charm:any
-  private appliedBar:any
-  private downloadBar:any
-  private writtens:string[] = []
-
-  constructor() {
-    this.multi = multimeter(process);
-    this.charm = this.multi.charm;
-    this.charm.on('^C', process.exit);
-    this.charm.reset();
-
-    this.multi.write('Progress:\n\n');
-
-    this.multi.write("Download: \n");
-    this.downloadBar = this.multi("Download: \n".length, 3, {
-      width : 20,
-      solid : {
-        text : '|',
-        foreground : 'white',
-        background : 'blue'
-      },
-      empty : { text : ' ' }
-    });
-
-    this.multi.write("Apply:    \n");
-    this.appliedBar = this.multi("Apply:    \n".length, 4, {
-      width : 20,
-      solid : {
-        text : '|',
-        foreground : 'white',
-        background : 'blue'
-      },
-      empty : { text : ' ' }
-    });
-
-    this.multi.write('\nStatus: ');
-
-    this.charm.position( (x:number, y:number) => {
-      this.xPos = x;
-      this.yPos = y;
-    });
-
-    this.writtens = [];
-
-    this.downloadBar.percent(0);
-    this.appliedBar.percent(0);
-  }
-
-  writeStatus(str:string) {
-    this.writtens.push(str);
-    //require('fs').writeFileSync('writtens.json', JSON.stringify(writtens));
-    this.charm
-      .position(this.xPos, this.yPos)
-      .erase('end')
-      .write(str)
-    ;
-  };
-
-  downloadPercent(pct:number) {
-    return this.downloadBar.percent(pct)
-  }
-
-  appliedPercent(pct:number) {
-    return this.appliedBar.percent(pct)
-  }
-
-  end() {
-    this.multi.write('\nAll done.\n');
-    this.multi.destroy();
-  }
-}
-
-class LoggerWatcher implements Watcher {
-
-  private downPct = 0
-  private appliedPct = 0
-  private lastMsg = ""
-
-  constructor(private logger:any) {
-  }
-
-  showProgress() {
-    return this.logger.info('Downloaded %s%, Applied %s%', this.downPct, this.appliedPct)
-  }
-
-  writeStatus(str:string) {
-    if (str != this.lastMsg) {
-      this.lastMsg = str;
-      this.logger.info(str);
-    }
-  }
-
-  downloadPercent(pct:number) {
-    if (pct !== undefined) {
-      let changed = pct > this.downPct;
-      this.downPct = pct;
-      if (changed) this.showProgress();
-    }
-    return this.downPct;
-  }
-
-  appliedPercent(pct:number) {
-    if (pct !== undefined) {
-      let changed = pct > this.appliedPct;
-      this.appliedPct = pct;
-      if (changed) this.showProgress();
-    }
-    return this.appliedPct;
-  }
-
-  end() {
-  }
-
-}
-
-class P2PDownloader {
-
-  private PARALLEL_PER_CHUNK = 1;
-  private MAX_DELAY_PER_DOWNLOAD = 15000;
-  private NO_NODES_AVAILABLE = "No node available for download";
-  private TOO_LONG_TIME_DOWNLOAD:string
-  private nbBlocksToDownload:number
-  private numberOfChunksToDownload:number
-  private downloadSlots:number
-  private chunks:any
-  private processing:any
-  private handler:any
-  private resultsDeferers:any
-  private resultsData:Promise<BlockDTO[]>[]
-  private nodes:any = {}
-  private nbDownloadsTried = 0
-  private nbDownloading = 0
-  private lastAvgDelay:number
-  private aSlotWasAdded = false
-  private slots:number[] = [];
-  private downloads:any = {};
-  private startResolver:any
-  private downloadStarter:Promise<any>
-
-  constructor(
-    private currency:string,
-    private localNumber:number,
-    private to:number,
-    private toHash:string,
-    private peers:PeerDTO[],
-    private watcher:Watcher,
-    private logger:any,
-    private hashf:any,
-    private dal:FileDAL,
-    private slowOption:any) {
-
-    this.TOO_LONG_TIME_DOWNLOAD = "No answer after " + this.MAX_DELAY_PER_DOWNLOAD + "ms, will retry download later.";
-    this.nbBlocksToDownload = Math.max(0, to - localNumber);
-    this.numberOfChunksToDownload = Math.ceil(this.nbBlocksToDownload / CONST_BLOCKS_CHUNK);
-    this.chunks          = Array.from({ length: this.numberOfChunksToDownload }).map(() => null);
-    this.processing      = Array.from({ length: this.numberOfChunksToDownload }).map(() => false);
-    this.handler         = Array.from({ length: this.numberOfChunksToDownload }).map(() => null);
-    this.resultsDeferers = Array.from({ length: this.numberOfChunksToDownload }).map(() => null);
-    this.resultsData     = Array.from({ length: this.numberOfChunksToDownload }).map((unused, index) => new Promise((resolve, reject) => {
-      this.resultsDeferers[index] = { resolve, reject };
-    }));
-
-    // Create slots of download, in a ready stage
-    this.downloadSlots = slowOption ? 1 : Math.min(INITIAL_DOWNLOAD_SLOTS, peers.length);
-    this.lastAvgDelay = this.MAX_DELAY_PER_DOWNLOAD;
-
-    /**
-     * Triggers for starting the download.
-     */
-    this.downloadStarter = new Promise((resolve) => this.startResolver = resolve);
-
-    /**
-     * Download worker
-     * @type {*|Promise} When finished.
-     */
-    (async () => {
-      try {
-        await this.downloadStarter;
-        let doneCount = 0, resolvedCount = 0;
-        while (resolvedCount < this.chunks.length) {
-          doneCount = 0;
-          resolvedCount = 0;
-          // Add as much possible downloads as possible, and count the already done ones
-          for (let i = this.chunks.length - 1; i >= 0; i--) {
-            if (this.chunks[i] === null && !this.processing[i] && this.slots.indexOf(i) === -1 && this.slots.length < this.downloadSlots) {
-              this.slots.push(i);
-              this.processing[i] = true;
-              this.downloads[i] = makeQuerablePromise(this.downloadChunk(i)); // Starts a new download
-            } else if (this.downloads[i] && this.downloads[i].isFulfilled() && this.processing[i]) {
-              doneCount++;
-            }
-            // We count the number of perfectly downloaded & validated chunks
-            if (this.chunks[i]) {
-              resolvedCount++;
-            }
-          }
-          watcher.downloadPercent(Math.round(doneCount / this.numberOfChunksToDownload * 100));
-          let races = this.slots.map((i) => this.downloads[i]);
-          if (races.length) {
-            try {
-              await this.raceOrCancelIfTimeout(this.MAX_DELAY_PER_DOWNLOAD, races);
-            } catch (e) {
-              this.logger.warn(e);
-            }
-            for (let i = 0; i < this.slots.length; i++) {
-              // We must know the index of what resolved/rejected to free the slot
-              const doneIndex = this.slots.reduce((found:any, realIndex:number, index:number) => {
-                if (found !== null) return found;
-                if (this.downloads[realIndex].isFulfilled()) return index;
-                return null;
-              }, null);
-              if (doneIndex !== null) {
-                const realIndex = this.slots[doneIndex];
-                if (this.downloads[realIndex].isResolved()) {
-                  // IIFE to be safe about `realIndex`
-                  (async () => {
-                      const blocks = await this.downloads[realIndex];
-                      if (realIndex < this.chunks.length - 1) {
-                        // We must wait for NEXT blocks to be STRONGLY validated before going any further, otherwise we
-                        // could be on the wrong chain
-                        await this.getChunk(realIndex + 1);
-                      }
-                      const chainsWell = await this.chainsCorrectly(blocks, realIndex);
-                      if (chainsWell) {
-                        // Chunk is COMPLETE
-                        this.logger.warn("Chunk #%s is COMPLETE from %s", realIndex, [this.handler[realIndex].host, this.handler[realIndex].port].join(':'));
-                        this.chunks[realIndex] = blocks;
-                        this.resultsDeferers[realIndex].resolve(this.chunks[realIndex]);
-                      } else {
-                        this.logger.warn("Chunk #%s DOES NOT CHAIN CORRECTLY from %s", realIndex, [this.handler[realIndex].host, this.handler[realIndex].port].join(':'));
-                        // Penality on this node to avoid its usage
-                        if (this.handler[realIndex].resetFunction) {
-                          await this.handler[realIndex].resetFunction();
-                        }
-                        if (this.handler[realIndex].tta !== undefined) {
-                          this.handler[realIndex].tta += this.MAX_DELAY_PER_DOWNLOAD;
-                        }
-                        // Need a retry
-                        this.processing[realIndex] = false;
-                      }
-                  })()
-                } else {
-                  this.processing[realIndex] = false; // Need a retry
-                }
-                this.slots.splice(doneIndex, 1);
-              }
-            }
-          }
-          // Wait a bit
-          await new Promise((resolve, reject) => setTimeout(resolve, 10));
-        }
-      } catch (e) {
-        this.logger.error('Fatal error in the downloader:');
-        this.logger.error(e);
-      }
-    })()
-  }
-
-  /**
-   * Get a list of P2P nodes to use for download.
-   * If a node is not yet correctly initialized (we can test a node before considering it good for downloading), then
-   * this method would not return it.
-   */
-  private async getP2Pcandidates(): Promise<any[]> {
-    let promises = this.peers.reduce((chosens:any, other:any, index:number) => {
-      if (!this.nodes[index]) {
-        // Create the node
-        let p = PeerDTO.fromJSONObject(this.peers[index]);
-        this.nodes[index] = makeQuerablePromise((async () => {
-          // We wait for the download process to be triggered
-          // await downloadStarter;
-          // if (nodes[index - 1]) {
-          //   try { await nodes[index - 1]; } catch (e) {}
-          // }
-          const node:any = await connect(p)
-          // We initialize nodes with the near worth possible notation
-          node.tta = 1;
-          node.nbSuccess = 0;
-          return node;
-        })())
-        chosens.push(this.nodes[index]);
-      } else {
-        chosens.push(this.nodes[index]);
-      }
-      // Continue
-      return chosens;
-    }, []);
-    let candidates:any[] = await Promise.all(promises)
-    candidates.forEach((c:any) => {
-      c.tta = c.tta || 0; // By default we say a node is super slow to answer
-      c.ttas = c.ttas || []; // Memorize the answer delays
-    });
-    if (candidates.length === 0) {
-      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);
-    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);
-      // We reinitialize the nodes
-      this.nodes = {};
-      // And try it all again
-      return this.getP2Pcandidates();
-    }
-    const parallelMax = Math.min(this.PARALLEL_PER_CHUNK, withGoodDelays.length);
-    withGoodDelays = _.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);
-    return withGoodDelays;
-  }
-
-  /**
-   * Download a chunk of blocks using P2P network through BMA API.
-   * @param from The starting block to download
-   * @param count The number of blocks to download.
-   * @param chunkIndex The # of the chunk in local algorithm (logging purposes only)
-   */
-  private async p2pDownload(from:number, count:number, chunkIndex:number) {
-    let candidates = await this.getP2Pcandidates();
-    // Book the nodes
-    return await this.raceOrCancelIfTimeout(this.MAX_DELAY_PER_DOWNLOAD, candidates.map(async (node:any) => {
-      try {
-        const start = Date.now();
-        this.handler[chunkIndex] = node;
-        node.downloading = true;
-        this.nbDownloading++;
-        this.watcher.writeStatus('Getting chunk #' + chunkIndex + '/' + (this.numberOfChunksToDownload - 1) + ' from ' + from + ' to ' + (from + count - 1) + ' on peer ' + [node.host, node.port].join(':'));
-        let blocks = await node.getBlocks(count, from);
-        node.ttas.push(Date.now() - start);
-        // Only keep a flow of 5 ttas for the node
-        if (node.ttas.length > 5) node.ttas.shift();
-        // Average time to answer
-        node.tta = Math.round(node.ttas.reduce((sum:number, tta:number) => sum + tta, 0) / node.ttas.length);
-        this.watcher.writeStatus('GOT chunk #' + chunkIndex + '/' + (this.numberOfChunksToDownload - 1) + ' from ' + from + ' to ' + (from + count - 1) + ' on peer ' + [node.host, node.port].join(':'));
-        node.nbSuccess++;
-
-        // 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 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;
-            }, 0) / downloading.length;
-          // Opens or close downloading slots
-          if (!this.slowOption) {
-            // Check the impact of an added node (not first time)
-            if (!this.aSlotWasAdded) {
-              // We try to add a node
-              const newValue = Math.min(peers.length, this.downloadSlots + 1);
-              if (newValue !== this.downloadSlots) {
-                this.downloadSlots = newValue;
-                this.aSlotWasAdded = true;
-                this.logger.info('AUGMENTED DOWNLOAD SLOTS! Now has %s slots', this.downloadSlots);
-              }
-            } else {
-              this.aSlotWasAdded = false;
-              const decelerationPercent = currentAvgDelay / this.lastAvgDelay - 1;
-              const addedNodePercent = 1 / this.nbDownloading;
-              this.logger.info('Deceleration = %s (%s/%s), AddedNodePercent = %s', decelerationPercent, currentAvgDelay, this.lastAvgDelay, addedNodePercent);
-              if (decelerationPercent > addedNodePercent) {
-                this.downloadSlots = Math.max(1, this.downloadSlots - 1); // We reduce the number of slots, but we keep at least 1 slot
-                this.logger.info('REDUCED DOWNLOAD SLOT! Now has %s slots', this.downloadSlots);
-              }
-            }
-          }
-          this.lastAvgDelay = currentAvgDelay;
-        }
-
-        this.nbDownloadsTried++;
-        this.nbDownloading--;
-        node.downloading = false;
-
-        return blocks;
-      } catch (e) {
-        this.nbDownloading--;
-        node.downloading = false;
-        this.nbDownloadsTried++;
-        node.ttas.push(this.MAX_DELAY_PER_DOWNLOAD + 1); // No more ask on this node
-        // Average time to answer
-        node.tta = Math.round(node.ttas.reduce((sum:number, tta:number) => sum + tta, 0) / node.ttas.length);
-        throw e;
-      }
-    }))
-  }
-
-  /**
-   * Function for downloading a chunk by its number.
-   * @param index Number of the chunk.
-   */
-  private async downloadChunk(index:number): Promise<BlockDTO[]> {
-    // The algorithm to download a chunk
-    const from = this.localNumber + 1 + index * CONST_BLOCKS_CHUNK;
-    let count = CONST_BLOCKS_CHUNK;
-    if (index == this.numberOfChunksToDownload - 1) {
-      count = this.nbBlocksToDownload % CONST_BLOCKS_CHUNK || CONST_BLOCKS_CHUNK;
-    }
-    try {
-      const fileName = this.currency + "/chunk_" + index + "-" + CONST_BLOCKS_CHUNK + ".json";
-      if (this.localNumber <= 0 && (await this.dal.confDAL.coreFS.exists(fileName))) {
-        this.handler[index] = {
-          host: 'filesystem',
-          port: 'blockchain',
-          resetFunction: () => this.dal.confDAL.coreFS.remove(fileName)
-        };
-        return (await this.dal.confDAL.coreFS.readJSON(fileName)).blocks;
-      } else {
-        const chunk:any = await this.p2pDownload(from, count, index);
-        // Store the file to avoid re-downloading
-        if (this.localNumber <= 0 && chunk.length === CONST_BLOCKS_CHUNK) {
-          await this.dal.confDAL.coreFS.makeTree(this.currency);
-          await this.dal.confDAL.coreFS.writeJSON(fileName, { blocks: chunk });
-        }
-        return chunk;
-      }
-    } catch (e) {
-      this.logger.error(e);
-      return this.downloadChunk(index);
-    }
-  }
-
-  /**
-   * Utility function this starts a race between promises but cancels it if no answer is found before `timeout`
-   * @param timeout
-   * @param races
-   * @returns {Promise}
-   */
-  private raceOrCancelIfTimeout(timeout:number, races:any[]) {
-    return Promise.race([
-      // Process the race, but cancel it if we don't get an anwser quickly enough
-      new Promise((resolve, reject) => {
-        setTimeout(() => {
-          reject(this.TOO_LONG_TIME_DOWNLOAD);
-        }, timeout)
-      })
-    ].concat(races));
-  };
-
-  private async chainsCorrectly(blocks:BlockDTO[], index:number) {
-
-    if (!blocks.length) {
-      this.logger.error('No block was downloaded');
-      return false;
-    }
-
-    for (let i = blocks.length - 1; i > 0; i--) {
-      if (blocks[i].number !== blocks[i - 1].number + 1 || blocks[i].previousHash !== blocks[i - 1].hash) {
-        this.logger.error("Blocks do not chaing correctly", blocks[i].number);
-        return false;
-      }
-      if (blocks[i].version != blocks[i - 1].version && blocks[i].version != blocks[i - 1].version + 1) {
-        this.logger.error("Version cannot be downgraded", blocks[i].number);
-        return false;
-      }
-    }
-
-    // Check hashes
-    for (let i = 0; i < blocks.length; i++) {
-      // Note: the hash, in Duniter, is made only on the **signing part** of the block: InnerHash + Nonce
-      if (blocks[i].version >= 6) {
-        for (const tx of blocks[i].transactions) {
-          tx.version = CrawlerConstants.TRANSACTION_VERSION;
-        }
-      }
-      if (blocks[i].inner_hash !== hashf(rawer.getBlockInnerPart(blocks[i])).toUpperCase()) {
-        this.logger.error("Inner hash of block#%s from %s does not match", blocks[i].number);
-        return false;
-      }
-      if (blocks[i].hash !== hashf(rawer.getBlockInnerHashAndNonceWithSignature(blocks[i])).toUpperCase()) {
-        this.logger.error("Hash of block#%s from %s does not match", blocks[i].number);
-        return false;
-      }
-    }
-
-    const lastBlockOfChunk = blocks[blocks.length - 1];
-    if ((lastBlockOfChunk.number == this.to || blocks.length < CONST_BLOCKS_CHUNK) && lastBlockOfChunk.hash != this.toHash) {
-      // Top chunk
-      this.logger.error('Top block is not on the right chain');
-      return false;
-    } else {
-      // Chaining between downloads
-      const previousChunk = await this.getChunk(index + 1);
-      const blockN = blocks[blocks.length - 1]; // The block n
-      const blockNp1 = previousChunk[0]; // The block n + 1
-      if (blockN && blockNp1 && (blockN.number + 1 !== blockNp1.number || blockN.hash != blockNp1.previousHash)) {
-        this.logger.error('Chunk is not referenced by the upper one');
-        return false;
-      }
-    }
-    return true;
-  }
-
-  /**
-   * PUBLIC API
-   */
-
-  /***
-   * Triggers the downloading
-   */
-  start() {
-    return this.startResolver()
-  }
-
-  /***
-   * Promises a chunk to be downloaded and returned
-   * @param index The number of the chunk to download & return
-   */
-  getChunk(index:number) {
-    return this.resultsData[index] || Promise.resolve([])
-  }
 }
diff --git a/app/modules/crawler/lib/sync/AbstractSynchronizer.ts b/app/modules/crawler/lib/sync/AbstractSynchronizer.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4b9215f1307b4f317cc5526a2ade3f2b05a5e04c
--- /dev/null
+++ b/app/modules/crawler/lib/sync/AbstractSynchronizer.ts
@@ -0,0 +1,48 @@
+// 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 {BlockDTO} from "../../../../lib/dto/BlockDTO"
+import {ISyncDownloader} from "./ISyncDownloader"
+import {CommonConstants} from "../../../../lib/common-libs/constants"
+import {PeerDTO} from "../../../../lib/dto/PeerDTO"
+import {Watcher} from "./Watcher"
+import {FileDAL} from "../../../../lib/dal/fileDAL"
+import * as path from 'path'
+
+export abstract class AbstractSynchronizer {
+
+  constructor() {
+  }
+
+  abstract init(): Promise<void>
+  abstract initWithKnownLocalAndToAndCurrency(to: number, localNumber: number, currency: string): Promise<void>
+  abstract getCurrent(): Promise<BlockDTO|null>
+  abstract getBlock(number: number): Promise<BlockDTO|null>
+  abstract p2pDownloader(): ISyncDownloader
+  abstract fsDownloader(): ISyncDownloader
+  abstract syncPeers(fullSync:boolean, to?:number): Promise<void>
+  abstract syncSandbox(): Promise<void>
+  abstract getPeer(): PeerDTO
+  abstract setWatcher(watcher: Watcher): void
+  public abstract getCurrency(): string
+  public abstract getChunksPath(): string
+  public abstract get readDAL(): FileDAL
+
+  public getChunkRelativePath(i: number) {
+    return path.join(this.getCurrency(), this.getChunkName(i))
+  }
+
+  public getChunkName(i: number) {
+    return CommonConstants.CHUNK_PREFIX + i + "-" + CommonConstants.CONST_BLOCKS_CHUNK + ".json"
+  }
+}
diff --git a/app/modules/crawler/lib/sync/ChunkGetter.ts b/app/modules/crawler/lib/sync/ChunkGetter.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c6a41f8735baedaf490bd5840e3d23f128930b91
--- /dev/null
+++ b/app/modules/crawler/lib/sync/ChunkGetter.ts
@@ -0,0 +1,299 @@
+import {PromiseOfBlocksReading} from "./PromiseOfBlockReading"
+import {BlockDTO} from "../../../../lib/dto/BlockDTO"
+import {CrawlerConstants} from "../constants"
+import {hashf} from "../../../../lib/common"
+import {getBlockInnerHashAndNonceWithSignature, getBlockInnerPart} from "../../../../lib/common-libs/rawer"
+import {CommonConstants} from "../../../../lib/common-libs/constants"
+import {NewLogger} from "../../../../lib/logger"
+import {ISyncDownloader} from "./ISyncDownloader"
+import {DBBlock} from "../../../../lib/db/DBBlock"
+import {FileDAL} from "../../../../lib/dal/fileDAL"
+import {Watcher} from "./Watcher"
+import {cliprogram} from "../../../../lib/common-libs/programOptions"
+import {Querable, querablep} from "../../../../lib/common-libs/querable"
+import {AbstractSynchronizer} from "./AbstractSynchronizer"
+
+const logger = NewLogger()
+
+interface DownloadHandler {
+  downloader: ISyncDownloader
+}
+
+interface WaitingState extends DownloadHandler {
+  state: 'WAITING',
+  chunk?: Querable<BlockDTO[]>,
+}
+
+interface DownloadingState extends DownloadHandler {
+  state: 'DOWNLOADING',
+  chunk: Querable<BlockDTO[]>,
+}
+
+interface DownloadedState extends DownloadHandler {
+  state: 'DOWNLOADED',
+  chunk: Querable<BlockDTO[]>,
+}
+
+interface CompletedState extends DownloadHandler {
+  state: 'COMPLETED',
+  readBlocks: PromiseOfBlocksReading,
+}
+
+export class ChunkGetter {
+
+  private resultsDeferers:{ resolve: (data: PromiseOfBlocksReading) => void, reject: () => void }[]
+  private resultsData:Promise<PromiseOfBlocksReading>[]
+  private downloadHandlers:(WaitingState|DownloadingState|DownloadedState|CompletedState)[]
+  private fsDownloader: ISyncDownloader
+  private p2PDownloader: ISyncDownloader
+  private downloadedChunks = 0
+  private writtenChunks = 0
+  private numberOfChunksToDownload:number
+  private parallelDownloads = cliprogram.slow ? 1 : 5
+  private maxDownloadAdvance = 10 // 10 chunks can be downloaded even if 10th chunk above is not completed
+  private MAX_DOWNLOAD_TIMEOUT = 15000
+  private writeDAL: FileDAL
+
+  constructor(
+    private localNumber:number,
+    private to:number,
+    private toHash:string,
+    private syncStrategy: AbstractSynchronizer,
+    dal:FileDAL,
+    private nocautious:boolean,
+    private watcher:Watcher,
+  ) {
+    this.writeDAL = dal
+    const nbBlocksToDownload = Math.max(0, to - localNumber)
+    this.numberOfChunksToDownload = Math.ceil(nbBlocksToDownload / CommonConstants.CONST_BLOCKS_CHUNK)
+    this.p2PDownloader = syncStrategy.p2pDownloader()
+    this.fsDownloader = syncStrategy.fsDownloader()
+
+    this.resultsDeferers = Array.from({ length: this.numberOfChunksToDownload }).map(() => ({
+      resolve: () => { throw Error('resolve should not be called here') },
+      reject: () => { throw Error('reject should not be called here') },
+    }))
+    this.resultsData     = Array.from({ length: this.numberOfChunksToDownload }).map((unused, index) => new Promise(async (resolve, reject) => {
+      this.resultsDeferers[index] = { resolve, reject }
+    }))
+  }
+
+  /***
+   * Triggers the downloading, and parallelize it.
+   */
+  start() {
+
+    // Initializes the downloads queue
+    this.downloadHandlers = []
+    for (let i = 0; i < this.numberOfChunksToDownload; i++) {
+      this.downloadHandlers.push({
+        state: 'WAITING',
+        downloader: this.fsDownloader,
+      })
+    }
+
+    // Download loop
+    return (async () => {
+      let downloadFinished = false
+      while(!downloadFinished) {
+
+        let usedSlots = 0
+        let remainingDownloads = 0
+        let firstNonCompleted = 0
+
+        // Scan loop:
+        for (let i = this.numberOfChunksToDownload - 1; i >= 0; i--) {
+
+          let isTopChunk = i === this.resultsDeferers.length - 1
+          const handler = this.downloadHandlers[i]
+          if (handler.state !== 'COMPLETED' && firstNonCompleted === 0) {
+            firstNonCompleted = i
+          }
+          if (handler.state === 'WAITING') {
+            // We reached a new ready slot.
+            // If there is no more available slot, just stop the scan loop:
+            if (usedSlots === this.parallelDownloads || i < firstNonCompleted - this.maxDownloadAdvance) {
+              remainingDownloads++
+              break;
+            }
+            // Otherwise let's start a download
+            if (isTopChunk) {
+              // The top chunk is always downloaded via P2P
+              handler.downloader = this.p2PDownloader
+            }
+            handler.chunk = querablep(handler.downloader.getChunk(i))
+            ;(handler as any).state = 'DOWNLOADING'
+            remainingDownloads++
+            usedSlots++
+          }
+          else if (handler.state === 'DOWNLOADING') {
+            if (handler.chunk.isResolved()) {
+              (handler as any).state = 'DOWNLOADED'
+              i++ // We loop back on this handler
+            } else if (Date.now() - handler.chunk.startedOn > this.MAX_DOWNLOAD_TIMEOUT) {
+              (handler as any).chunk = [];
+              (handler as any).state = 'DOWNLOADED'
+              i++ // We loop back on this handler
+            } else {
+              remainingDownloads++
+              usedSlots++
+            }
+          }
+          else if (handler.state === 'DOWNLOADED') {
+            // Chaining test: we must wait for upper chunk to be completed (= downloaded + chained)
+            const chunk = await handler.chunk
+            if (chunk.length === 0 && handler.downloader === this.fsDownloader) {
+              // Retry with P2P
+              handler.downloader = this.p2PDownloader
+              ;(handler as any).state = 'WAITING'
+            }
+            if (isTopChunk || this.downloadHandlers[i + 1].state === 'COMPLETED') {
+              const fileName = this.syncStrategy.getChunkRelativePath(i)
+              let promiseOfUpperChunk: PromiseOfBlocksReading = async () => []
+              if (!isTopChunk && chunk.length) {
+                // We need to wait for upper chunk to be completed to be able to check blocks' correct chaining
+                promiseOfUpperChunk = await this.resultsData[i + 1]
+              }
+              const chainsWell = await chainsCorrectly(chunk, promiseOfUpperChunk, this.to, this.toHash)
+              if (!chainsWell) {
+                if (handler.downloader === this.p2PDownloader) {
+                  if (chunk.length === 0) {
+                    logger.error('No block was downloaded')
+                  }
+                  logger.warn("Chunk #%s is DOES NOT CHAIN CORRECTLY. Retrying.", i)
+                }
+                handler.downloader = this.p2PDownloader // If ever the first call does not chains well, we try using P2P
+                ;(handler as any).state = 'WAITING'
+                i++
+              } else {
+                logger.warn("Chunk #%s read from filesystem.", i)
+                let doWrite = handler.downloader !== this.fsDownloader
+                  || !(await this.writeDAL.confDAL.coreFS.exists(fileName))
+                if (doWrite) {
+                  // Store the file to avoid re-downloading
+                  if (this.localNumber <= 0 && chunk.length === CommonConstants.CONST_BLOCKS_CHUNK) {
+                    await this.writeDAL.confDAL.coreFS.makeTree(this.syncStrategy.getCurrency())
+                    const content = { blocks: chunk.map((b:any) => DBBlock.fromBlockDTO(b)) }
+                    await this.writeDAL.confDAL.coreFS.writeJSON(fileName, content)
+                  }
+                }
+              }
+
+              if (chainsWell) {
+
+                // Chunk is COMPLETE
+                logger.warn("Chunk #%s is COMPLETE", i)
+                ;(handler as any).state = 'COMPLETED'
+                if (!isTopChunk) {
+                  (handler as any).chunk = undefined
+                }
+                this.downloadedChunks++
+                this.watcher.downloadPercent(parseInt((this.downloadedChunks / this.numberOfChunksToDownload * 100).toFixed(0)))
+                // We pre-save blocks only for non-cautious sync
+                if (this.nocautious) {
+                  await this.writeDAL.blockchainArchiveDAL.archive(chunk.map(b => {
+                    const block = DBBlock.fromBlockDTO(b)
+                    block.fork = false
+                    return block
+                  }))
+                  this.writtenChunks++
+                  this.watcher.storagePercent(Math.round(this.writtenChunks / this.numberOfChunksToDownload * 100));
+                } else {
+                  this.watcher.storagePercent(parseInt((this.downloadedChunks / this.numberOfChunksToDownload * 100).toFixed(0)))
+                }
+
+                // Returns a promise of file content
+                this.resultsDeferers[i].resolve(async () => {
+                  if (isTopChunk) {
+                    return await handler.chunk // don't return directly "chunk" as it would prevent the GC to collect it
+                  }
+                  let content: { blocks: BlockDTO[] } = await this.syncStrategy.readDAL.confDAL.coreFS.readJSON(fileName)
+                  if (!content) {
+                    // Reading from classical DAL doesn't work, maybe we are using --readfilesystem option.
+                    content = await this.writeDAL.confDAL.coreFS.readJSON(fileName)
+                  }
+                  return content.blocks
+                })
+              }
+            } else {
+              remainingDownloads++
+            }
+          }
+        }
+
+        downloadFinished = remainingDownloads === 0
+
+        // Wait for a download to be finished
+        if (!downloadFinished) {
+          const downloadsToWait = (this.downloadHandlers.filter(h => h.state === 'DOWNLOADING') as DownloadingState[])
+            .map(h => h.chunk)
+          if (downloadsToWait.length) {
+            await Promise.race(downloadsToWait)
+          }
+        }
+      }
+    })()
+  }
+
+  async getChunk(i: number): Promise<PromiseOfBlocksReading> {
+    const reading = this.resultsData[i] || Promise.resolve(async (): Promise<BlockDTO[]> => [])
+    // We don't want blocks above `to`
+    return async () => {
+      const blocks = await (await reading)()
+      return blocks.filter(b => b.number <= this.to)
+    }
+  }
+}
+
+export async function chainsCorrectly(blocks:BlockDTO[], readNextChunk: PromiseOfBlocksReading, topNumber: number, topHash: string) {
+
+  if (!blocks.length) {
+    return false
+  }
+
+  for (let i = blocks.length - 1; i > 0; i--) {
+    if (blocks[i].number !== blocks[i - 1].number + 1 || blocks[i].previousHash !== blocks[i - 1].hash) {
+      logger.error("Blocks do not chaing correctly", blocks[i].number);
+      return false;
+    }
+    if (blocks[i].version != blocks[i - 1].version && blocks[i].version != blocks[i - 1].version + 1) {
+      logger.error("Version cannot be downgraded", blocks[i].number);
+      return false;
+    }
+  }
+
+  // Check hashes
+  for (let i = 0; i < blocks.length; i++) {
+    // Note: the hash, in Duniter, is made only on the **signing part** of the block: InnerHash + Nonce
+    if (blocks[i].version >= 6) {
+      for (const tx of blocks[i].transactions) {
+        tx.version = CrawlerConstants.TRANSACTION_VERSION;
+      }
+    }
+    if (blocks[i].inner_hash !== hashf(getBlockInnerPart(blocks[i])).toUpperCase()) {
+      logger.error("Inner hash of block#%s from %s does not match", blocks[i].number)
+      return false
+    }
+    if (blocks[i].hash !== hashf(getBlockInnerHashAndNonceWithSignature(blocks[i])).toUpperCase()) {
+      logger.error("Hash of block#%s from %s does not match", blocks[i].number)
+      return false
+    }
+  }
+
+  const lastBlockOfChunk = blocks[blocks.length - 1];
+  if ((lastBlockOfChunk.number === topNumber || blocks.length < CommonConstants.CONST_BLOCKS_CHUNK) && lastBlockOfChunk.hash != topHash) {
+    // Top chunk
+    logger.error('Top block is not on the right chain')
+    return false
+  } else {
+    // Chaining between downloads
+    const previousChunk = await readNextChunk()
+    const blockN = blocks[blocks.length - 1] // The block n
+    const blockNp1 = (await previousChunk)[0] // The block n + 1
+    if (blockN && blockNp1 && (blockN.number + 1 !== blockNp1.number || blockN.hash != blockNp1.previousHash)) {
+      logger.error('Chunk is not referenced by the upper one')
+      return false
+    }
+  }
+  return true
+}
diff --git a/app/modules/crawler/lib/sync/FsSyncDownloader.ts b/app/modules/crawler/lib/sync/FsSyncDownloader.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7078c6f88784be22295f3c31fd6d389736c06dfa
--- /dev/null
+++ b/app/modules/crawler/lib/sync/FsSyncDownloader.ts
@@ -0,0 +1,34 @@
+import {ISyncDownloader} from "./ISyncDownloader"
+import {BlockDTO} from "../../../../lib/dto/BlockDTO"
+import {FileSystem} from "../../../../lib/system/directory"
+import * as path from 'path'
+
+export class FsSyncDownloader implements ISyncDownloader {
+
+  private ls: Promise<string[]>
+
+  constructor(
+    private fs: FileSystem,
+    private basePath: string,
+    private getChunkName:(i: number) => string,
+    ) {
+    this.ls = this.fs.fsList(basePath)
+  }
+
+  async getChunk(i: number): Promise<BlockDTO[]> {
+    const files = await this.ls
+    const filepath = path.join(this.basePath, this.getChunkName(i))
+    const basename = path.basename(filepath)
+    let existsOnDAL = files.filter(f => f === basename).length === 1
+    if (!existsOnDAL) {
+      // We make another try in case the file was created after the initial `ls` test
+      existsOnDAL = await this.fs.fsExists(filepath)
+    }
+    if (existsOnDAL) {
+      const content: any = JSON.parse(await this.fs.fsReadFile(filepath))
+      // Returns a promise of file content
+      return content.blocks
+    }
+    return []
+  }
+}
diff --git a/app/modules/crawler/lib/sync/ISyncDownloader.ts b/app/modules/crawler/lib/sync/ISyncDownloader.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e66bdf108f9111d50ba591246a6917a4118f0a0c
--- /dev/null
+++ b/app/modules/crawler/lib/sync/ISyncDownloader.ts
@@ -0,0 +1,5 @@
+import {BlockDTO} from "../../../../lib/dto/BlockDTO"
+
+export interface ISyncDownloader {
+  getChunk(i: number): Promise<BlockDTO[]>
+}
diff --git a/app/modules/crawler/lib/sync/LocalPathSynchronizer.ts b/app/modules/crawler/lib/sync/LocalPathSynchronizer.ts
new file mode 100644
index 0000000000000000000000000000000000000000..db76e498e80935e3c76edc0f5c235feb2413f67d
--- /dev/null
+++ b/app/modules/crawler/lib/sync/LocalPathSynchronizer.ts
@@ -0,0 +1,114 @@
+// 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 {ISyncDownloader} from "./ISyncDownloader"
+import {BlockDTO} from "../../../../lib/dto/BlockDTO"
+import {PeerDTO} from "../../../../lib/dto/PeerDTO"
+import {Watcher} from "./Watcher"
+import {PeeringService} from "../../../../service/PeeringService"
+import {Server} from "../../../../../server"
+import {FileDAL} from "../../../../lib/dal/fileDAL"
+import {FsSyncDownloader} from "./FsSyncDownloader"
+import {AbstractSynchronizer} from "./AbstractSynchronizer"
+import {CommonConstants} from "../../../../lib/common-libs/constants"
+import {RealFS} from "../../../../lib/system/directory"
+
+export class LocalPathSynchronizer extends AbstractSynchronizer {
+
+  private theP2pDownloader: ISyncDownloader
+  private theFsDownloader: ISyncDownloader
+  private currency: string
+  private watcher: Watcher
+  private ls: Promise<string[]>
+
+  constructor(
+    private path: string,
+    private server:Server,
+  ) {
+    super()
+    const fs = RealFS()
+    this.ls = fs.fsList(path)
+    // We read from the real file system here, directly.
+    this.theFsDownloader = new FsSyncDownloader(fs, this.path, this.getChunkName.bind(this))
+    this.theP2pDownloader = new FsSyncDownloader(fs, this.path, this.getChunkName.bind(this))
+  }
+
+  get dal(): FileDAL {
+    return this.server.dal
+  }
+
+  get readDAL(): FileDAL {
+    return this.dal
+  }
+
+  get PeeringService(): PeeringService {
+    return this.server.PeeringService
+  }
+
+  getCurrency(): string {
+    return this.currency
+  }
+
+  getPeer(): PeerDTO {
+    return this as any
+  }
+
+  getChunksPath(): string {
+    return this.path
+  }
+
+  setWatcher(watcher: Watcher): void {
+    this.watcher = watcher
+  }
+
+  async init(): Promise<void> {
+    // TODO: check that path exists and that files seem consistent
+  }
+
+  async initWithKnownLocalAndToAndCurrency(to: number, localNumber: number, currency: string): Promise<void> {
+    this.currency = currency
+  }
+
+  p2pDownloader(): ISyncDownloader {
+    return this.theP2pDownloader
+  }
+
+  fsDownloader(): ISyncDownloader {
+    return this.theFsDownloader
+  }
+
+  async getCurrent(): Promise<BlockDTO|null> {
+    const chunkNumbers: number[] = (await this.ls).map(s => parseInt(s.replace(CommonConstants.CHUNK_PREFIX, '')))
+    const topChunk = chunkNumbers.reduce((number, max) => Math.max(number, max), -1)
+    if (topChunk === -1) {
+      return null
+    }
+    const chunk = await this.theFsDownloader.getChunk(topChunk)
+    return chunk[chunk.length - 1] // This is the top block of the top chunk = the current block
+  }
+
+  async getBlock(number: number): Promise<BlockDTO|null> {
+    const chunkNumber = parseInt(String(number / CommonConstants.CONST_BLOCKS_CHUNK))
+    const position = number % CommonConstants.CONST_BLOCKS_CHUNK
+    const chunk = await this.theFsDownloader.getChunk(chunkNumber)
+    return chunk[position]
+  }
+
+  async syncPeers(fullSync: boolean, to?: number): Promise<void> {
+    // Does nothing on LocalPathSynchronizer
+  }
+
+  async syncSandbox(): Promise<void> {
+    // Does nothing on LocalPathSynchronizer
+  }
+}
diff --git a/app/modules/crawler/lib/sync/P2PSyncDownloader.ts b/app/modules/crawler/lib/sync/P2PSyncDownloader.ts
new file mode 100644
index 0000000000000000000000000000000000000000..474973635c43248f72bdf8b3569f286d14250c4c
--- /dev/null
+++ b/app/modules/crawler/lib/sync/P2PSyncDownloader.ts
@@ -0,0 +1,211 @@
+import {JSONDBPeer} from "../../../../lib/db/DBPeer"
+import {PeerDTO} from "../../../../lib/dto/PeerDTO"
+import {connect} from "../connect"
+import {Underscore} from "../../../../lib/common-libs/underscore"
+import {BlockDTO} from "../../../../lib/dto/BlockDTO"
+import {Watcher} from "./Watcher"
+import {CommonConstants} from "../../../../lib/common-libs/constants"
+import {ISyncDownloader} from "./ISyncDownloader"
+import {cliprogram} from "../../../../lib/common-libs/programOptions"
+
+const makeQuerablePromise = require('querablep');
+
+export class P2PSyncDownloader implements ISyncDownloader {
+
+  private PARALLEL_PER_CHUNK = 1;
+  private MAX_DELAY_PER_DOWNLOAD = cliprogram.slow ? 15000 : 5000;
+  private WAIT_DELAY_WHEN_MAX_DOWNLOAD_IS_REACHED = 3000;
+  private NO_NODES_AVAILABLE = "No node available for download";
+  private TOO_LONG_TIME_DOWNLOAD:string
+  private nbBlocksToDownload:number
+  private numberOfChunksToDownload:number
+  private processing:any
+  private handler:any
+  private nodes:any = {}
+  private nbDownloadsTried = 0
+  private nbDownloading = 0
+  private lastAvgDelay:number
+  private downloads: { [chunk: number]: any } = {}
+
+  constructor(
+    private localNumber:number,
+    private to:number,
+    private peers:JSONDBPeer[],
+    private watcher:Watcher,
+    private logger:any,
+    ) {
+
+    this.TOO_LONG_TIME_DOWNLOAD = "No answer after " + this.MAX_DELAY_PER_DOWNLOAD + "ms, will retry download later.";
+    this.nbBlocksToDownload = Math.max(0, to - localNumber);
+    this.numberOfChunksToDownload = Math.ceil(this.nbBlocksToDownload / CommonConstants.CONST_BLOCKS_CHUNK);
+    this.processing      = Array.from({ length: this.numberOfChunksToDownload }).map(() => false);
+    this.handler         = Array.from({ length: this.numberOfChunksToDownload }).map(() => null);
+
+    // Create slots of download, in a ready stage
+    this.lastAvgDelay = this.MAX_DELAY_PER_DOWNLOAD;
+  }
+
+  /**
+   * Get a list of P2P nodes to use for download.
+   * If a node is not yet correctly initialized (we can test a node before considering it good for downloading), then
+   * this method would not return it.
+   */
+  private async getP2Pcandidates(): Promise<any[]> {
+    let promises = this.peers.reduce((chosens:any, other:any, index:number) => {
+      if (!this.nodes[index]) {
+        // Create the node
+        let p = PeerDTO.fromJSONObject(this.peers[index]);
+        this.nodes[index] = makeQuerablePromise((async () => {
+          // We wait for the download process to be triggered
+          // await downloadStarter;
+          // if (nodes[index - 1]) {
+          //   try { await nodes[index - 1]; } catch (e) {}
+          // }
+          const node:any = await connect(p)
+          // We initialize nodes with the near worth possible notation
+          node.tta = 1;
+          node.nbSuccess = 0;
+          if (node.host.match(/^(localhost|192|127)/)) {
+            node.tta = this.MAX_DELAY_PER_DOWNLOAD
+          }
+          return node;
+        })())
+        chosens.push(this.nodes[index]);
+      } else {
+        chosens.push(this.nodes[index]);
+      }
+      // Continue
+      return chosens;
+    }, []);
+    let candidates:any[] = await Promise.all(promises)
+    candidates.forEach((c:any) => {
+      c.tta = c.tta || 0; // By default we say a node is super slow to answer
+      c.ttas = c.ttas || []; // Memorize the answer delays
+    });
+    if (candidates.length === 0) {
+      throw this.NO_NODES_AVAILABLE;
+    }
+    // We remove the nodes impossible to reach (timeout)
+    let withGoodDelays = Underscore.filter(candidates, (c:any) => c.tta <= this.MAX_DELAY_PER_DOWNLOAD && !c.excluded && !c.downloading);
+    if (withGoodDelays.length === 0) {
+      await new Promise(res => setTimeout(res, this.WAIT_DELAY_WHEN_MAX_DOWNLOAD_IS_REACHED)) // We wait a bit before continuing the downloads
+      // We reinitialize the nodes
+      this.nodes = {};
+      // And try it all again
+      return this.getP2Pcandidates();
+    }
+    const parallelMax = Math.min(this.PARALLEL_PER_CHUNK, withGoodDelays.length);
+    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);
+    return withGoodDelays;
+  }
+
+  /**
+   * Download a chunk of blocks using P2P network through BMA API.
+   * @param from The starting block to download
+   * @param count The number of blocks to download.
+   * @param chunkIndex The # of the chunk in local algorithm (logging purposes only)
+   */
+  private async p2pDownload(from:number, count:number, chunkIndex:number) {
+    // if this chunk has already been downloaded before, we exclude its supplier node from the download list as it won't give correct answer now
+    const lastSupplier = this.downloads[chunkIndex]
+    if (lastSupplier) {
+      lastSupplier.excluded = true
+      this.logger.warn('Excluding node %s as it returns unchainable chunks', [lastSupplier.host, lastSupplier.port].join(':'))
+    }
+    let candidates = await this.getP2Pcandidates();
+    // Book the nodes
+    return await this.raceOrCancelIfTimeout(this.MAX_DELAY_PER_DOWNLOAD, candidates.map(async (node:any) => {
+      try {
+        const start = Date.now();
+        this.handler[chunkIndex] = node;
+        node.downloading = true;
+        this.nbDownloading++;
+        this.watcher.writeStatus('Getting chunck #' + chunkIndex + '/' + (this.numberOfChunksToDownload - 1) + ' from ' + from + ' to ' + (from + count - 1) + ' on peer ' + [node.host, node.port].join(':'));
+        let blocks = await node.getBlocks(count, from);
+        node.ttas.push(Date.now() - start);
+        // Only keep a flow of 5 ttas for the node
+        if (node.ttas.length > 5) node.ttas.shift();
+        // Average time to answer
+        node.tta = Math.round(node.ttas.reduce((sum:number, tta:number) => sum + tta, 0) / node.ttas.length);
+        this.watcher.writeStatus('GOT chunck #' + chunkIndex + '/' + (this.numberOfChunksToDownload - 1) + ' from ' + from + ' to ' + (from + count - 1) + ' on peer ' + [node.host, node.port].join(':'));
+        if (this.PARALLEL_PER_CHUNK === 1) {
+          // Only works if we have 1 concurrent peer per chunk
+          this.downloads[chunkIndex] = node
+        }
+        node.nbSuccess++;
+
+        const peers = await Promise.all(Underscore.values(this.nodes))
+        const downloading = Underscore.filter(peers, (p:any) => p.downloading && p.ttas.length);
+        this.lastAvgDelay = 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
+        }, 0) / downloading.length
+
+        this.nbDownloadsTried++;
+        this.nbDownloading--;
+        node.downloading = false;
+
+        return blocks;
+      } catch (e) {
+        this.nbDownloading--;
+        node.downloading = false;
+        this.nbDownloadsTried++;
+        node.ttas.push(this.MAX_DELAY_PER_DOWNLOAD + 1); // No more ask on this node
+        // Average time to answer
+        node.tta = Math.round(node.ttas.reduce((sum:number, tta:number) => sum + tta, 0) / node.ttas.length);
+        throw e;
+      }
+    }))
+  }
+
+  /**
+   * Function for downloading a chunk by its number.
+   * @param index Number of the chunk.
+   */
+  private async downloadChunk(index:number): Promise<BlockDTO[]> {
+    // The algorithm to download a chunk
+    const from = this.localNumber + 1 + index * CommonConstants.CONST_BLOCKS_CHUNK;
+    let count = CommonConstants.CONST_BLOCKS_CHUNK;
+    if (index == this.numberOfChunksToDownload - 1) {
+      count = this.nbBlocksToDownload % CommonConstants.CONST_BLOCKS_CHUNK || CommonConstants.CONST_BLOCKS_CHUNK;
+    }
+    try {
+      return await this.p2pDownload(from, count, index) as BlockDTO[]
+    } catch (e) {
+      this.logger.error(e);
+      return this.downloadChunk(index);
+    }
+  }
+
+  /**
+   * Utility function this starts a race between promises but cancels it if no answer is found before `timeout`
+   * @param timeout
+   * @param races
+   * @returns {Promise}
+   */
+  private raceOrCancelIfTimeout(timeout:number, races:any[]) {
+    return Promise.race([
+      // Process the race, but cancel it if we don't get an anwser quickly enough
+      new Promise((resolve, reject) => {
+        setTimeout(() => {
+          reject(this.TOO_LONG_TIME_DOWNLOAD);
+        }, timeout)
+      })
+    ].concat(races));
+  };
+
+  /**
+   * PUBLIC API
+   */
+
+  /***
+   * Promises a chunk to be downloaded and returned
+   * @param index The number of the chunk to download & return
+   */
+  getChunk(index:number): Promise<BlockDTO[]> {
+    return this.downloadChunk(index)
+  }
+}
diff --git a/app/modules/crawler/lib/sync/PromiseOfBlockReading.ts b/app/modules/crawler/lib/sync/PromiseOfBlockReading.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8b35249ada4daf2fad0b1660bfcb42cb1c463204
--- /dev/null
+++ b/app/modules/crawler/lib/sync/PromiseOfBlockReading.ts
@@ -0,0 +1,5 @@
+import {BlockDTO} from "../../../../lib/dto/BlockDTO"
+
+export interface PromiseOfBlocksReading {
+  (): Promise<BlockDTO[]>
+}
diff --git a/app/modules/crawler/lib/sync/RemoteSynchronizer.ts b/app/modules/crawler/lib/sync/RemoteSynchronizer.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8113ec42d4c6a0fcd9ca2ad123e9f0c22e7aaa68
--- /dev/null
+++ b/app/modules/crawler/lib/sync/RemoteSynchronizer.ts
@@ -0,0 +1,294 @@
+// 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 {ISyncDownloader} from "./ISyncDownloader"
+import {BlockDTO} from "../../../../lib/dto/BlockDTO"
+import {PeerDTO} from "../../../../lib/dto/PeerDTO"
+import {Contacter} from "../contacter"
+import {connect} from "../connect"
+import {NewLogger} from "../../../../lib/logger"
+import {CrawlerConstants} from "../constants"
+import {HttpMerkleOfPeers} from "../../../bma/lib/dtos"
+import {cliprogram} from "../../../../lib/common-libs/programOptions"
+import {Watcher} from "./Watcher"
+import {dos2unix} from "../../../../lib/common-libs/dos2unix"
+import {PeeringService} from "../../../../service/PeeringService"
+import {Server} from "../../../../../server"
+import {DBPeer, JSONDBPeer} from "../../../../lib/db/DBPeer"
+import {Underscore} from "../../../../lib/common-libs/underscore"
+import {FileDAL} from "../../../../lib/dal/fileDAL"
+import {P2PSyncDownloader} from "./P2PSyncDownloader"
+import {FsSyncDownloader} from "./FsSyncDownloader"
+import {AbstractSynchronizer} from "./AbstractSynchronizer"
+import {pullSandboxToLocalServer} from "../sandbox"
+import * as path from 'path'
+
+const logger = NewLogger()
+
+export class RemoteSynchronizer extends AbstractSynchronizer {
+
+  private node:Contacter
+  private peer:PeerDTO
+  private shuffledPeers: JSONDBPeer[]
+  private theP2pDownloader: ISyncDownloader
+  private theFsDownloader: ISyncDownloader
+  private to: number
+  private localNumber: number
+  private currency: string
+  private watcher: Watcher
+  private static contacterOptions = {
+    timeout: CrawlerConstants.SYNC_LONG_TIMEOUT
+  }
+
+  constructor(
+    private host: string,
+    private port: number,
+    private server:Server,
+    private noShufflePeers = false,
+    private otherDAL?:FileDAL,
+  ) {
+    super()
+  }
+
+  get dal(): FileDAL {
+    return this.server.dal
+  }
+
+  get readDAL(): FileDAL {
+    return this.otherDAL || this.dal
+  }
+
+  get PeeringService(): PeeringService {
+    return this.server.PeeringService
+  }
+
+  getCurrency(): string {
+    return this.currency
+  }
+
+  getPeer(): PeerDTO {
+    return this.node as any
+  }
+
+  setWatcher(watcher: Watcher): void {
+    this.watcher = watcher
+  }
+
+  getChunksPath(): string {
+    return this.getCurrency()
+  }
+
+  async init(): Promise<void> {
+    const peering = await Contacter.fetchPeer(this.host, this.port, RemoteSynchronizer.contacterOptions)
+    this.peer = PeerDTO.fromJSONObject(peering)
+    logger.info("Try with %s %s", this.peer.getURL(), this.peer.pubkey.substr(0, 6))
+    this.node = await connect(this.peer)
+    ;(this.node as any).pubkey = this.peer.pubkey
+    this.watcher.writeStatus('Connecting to ' + this.host + '...')
+  }
+
+  async initWithKnownLocalAndToAndCurrency(to: number, localNumber: number, currency: string): Promise<void> {
+    this.to = to
+    this.localNumber = localNumber
+    this.currency = currency
+    //=======
+    // Peers (just for P2P download)
+    //=======
+    let peers:(JSONDBPeer|null)[] = [];
+    if (!cliprogram.nopeers && (to - localNumber > 1000)) { // P2P download if more than 1000 blocs
+      this.watcher.writeStatus('Peers...');
+      const merkle = await this.dal.merkleForPeers();
+      const getPeers:(params:any) => Promise<HttpMerkleOfPeers> = this.node.getPeers.bind(this.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) => {
+          if(merkle.leaves().indexOf(leaf) == -1){
+            leavesToAdd.push(leaf);
+          }
+        });
+        peers = await Promise.all(leavesToAdd.map(async (leaf) => {
+          try {
+            const json3 = await getPeers({ "leaf": leaf });
+            const jsonEntry = json3.leaf.value;
+            const endpoint = jsonEntry.endpoints[0];
+            this.watcher.writeStatus('Peer ' + endpoint);
+            return jsonEntry;
+          } catch (e) {
+            logger.warn("Could not get peer of leaf %s, continue...", leaf);
+            return null;
+          }
+        }))
+      }
+      else {
+        this.watcher.writeStatus('Peers already known');
+      }
+    }
+
+    if (!peers.length) {
+      peers.push(DBPeer.fromPeerDTO(this.peer))
+    }
+    peers = peers.filter((p) => p);
+    this.shuffledPeers = (this.noShufflePeers ? peers : Underscore.shuffle(peers)).filter(p => !!(p)) as JSONDBPeer[]
+  }
+
+  p2pDownloader(): ISyncDownloader {
+    if (!this.theP2pDownloader) {
+      this.theP2pDownloader = new P2PSyncDownloader(this.localNumber, this.to, this.shuffledPeers, this.watcher, logger)
+    }
+    return this.theP2pDownloader
+  }
+
+  fsDownloader(): ISyncDownloader {
+    if (!this.theFsDownloader) {
+      this.theFsDownloader = new FsSyncDownloader(this.readDAL.fs, path.join(this.readDAL.rootPath, this.getChunksPath()), this.getChunkName.bind(this))
+    }
+    return this.theFsDownloader
+  }
+
+  getCurrent(): Promise<BlockDTO|null> {
+    return this.node.getCurrent()
+  }
+
+  getBlock(number: number): Promise<BlockDTO|null> {
+    return this.node.getBlock(number)
+  }
+
+  static async test(host: string, port: number): Promise<BlockDTO> {
+    const peering = await Contacter.fetchPeer(host, port, this.contacterOptions);
+    const node = await connect(PeerDTO.fromJSONObject(peering));
+    return node.getCurrent()
+  }
+
+  async syncPeers(fullSync: boolean, to?: number): Promise<void> {
+    if (!cliprogram.nopeers && fullSync) {
+
+      const peering = await Contacter.fetchPeer(this.host, this.port, RemoteSynchronizer.contacterOptions);
+
+      let peer = PeerDTO.fromJSONObject(peering);
+      logger.info("Try with %s %s", peer.getURL(), peer.pubkey.substr(0, 6));
+      let node:any = await connect(peer);
+      node.pubkey = peer.pubkey;
+      logger.info('Sync started.');
+
+      this.watcher.writeStatus('Peers...');
+      await this.syncPeer(node);
+      const merkle = await this.dal.merkleForPeers();
+      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) => {
+          if(merkle.leaves().indexOf(leaf) == -1){
+            leavesToAdd.push(leaf);
+          }
+        });
+        for (let i = 0; i < leavesToAdd.length; i++) {
+          try {
+            const leaf = leavesToAdd[i]
+            const json3 = await getPeers({ "leaf": leaf });
+            const jsonEntry = json3.leaf.value;
+            const sign = json3.leaf.value.signature;
+            const entry:any = {};
+            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);
+            this.watcher.peersPercent((i + 1) / leavesToAdd.length * 100)
+            await this.PeeringService.submitP(entry, false, to === undefined);
+          } catch (e) {
+            logger.warn(e && e.message || e)
+          }
+        }
+        this.watcher.peersPercent(100)
+      }
+      else {
+        this.watcher.writeStatus('Peers already known');
+      }
+    }
+  }
+
+  //============
+  // Peer
+  //============
+  private async syncPeer (node:any) {
+
+    // Global sync vars
+    const remotePeer = PeerDTO.fromJSONObject({});
+    const json = await node.getPeer();
+    remotePeer.version = json.version
+    remotePeer.currency = json.currency
+    remotePeer.pubkey = json.pub
+    remotePeer.endpoints = json.endpoints
+    remotePeer.blockstamp = json.block
+    remotePeer.signature = json.signature
+    const entry = remotePeer.getRawUnsigned();
+    const signature = dos2unix(remotePeer.signature);
+    // Parameters
+    if(!(entry && signature)){
+      throw 'Requires a peering entry + signature';
+    }
+
+    let remoteJsonPeer:any = json
+    remoteJsonPeer.pubkey = json.pubkey;
+    let signatureOK = this.PeeringService.checkPeerSignature(remoteJsonPeer);
+    if (!signatureOK) {
+      this.watcher.writeStatus('Wrong signature for peer #' + remoteJsonPeer.pubkey);
+    }
+    try {
+      await this.PeeringService.submitP(remoteJsonPeer);
+    } catch (err) {
+      if (err.indexOf !== undefined && err.indexOf(CrawlerConstants.ERRORS.NEWER_PEER_DOCUMENT_AVAILABLE.uerr.message) !== -1 && err != CrawlerConstants.ERROR.PEER.UNKNOWN_REFERENCE_BLOCK) {
+        throw err;
+      }
+    }
+  }
+
+  async syncSandbox(): Promise<void> {
+    this.watcher.writeStatus('Synchronizing the sandboxes...');
+    await pullSandboxToLocalServer(this.currency, this.node, this.server, this.server.logger, this.watcher, 1, false)
+  }
+}
+
+class NodesMerkle {
+
+  private depth:number
+  private nodesCount:number
+  private leavesCount:number
+  private merkleRoot:string
+
+  constructor(json:any) {
+    this.depth = json.depth
+    this.nodesCount = json.nodesCount
+    this.leavesCount = json.leavesCount
+    this.merkleRoot = json.root;
+  }
+
+  // var i = 0;
+  // this.levels = [];
+  // while(json && json.levels[i]){
+  //   this.levels.push(json.levels[i]);
+  //   i++;
+  // }
+
+  root() {
+    return this.merkleRoot
+  }
+}
diff --git a/app/modules/crawler/lib/sync/Watcher.ts b/app/modules/crawler/lib/sync/Watcher.ts
new file mode 100644
index 0000000000000000000000000000000000000000..de7a27db35a5d0226e70ac81e24b71b05d051b7a
--- /dev/null
+++ b/app/modules/crawler/lib/sync/Watcher.ts
@@ -0,0 +1,224 @@
+import * as events from "events"
+import {cliprogram} from "../../../../lib/common-libs/programOptions"
+
+const multimeter   = require('multimeter')
+
+export interface Watcher {
+  writeStatus(str: string): void
+  downloadPercent(pct?: number): number
+  storagePercent(pct?: number): number
+  appliedPercent(pct?: number): number
+  sbxPercent(pct?: number): number
+  peersPercent(pct?: number): number
+  end(): void
+}
+
+export type EventName = 'downloadChange'|'storageChange'|'appliedChange'|'sbxChange'|'peersChange'
+
+export class EventWatcher extends events.EventEmitter implements Watcher {
+
+  constructor(private innerWatcher:Watcher) {
+    super()
+  }
+
+  writeStatus(str: string): void {
+    this.innerWatcher.writeStatus(str)
+  }
+
+  downloadPercent(pct?: number): number {
+    return this.change('downloadChange', (pct) => this.innerWatcher.downloadPercent(pct), pct)
+  }
+
+  storagePercent(pct?: number): number {
+    return this.change('storageChange', (pct) => this.innerWatcher.storagePercent(pct), pct)
+  }
+
+  appliedPercent(pct?: number): number {
+    return this.change('appliedChange', (pct) => this.innerWatcher.appliedPercent(pct), pct)
+  }
+
+  sbxPercent(pct?: number): number {
+    return this.change('sbxChange', (pct) => this.innerWatcher.sbxPercent(pct), pct)
+  }
+
+  peersPercent(pct?: number): number {
+    return this.change('peersChange', (pct) => this.innerWatcher.peersPercent(pct), pct)
+  }
+
+  change(changeName: EventName, method: (pct?: number) => number, pct?: number) {
+    if (pct !== undefined && method() < pct) {
+      this.emit(changeName, pct || 0)
+    }
+    return method(pct)
+  }
+
+  end(): void {
+    this.innerWatcher.end()
+  }
+
+  onEvent(e: EventName, cb: (pct: number) => void) {
+    this.on(e, cb)
+  }
+}
+
+export class MultimeterWatcher implements Watcher {
+
+  private xPos:number
+  private yPos:number
+  private multi:any
+  private charm:any
+  private appliedBar:any
+  private savedBar:any
+  private downloadBar:any
+  private sbxBar:any
+  private peersBar:any
+  private writtens:string[] = []
+
+  constructor() {
+    this.multi = multimeter(process);
+    this.charm = this.multi.charm;
+    this.charm.on('^C', process.exit);
+    this.charm.reset();
+
+    this.multi.write('Progress:\n\n');
+
+    let line = 3
+    this.downloadBar = this.createBar('Download', line++)
+    this.savedBar    = this.createBar('Storage',  line++)
+    this.appliedBar  = this.createBar('Apply',    line++)
+    if (!cliprogram.nosbx) {
+      this.sbxBar    = this.createBar('Sandbox',  line++)
+    }
+    if (!cliprogram.nopeers) {
+      this.peersBar  = this.createBar('Peers',    line++)
+    }
+
+    this.multi.write('\nStatus: ');
+
+    this.charm.position( (x:number, y:number) => {
+      this.xPos = x;
+      this.yPos = y;
+    });
+
+    this.writtens = [];
+
+    this.downloadBar.percent(0);
+    this.savedBar.percent(0);
+    this.appliedBar.percent(0);
+    if (!cliprogram.nosbx) {
+      this.sbxBar.percent(0);
+    }
+    if (!cliprogram.nopeers) {
+      this.peersBar.percent(0);
+    }
+  }
+
+  writeStatus(str:string) {
+    this.writtens.push(str);
+    this.charm
+      .position(this.xPos, this.yPos)
+      .erase('end')
+      .write(str)
+    ;
+  };
+
+  downloadPercent(pct:number) {
+    return this.downloadBar.percent(pct)
+  }
+
+  storagePercent(pct:number) {
+    return this.savedBar.percent(pct)
+  }
+
+  appliedPercent(pct:number) {
+    return this.appliedBar.percent(pct)
+  }
+
+  sbxPercent(pct:number) {
+    if (!cliprogram.nosbx) {
+      return this.sbxBar.percent(pct)
+    }
+    return 0
+  }
+
+  peersPercent(pct:number) {
+    if (!cliprogram.nopeers) {
+      return this.peersBar.percent(pct)
+    }
+    return 0
+  }
+
+  end() {
+    this.multi.write('\nAll done.\n');
+    this.multi.destroy();
+  }
+
+  private createBar(title: string, line: number) {
+    const header = (title + ':').padEnd(14, ' ') + '\n'
+    this.multi.write(header)
+    return this.multi(header.length, line, {
+      width : 20,
+      solid : {
+        text : '|',
+        foreground : 'white',
+        background : 'blue'
+      },
+      empty : { text : ' ' }
+    })
+  }
+}
+
+export class LoggerWatcher implements Watcher {
+
+  private downPct = 0
+  private savedPct = 0
+  private appliedPct = 0
+  private lastMsg = ""
+
+  constructor(private logger:any) {
+  }
+
+  showProgress() {
+    return this.logger.info('Downloaded %s%, Blockchained %s%, Applied %s%', this.downPct, this.savedPct, this.appliedPct)
+  }
+
+  writeStatus(str:string) {
+    if (str != this.lastMsg) {
+      this.lastMsg = str;
+      this.logger.info(str);
+    }
+  }
+
+  downloadPercent(pct:number) {
+    return this.change('downPct', pct)
+  }
+
+  storagePercent(pct:number) {
+    return this.change('savedPct', pct)
+  }
+
+  appliedPercent(pct:number) {
+    return this.change('appliedPct', pct)
+  }
+
+  sbxPercent(pct:number) {
+    return 0
+  }
+
+  peersPercent(pct:number) {
+    return 0
+  }
+
+  change(prop: 'downPct'|'savedPct'|'appliedPct', pct:number) {
+    if (pct !== undefined) {
+      let changed = pct > this[prop]
+      this[prop] = pct
+      if (changed) this.showProgress()
+    }
+    return this[prop]
+  }
+
+  end() {
+  }
+
+}
diff --git a/app/modules/daemon.ts b/app/modules/daemon.ts
index 628107e6914f112f899d06e579b04861289156f2..9fbff1423b4dec5f7cf07837b41b026a0ea39cc8 100644
--- a/app/modules/daemon.ts
+++ b/app/modules/daemon.ts
@@ -13,20 +13,17 @@
 
 import {ConfDTO} from "../lib/dto/ConfDTO"
 import {Server} from "../../server"
+import {Directory, RealFS} from "../lib/system/directory"
 
-"use strict";
-
-const qfs       = require('q-io/fs');
-const directory = require('../lib/system/directory');
 const constants = require('../lib/constants');
-const path      = require('path');
 const Tail      = require("tail").Tail
 
 module.exports = {
   duniter: {
 
     cliOptions: [
-      { value: '--loglevel <level>', desc: 'Logs level, either [error,warning,info,debug,trace]. default to `info`.' }
+      { value: '--loglevel <level>', desc: 'Logs level, either [error,warning,info,debug,trace]. default to `info`.' },
+      { value: '--sql-traces', desc: 'Will log every SQL query that is executed. Requires --loglevel \'trace\'.' }
     ],
 
     service: {
@@ -95,7 +92,7 @@ module.exports = {
       desc: 'Follow duniter logs.',
       logs: false,
       onConfiguredExecute: async (server:Server, conf:ConfDTO, program:any, params:any) => {
-        printTailAndWatchFile(directory.INSTANCE_HOMELOG_FILE, constants.NB_INITIAL_LINES_TO_SHOW)
+        printTailAndWatchFile(Directory.INSTANCE_HOMELOG_FILE, constants.NB_INITIAL_LINES_TO_SHOW)
         // Never ending command
         return new Promise(res => null)
       }
@@ -149,8 +146,9 @@ function stopDaemon(daemon:any) {
 }
 
 async function printTailAndWatchFile(file:any, tailSize:number) {
-    if (await qfs.exists(file)) {
-      const content = await qfs.read(file)
+    const fs = RealFS()
+    if (await fs.fsExists(file)) {
+      const content = await fs.fsReadFile(file)
       const lines = content.split('\n')
       const from = Math.max(0, lines.length - tailSize)
       const lastLines = lines.slice(from).join('\n')
diff --git a/app/modules/dump.ts b/app/modules/dump.ts
new file mode 100644
index 0000000000000000000000000000000000000000..094e35a74651ae6905b1f230148523dd2e070066
--- /dev/null
+++ b/app/modules/dump.ts
@@ -0,0 +1,203 @@
+// 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 {ConfDTO} from "../lib/dto/ConfDTO"
+import {Server} from "../../server"
+import {moment} from "../lib/common-libs/moment"
+import {DBBlock} from "../lib/db/DBBlock"
+import {SindexEntry} from "../lib/indexer"
+import {BlockDTO} from "../lib/dto/BlockDTO"
+
+const Table = require('cli-table')
+
+module.exports = {
+  duniter: {
+    cli: [{
+      name: 'dump [what] [name] [cond]',
+      desc: 'Dumps data of the blockchain.',
+      logs: false,
+      preventIfRunning: true,
+
+      onDatabaseExecute: async (server:Server, conf:ConfDTO, program:any, params:any) => {
+        const what: string = params[0] || ''
+        const name: string = params[1] || ''
+        const cond: string = params[2] || ''
+        switch (what) {
+
+          case 'current':
+            await dumpCurrent(server)
+            break
+
+          case 'table':
+            await dumpTable(server, name, cond)
+            break
+
+          case 'history':
+            await dumpHistory(server, name)
+            break
+
+          default:
+            console.error(`Unknown dump ${what}`)
+            break
+        }
+        // Save DB
+        await server.disconnect();
+      }
+    }]
+  }
+}
+
+async function dumpCurrent(server: Server) {
+  const current = await server.dal.getCurrentBlockOrNull()
+  if (!current) {
+    console.log('')
+  }
+  else {
+    console.log(BlockDTO.fromJSONObject(current).getRawSigned())
+  }
+}
+
+async function dumpTable(server: Server, name: string, condition?: string) {
+  const criterion: any = {}
+  const filters = condition && condition.split(',') || []
+  for (const f of filters) {
+    const k = f.split('=')[0]
+    const v = f.split('=')[1]
+    if (v === 'true' || v === 'false') {
+      criterion[k] = v === 'true' ? true : 0
+    } else if (v === 'NULL') {
+      criterion[k] = null
+    } else if (v.match(/^\d+$/)) {
+      criterion[k] = parseInt(v)
+    } else {
+      criterion[k] = v
+    }
+  }
+  let rows: any[]
+  switch (name) {
+    case 'i_index':
+      rows = await server.dal.iindexDAL.findRawWithOrder(criterion, [['writtenOn', false], ['wotb_id', false]])
+      dump(rows, ['op','uid','pub','hash','sig','created_on','written_on','member','wasMember','kick','wotb_id'])
+      break
+    case 'm_index':
+      rows = await server.dal.mindexDAL.findRawWithOrder(criterion, [['writtenOn', false], ['pub', false]])
+      dump(rows, ['op','pub','created_on','written_on','expires_on','expired_on','revokes_on','revoked_on','leaving','revocation','chainable_on'])
+      break
+    case 'c_index':
+      rows = await server.dal.cindexDAL.findRawWithOrder(criterion, [['writtenOn', false], ['issuer', false], ['receiver', false]])
+      dump(rows, ['op','issuer','receiver','created_on','written_on','sig','expires_on','expired_on','chainable_on','from_wid','to_wid'])
+      break
+    case 's_index':
+      const rowsTX = await server.dal.sindexDAL.findRawWithOrder(criterion, [['writtenOn', false], ['identifier', false], ['pos', false]])
+      const rowsUD = await server.dal.dividendDAL.findForDump(criterion)
+      rows = rowsTX.concat(rowsUD)
+      sortSindex(rows)
+      dump(rows, ['op','tx','identifier','pos','created_on','amount','base','locktime','consumed','conditions', 'writtenOn'])
+      break
+    default:
+      console.error(`Unknown dump table ${name}`)
+      break
+  }
+}
+
+function dump(rows: any[], columns: string[]) {
+  // Table columns
+  const t = new Table({
+    head: columns
+  });
+  for (const row of rows) {
+    t.push(columns.map((c) => {
+      if (row[c] === null) {
+        return "NULL"
+      }
+      else if (row[c] === undefined) {
+        return 'NULL'
+      }
+      else if (typeof row[c] === 'boolean') {
+        return row[c] ? 1 : 0
+      }
+      return row[c]
+    }));
+  }
+  try {
+    const dumped = t.toString()
+    console.log(dumped)
+  } catch (e) {
+    console.error(e)
+  }
+}
+
+async function dumpHistory(server: Server, pub: string) {
+  const irows = await server.dal.iindexDAL.findRawWithOrder({ pub }, [['writtenOn', false]])
+  const mrows = await server.dal.mindexDAL.findRawWithOrder({ pub }, [['writtenOn', false]])
+  console.log('----- IDENTITY -----')
+  for (const e of irows) {
+    const date = await getDateFor(server, e.written_on)
+    if (e.uid) {
+      console.log('%s: new identity %s (created on %s)', date, e.uid, await getDateFor(server, e.created_on as string))
+    } else if (e.member) {
+      console.log('%s: comeback', date)
+    } else if (e.kick) {
+      // console.log('%s: being kicked... (either)', date)
+    } else if (e.member === false) {
+      console.log('%s: excluded', date)
+    } else {
+      console.log('Non displayable IINDEX entry')
+    }
+  }
+  console.log('----- MEMBERSHIP -----')
+  for (const e of mrows) {
+    const date = await getDateFor(server, e.written_on)
+    if (e.chainable_on) {
+      console.log('%s: join/renew', date)
+    } else if (e.expired_on) {
+      console.log('%s: expired', date)
+    } else if (e.revoked_on) {
+      console.log('%s: revoked', date)
+    } else {
+      console.log('Non displayable MINDEX entry')
+    }
+  }
+}
+
+async function getDateFor(server: Server, blockstamp: string) {
+  const b = (await server.dal.getAbsoluteBlockByBlockstamp(blockstamp)) as DBBlock
+  const s = "         " + b.number
+  const bnumberPadded = s.substr(s.length - 6)
+  return formatTimestamp(b.medianTime) + ' (#' + bnumberPadded + ')'
+}
+
+function formatTimestamp(ts: number) {
+  return moment(ts * 1000).format('YYYY-MM-DD hh:mm:ss')
+}
+
+function sortSindex(rows: SindexEntry[]) {
+  // We sort by writtenOn, identifier, pos
+  rows.sort((a, b) => {
+    if (a.writtenOn === b.writtenOn) {
+      if (a.identifier === b.identifier) {
+        if (a.pos === b.pos) {
+          return a.op === 'CREATE' && b.op === 'UPDATE' ? -1 : (a.op === 'UPDATE' && b.op === 'CREATE' ? 1 : 0)
+        } else {
+          return a.pos < b.pos ? -1 : 1
+        }
+      }
+      else {
+        return a.identifier < b.identifier ? -1 : 1
+      }
+    }
+    else {
+      return a.writtenOn < b.writtenOn ? -1 : 1
+    }
+  })
+}
\ No newline at end of file
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 6bf5ceef05f3db500be5391a32b155790374dbce..a33a84d4ecdc48dcdc06f08ea1dee15689b0475d 100644
--- a/app/modules/prover/index.ts
+++ b/app/modules/prover/index.ts
@@ -21,6 +21,7 @@ import {parsers} from "../../lib/common-libs/parsers/index"
 import {PeerDTO} from "../../lib/dto/PeerDTO"
 import {Server} from "../../../server"
 import {BlockDTO} from "../../lib/dto/BlockDTO"
+import {DBIdentity} from "../../lib/dal/sqliteDAL/IdentityDAL"
 
 const async = require('async');
 
@@ -68,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);
@@ -109,7 +110,7 @@ export const ProverDependency = {
       onDatabaseExecute: async (server:Server, conf:ConfDTO, program:any, params:any) => {
         const difficulty = params[0]
         const generator = new BlockGeneratorWhichProves(server, null);
-        let toDelete, catched = true;
+        let toDelete:DBIdentity[] = [], catched = true;
         do {
           try {
             await generateAndSend(program, difficulty, server, () => () => generator.nextBlock())
diff --git a/app/modules/prover/lib/PowWorker.ts b/app/modules/prover/lib/PowWorker.ts
index 5d74ba256bf1a6b74ddf4c9fc4dcd5a58f60bbbc..4c6df8ce83143d23cafb5e64c2b8b822d32e246a 100644
--- a/app/modules/prover/lib/PowWorker.ts
+++ b/app/modules/prover/lib/PowWorker.ts
@@ -11,7 +11,7 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-import {Querable} from "./permanentProver"
+import {Querable} from "../../../lib/common-libs/querable"
 
 const querablep = require('querablep')
 
diff --git a/app/modules/prover/lib/blockGenerator.ts b/app/modules/prover/lib/blockGenerator.ts
index 0608a1b0291cf4a55bfdd239770aa9d9e374e265..f5520d68f47ee71872c2fd0d811eb78c90edaf71 100644
--- a/app/modules/prover/lib/blockGenerator.ts
+++ b/app/modules/prover/lib/blockGenerator.ts
@@ -11,15 +11,13 @@
 // 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 * as moment from "moment"
 import {Server} from "../../../../server"
 import {BlockchainContext} from "../../../lib/computation/BlockchainContext"
 import {TransactionDTO} from "../../../lib/dto/TransactionDTO"
 import {GLOBAL_RULES_HELPERS} from "../../../lib/rules/global_rules"
 import {LOCAL_RULES_HELPERS} from "../../../lib/rules/local_rules"
 import {Indexer} from "../../../lib/indexer"
-import {FileDAL} from "../../../lib/dal/fileDAL"
 import {DBBlock} from "../../../lib/db/DBBlock"
 import {verify} from "../../../lib/common-libs/crypto/keyring"
 import {rawer} from "../../../lib/common-libs/index"
@@ -29,31 +27,64 @@ import {IdentityDTO} from "../../../lib/dto/IdentityDTO"
 import {CertificationDTO} from "../../../lib/dto/CertificationDTO"
 import {MembershipDTO} from "../../../lib/dto/MembershipDTO"
 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
 
+export interface PreJoin {
+  identity: {
+    pubkey: string
+    uid: string
+    buid: string
+    sig: string
+    member: boolean
+    wasMember: boolean
+    revoked: boolean
+  }
+  key: null
+  idHash: string
+  certs: DBCert[]
+  ms: any
+}
+
+interface LeaveData {
+  identity: {
+    member: boolean
+  } | null
+  ms: any
+  key: any
+  idHash: string
+}
+
 export class BlockGenerator {
 
-  conf:ConfDTO
-  dal:any
   mainContext:BlockchainContext
   selfPubkey:string
   logger:any
 
   constructor(private server:Server) {
-    this.conf = server.conf;
-    this.dal = server.dal;
     this.mainContext = server.BlockchainService.getContext();
     this.selfPubkey = (this.conf.pair && this.conf.pair.pub) || ''
     this.logger = server.logger;
   }
 
+  get conf(): ConfDTO {
+    return this.server.conf
+  }
+
+  get dal(): FileDAL {
+    return this.server.dal
+  }
+
   nextBlock(manualValues:any = {}, simulationValues:any = {}) {
-    return this.generateNextBlock(new NextBlockGenerator(this.mainContext, this.conf, this.dal, this.logger), manualValues, simulationValues)
+    return this.generateNextBlock(new NextBlockGenerator(this.mainContext, this.server, this.logger), manualValues, simulationValues)
   }
 
   async manualRoot() {
@@ -77,47 +108,31 @@ export class BlockGenerator {
     const exclusions = await this.dal.getToBeKickedPubkeys();
     const wereExcludeds = await this.dal.getRevokedPubkeys();
     const newCertsFromWoT = await generator.findNewCertsFromWoT(current);
-    const newcomersLeavers = await this.findNewcomersAndLeavers(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 joinData = newcomersLeavers[2];
-    const leaveData = newcomersLeavers[3];
-    const newCertsFromNewcomers = newcomersLeavers[4];
-    const certifiersOfNewcomers = _.uniq(_.keys(joinData).reduce((theCertifiers:any, newcomer:string) => {
-      return theCertifiers.concat(_.pluck(joinData[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;
       });
     });
-    _(newCertsFromNewcomers).keys().forEach((certified:string) => {
-      newCertsFromWoT[certified] = (newCertsFromWoT[certified] || []).concat(newCertsFromNewcomers[certified]);
-    });
-    // Revocations
     // Create the block
-    return this.createBlock(current, joinData, leaveData, newCertsFromWoT, revocations, exclusions, wereExcludeds, transactions, manualValues);
-  }
-
-  private async findNewcomersAndLeavers(current:DBBlock, filteringFunc: (joinData: { [pub:string]: any }) => Promise<{ [pub:string]: any }>) {
-    const newcomers = await this.findNewcomers(current, filteringFunc);
-    const leavers = await this.findLeavers(current);
-
-    const cur = newcomers.current;
-    const newWoTMembers = newcomers.newWotMembers;
-    const finalJoinData = newcomers.finalJoinData;
-    const updates = newcomers.updates;
-
-    return [cur, newWoTMembers, finalJoinData, leavers, updates];
+    return this.createBlock(current, newcomers, leavers, newCertsFromWoT, revocations, exclusions, wereExcludeds, transactions, manualValues);
   }
 
-  private async findTransactions(current:DBBlock, options:{ dontCareAboutChaining?:boolean }) {
+  private async findTransactions(current:DBBlock|null, options:{ dontCareAboutChaining?:boolean }) {
+    if (!current) {
+      return []
+    }
     const versionMin = current ? Math.min(CommonConstants.LAST_VERSION_FOR_TX, current.version) : CommonConstants.DOCUMENTS_VERSION;
     const txs = await this.dal.getTransactionsPending(versionMin);
     const transactions = [];
@@ -129,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);
@@ -149,56 +164,55 @@ export class BlockGenerator {
     return transactions;
   }
 
-  private async findLeavers(current:DBBlock) {
-    const leaveData: { [pub:string]: any } = {};
-    const memberships = await this.dal.findLeavers(current && current.medianTime);
+  private async findLeavers(current:DBBlock|null) {
+    const leaveData: { [pub:string]: { identity: { member:boolean }|null, ms: any, key: any, idHash: string } } = {};
+    const memberships = await this.dal.findLeavers((current && current.medianTime) || 0)
     const leavers:string[] = [];
     memberships.forEach((ms:any) => leavers.push(ms.issuer));
     for (const ms of memberships) {
-      const leave = { identity: null, ms: ms, key: null, idHash: '' };
+      const leave: { identity: { member:boolean }|null, ms: any, key: any, idHash: string } = { identity: null, ms: ms, key: null, idHash: '' };
       leave.idHash = (hashf(ms.userid + ms.certts + ms.issuer) + "").toUpperCase();
       let block;
       if (current) {
-        block = await this.dal.getBlock(ms.number);
+        block = await this.dal.getAbsoluteValidBlockInForkWindowByBlockstamp(ms.block)
       }
       else {
         block = {};
       }
-      const identity = await this.dal.getIdentityByHashOrNull(leave.idHash);
+      const identity = await this.dal.getGlobalIdentityByHashForIsMember(leave.idHash)
       const currentMembership = await this.dal.mindexDAL.getReducedMS(ms.issuer);
       const currentMSN = currentMembership ? parseInt(currentMembership.created_on) : -1;
       if (identity && block && currentMSN < leave.ms.number && identity.member) {
         // MS + matching cert are found
         leave.identity = identity;
-        leaveData[identity.pubkey] = leave;
+        leaveData[identity.pub] = leave;
       }
     }
     return leaveData;
   }
 
-  private async findNewcomers(current:DBBlock, filteringFunc: (joinData: { [pub:string]: any }) => Promise<{ [pub:string]: any }>) {
-    const updates = {};
+  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, updates)
+        const theNewLinks = await this.computeNewLinks(nextBlockNumber, someNewcomers, joinData)
         await this.checkWoTConstraints(nextBlock, theNewLinks, current);
       })
-      const newLinks = await this.computeNewLinks(nextBlockNumber, realNewcomers, joinData, updates);
+      const newLinks = await this.computeNewLinks(nextBlockNumber, realNewcomers, joinData)
       const newWoT = wotMembers.concat(realNewcomers);
-      const finalJoinData: { [pub:string]: any } = {};
+      const finalJoinData: { [pub:string]: PreJoin } = {};
       realNewcomers.forEach((newcomer:string) => {
         // Only keep membership of selected newcomers
         finalJoinData[newcomer] = joinData[newcomer];
@@ -212,19 +226,14 @@ export class BlockGenerator {
         });
         joinData[newcomer].certs = keptCerts;
       });
-      return {
-        current: current,
-        newWotMembers: wotMembers.concat(realNewcomers),
-        finalJoinData: finalJoinData,
-        updates: updates
-      }
+      return finalJoinData
     } catch(err) {
       this.logger.error(err);
       throw err;
     }
   }
 
-  private async checkWoTConstraints(block:{ number:number, joiners:string[], identities:string[] }, newLinks:any, current:DBBlock) {
+  private async checkWoTConstraints(block:{ number:number, joiners:string[], identities:string[] }, newLinks:any, current:DBBlock|null) {
     if (block.number < 0) {
       throw 'Cannot compute WoT constraint for negative block number';
     }
@@ -266,25 +275,28 @@ export class BlockGenerator {
     }
   }
 
-  private async getPreJoinData(current:DBBlock) {
-    const preJoinData:any = {};
-    const memberships = await this.dal.findNewcomers(current && current.medianTime)
+  private async getPreJoinData(current:DBBlock|null) {
+    const preJoinData:{ [k:string]: PreJoin } = {}
+    const memberships = await this.dal.findNewcomers((current && current.medianTime) || 0)
     const joiners:string[] = [];
     memberships.forEach((ms:any) => joiners.push(ms.issuer));
     for (const ms of memberships) {
       try {
         if (ms.block !== CommonConstants.SPECIAL_BLOCK) {
-          let msBasedBlock = await this.dal.getBlockByBlockstampOrNull(ms.block);
+          let msBasedBlock = await this.dal.getAbsoluteValidBlockInForkWindow(ms.blockNumber, ms.blockHash)
           if (!msBasedBlock) {
             throw constants.ERRORS.BLOCKSTAMP_DOES_NOT_MATCH_A_BLOCK;
           }
+          if (!current) {
+            throw Error(DataErrors[DataErrors.CANNOT_DETERMINATE_MEMBERSHIP_AGE])
+          }
           let age = current.medianTime - msBasedBlock.medianTime;
           if (age > this.conf.msWindow) {
             throw constants.ERRORS.TOO_OLD_MEMBERSHIP;
           }
         }
         const idtyHash = (hashf(ms.userid + ms.certts + ms.issuer) + "").toUpperCase();
-        const join:any = await this.getSinglePreJoinData(current, idtyHash, joiners);
+        const join = await this.getSinglePreJoinData(current, idtyHash, joiners);
         join.ms = ms;
         const currentMembership = await this.dal.mindexDAL.getReducedMS(ms.issuer);
         const currentMSN = currentMembership ? parseInt(currentMembership.created_on) : -1;
@@ -302,25 +314,22 @@ export class BlockGenerator {
     return preJoinData;
   }
 
-  private async computeNewLinks(forBlock:number, theNewcomers:any, joinData:any, updates:any) {
+  private async computeNewLinks(forBlock:number, theNewcomers:any, joinData:Map<PreJoin>) {
     let newCerts = await this.computeNewCerts(forBlock, theNewcomers, joinData);
-    return this.newCertsToLinks(newCerts, updates);
+    return this.newCertsToLinks(newCerts);
   }
 
-  newCertsToLinks(newCerts:any, updates:any) {
-    let newLinks:any = {};
-    _.mapObject(newCerts, function(certs:any, pubkey:string) {
-      newLinks[pubkey] = _.pluck(certs, 'from');
-    });
-    _.mapObject(updates, function(certs:any, pubkey:string) {
-      newLinks[pubkey] = (newLinks[pubkey] || []).concat(_.pluck(certs, 'pubkey'));
-    });
-    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] || [];
@@ -343,11 +352,11 @@ export class BlockGenerator {
         }
       }
     }
-    return newCerts;
+    return newCerts
   }
 
-  async getSinglePreJoinData(current:DBBlock, idHash:string, joiners:string[]) {
-    const identity = await this.dal.getIdentityByHashOrNull(idHash);
+  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();
     if (!identity) {
@@ -357,7 +366,10 @@ export class BlockGenerator {
       throw constants.ERRORS.TOO_OLD_IDENTITY;
     }
     else if (!identity.wasMember && identity.buid != CommonConstants.SPECIAL_BLOCK) {
-      const idtyBasedBlock = await this.dal.getBlock(identity.buid);
+      const idtyBasedBlock = await this.dal.getTristampOf(parseInt(identity.buid.split('-')[0]))
+      if (!current || !idtyBasedBlock) {
+        throw Error(DataErrors[DataErrors.CANNOT_DETERMINATE_IDENTITY_AGE])
+      }
       const age = current.medianTime - idtyBasedBlock.medianTime;
       if (age > this.conf.idtyWindow) {
         throw constants.ERRORS.TOO_OLD_IDENTITY;
@@ -375,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
@@ -385,7 +397,7 @@ export class BlockGenerator {
         const certifiers = [];
         for (const cert of certs) {
           try {
-            const basedBlock = await this.dal.getBlock(cert.block_number);
+            const basedBlock = await this.dal.getTristampOf(cert.block_number)
             if (!basedBlock) {
               throw 'Unknown timestamp block for identity';
             }
@@ -408,10 +420,12 @@ export class BlockGenerator {
             const isMember = await this.dal.isMember(cert.from);
             const doubleSignature = !!(~certifiers.indexOf(cert.from))
             if (isMember && !doubleSignature) {
-              const isValid = await GLOBAL_RULES_HELPERS.checkCertificationIsValidForBlock(cert, { number: current.number + 1, currency: current.currency }, async () => {
-                const idty = await this.dal.getIdentityByHashOrNull(idHash)
-                return idty
-              }, this.conf, this.dal);
+              const isValid = await GLOBAL_RULES_HELPERS.checkCertificationIsValidForBlock(
+                cert,
+                { number: current.number + 1, currency: current.currency },
+                async () => this.dal.getGlobalIdentityByHashForHashingAndSig(idHash),
+                this.conf,
+                this.dal)
               if (isValid) {
                 certifiers.push(cert.from);
                 foundCerts.push(cert);
@@ -424,15 +438,26 @@ export class BlockGenerator {
         }
       }
     }
+    const ms:any = null // TODO: refactor
     return {
       identity: identity,
       key: null,
       idHash: idHash,
-      certs: foundCerts
+      certs: foundCerts,
+      ms
     };
   }
 
-  private async createBlock(current:DBBlock, joinData:any, leaveData:any, updates:any, revocations:any, exclusions:any, wereExcluded:any, transactions:any, manualValues:any) {
+  private async createBlock(
+    current:DBBlock|null,
+    joinData:{ [pub:string]: PreJoin },
+    leaveData:{ [pub:string]: LeaveData },
+    updates:any,
+    revocations:any,
+    exclusions:any,
+    wereExcluded:any,
+    transactions:any,
+    manualValues:any) {
 
     if (manualValues && manualValues.excluded) {
       exclusions = manualValues.excluded;
@@ -448,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];
     });
@@ -503,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) {
@@ -517,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) {
@@ -538,11 +563,11 @@ 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
-      if (data.identity.member) {
+      if (data.identity && data.identity.member) {
         if (blockLen < maxLenOfBlock) {
           block.leavers.push(MembershipDTO.fromJSONObject(data.ms).inline());
           blockLen++;
@@ -577,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];
     });
@@ -643,7 +668,7 @@ export class BlockGenerator {
       block.dividend = vHEAD.dividend;
       block.unitbase = vHEAD.unitBase;
     } else {
-      block.unitbase = block.number == 0 ? 0 : current.unitbase;
+      block.unitbase = block.number == 0 ? 0 : (current as DBBlock).unitbase; // For sur current is not null, as UD is only on blocks# > 0
     }
     // Rotation
     block.issuersCount = vHEAD.issuersCount;
@@ -651,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;
@@ -666,7 +691,7 @@ export class BlockGeneratorWhichProves extends BlockGenerator {
     super(server)
   }
 
-  async makeNextBlock(block:DBBlock|null, trial:number, manualValues:any = null) {
+  async makeNextBlock(block:DBBlock|null, trial?:number|null, manualValues:any = null) {
     const unsignedBlock = block || (await this.nextBlock(manualValues))
     const trialLevel = trial || (await this.mainContext.getIssuerPersonalizedDifficulty(this.selfPubkey))
     return this.prover.prove(unsignedBlock, trialLevel, (manualValues && manualValues.time) || null);
@@ -674,7 +699,7 @@ export class BlockGeneratorWhichProves extends BlockGenerator {
 }
 
 interface BlockGeneratorInterface {
-  findNewCertsFromWoT(current:DBBlock): Promise<any>
+  findNewCertsFromWoT(current:DBBlock|null): Promise<any>
   filterJoiners(preJoinData:any): Promise<any>
 }
 
@@ -686,35 +711,43 @@ class NextBlockGenerator implements BlockGeneratorInterface {
 
   constructor(
     private mainContext:BlockchainContext,
-    private conf:ConfDTO,
-    private dal:FileDAL,
+    private server:Server,
     private logger:any) {
   }
 
-  async findNewCertsFromWoT(current:DBBlock) {
+  get conf() {
+    return this.server.conf
+  }
+
+  get dal() {
+    return this.server.dal
+  }
+
+  async findNewCertsFromWoT(current:DBBlock|null) {
     const updates:any = {};
     const updatesToFrom:any = {};
     const certs = await this.dal.certsFindNew();
     const vHEAD_1 = await this.mainContext.getvHEAD_1();
     for (const cert of certs) {
-      const targetIdty = await this.dal.getIdentityByHashOrNull(cert.target);
+      const targetIdty = await this.dal.getGlobalIdentityByHashForHashingAndSig(cert.target)
       // The identity must be known
       if (targetIdty) {
         const certSig = cert.sig;
         // Do not rely on certification block UID, prefer using the known hash of the block by its given number
-        const targetBlock = await this.dal.getBlock(cert.block_number);
+        const targetBlock = await this.dal.getTristampOf(cert.block_number)
         // Check if writable
-        let duration = current && targetBlock ? current.medianTime - parseInt(targetBlock.medianTime) : 0;
+        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;
@@ -769,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;
   }
@@ -787,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/permanentProver.ts b/app/modules/prover/lib/permanentProver.ts
index 9bf74f00054a6c36c5f58bf7cd686f15bdc94dea..7347aac00ea85194004af7da636979391f3452f3 100644
--- a/app/modules/prover/lib/permanentProver.ts
+++ b/app/modules/prover/lib/permanentProver.ts
@@ -19,14 +19,7 @@ import {dos2unix} from "../../../lib/common-libs/dos2unix"
 import {parsers} from "../../../lib/common-libs/parsers/index"
 
 import {Server} from "../../../../server"
-
-const querablep = require('querablep');
-
-export interface Querable<T> extends Promise<T> {
-  isFulfilled(): boolean
-  isResolved(): boolean
-  isRejected(): boolean
-}
+import {Querable, querablep} from "../../../lib/common-libs/querable"
 
 export class PermanentProver {
 
@@ -36,7 +29,7 @@ export class PermanentProver {
   generator:BlockGeneratorWhichProves
   loops:number
 
-  private permanencePromise:Querable<any>|null = null
+  private permanencePromise:Querable<void>|null = null
 
   private blockchainChangedResolver:any = null
   private promiseOfWaitingBetween2BlocksOfOurs:any = null
@@ -140,7 +133,7 @@ export class PermanentProver {
               // The pushFIFO is here to get the difficulty level while excluding any new block to be resolved.
               // Without it, a new block could be added meanwhile and would make the difficulty wrongly computed.
               await this.server.BlockchainService.pushFIFO('generatingNextBlock', async () => {
-                const current = await this.server.dal.getCurrentBlockOrNull();
+                const current = (await this.server.dal.getCurrentBlockOrNull()) as DBBlock
                 const selfPubkey = this.server.keyPair.publicKey;
                 if (!cancelAlreadyTriggered) {
                   trial2 = await this.server.getBcContext().getIssuerPersonalizedDifficulty(selfPubkey)
@@ -209,7 +202,7 @@ export class PermanentProver {
     permanenceResolve()
   }
 
-  async blockchainChanged(gottenBlock:any) {
+  async blockchainChanged(gottenBlock?:any) {
     if (this.server && (!gottenBlock || !this.lastComputedBlock || gottenBlock.hash !== this.lastComputedBlock.hash)) {
       // Cancel any processing proof
       await this.prover.cancel()
diff --git a/app/modules/prover/lib/powCluster.ts b/app/modules/prover/lib/powCluster.ts
index 9bc46362a4fd7ec376dafdc93ab9ed25c505a368..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')
@@ -50,7 +50,7 @@ export class Master {
   onInfoCallback:any
   workersOnline:Promise<any>[]
 
-  constructor(private nbCores:number, logger:any, private dal?:FileDAL) {
+  constructor(private nbCores:number|null|undefined, logger:any, private dal?:FileDAL) {
     this.clusterId = clusterId++
     this.logger = logger || Master.defaultLogger()
     this.onInfoMessage = (message:any) => {
@@ -90,7 +90,8 @@ export class Master {
       execArgv: [] // Do not try to debug forks
     })
 
-    this.slaves = Array.from({ length: this.nbCores }).map((value, index) => {
+    const nbCores = this.nbCores !== undefined && this.nbCores !== null ? this.nbCores : 1
+    this.slaves = Array.from({ length: nbCores }).map((value, index) => {
       const nodejsWorker = cluster.fork()
       const worker = new PowWorker(nodejsWorker, message => {
         this.onWorkerMessage(index, message)
@@ -139,7 +140,7 @@ export class Master {
         value: this.conf
       })
     })
-    return Promise.resolve(_.clone(conf))
+    return Promise.resolve(Underscore.clone(conf))
   }
 
   private cancelWorkersWork() {
@@ -204,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/prover/lib/proof.ts b/app/modules/prover/lib/proof.ts
index af1024409ad401bc0f0991215e52de8b3f0bdf82..50329b0a595ed6976b47dfc4390a4d5eb9951cc0 100644
--- a/app/modules/prover/lib/proof.ts
+++ b/app/modules/prover/lib/proof.ts
@@ -11,6 +11,7 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
+import * as moment from "moment"
 import {LOCAL_RULES_HELPERS} from "../../../lib/rules/local_rules"
 import {hashf} from "../../../lib/common"
 import {DBBlock} from "../../../lib/db/DBBlock"
@@ -21,10 +22,9 @@ import {dos2unix} from "../../../lib/common-libs/dos2unix"
 import {rawer} from "../../../lib/common-libs/index"
 import {ProcessCpuProfiler} from "../../../ProcessCpuProfiler"
 import {PowDAL} from "../../../lib/dal/fileDALs/PowDAL";
+import {Directory} from "../../../lib/system/directory"
 
-const moment = require('moment');
 const querablep = require('querablep');
-const directory = require('../../../lib/system/directory');
 
 export function createPowWorker() {
 
@@ -64,7 +64,7 @@ export function createPowWorker() {
           }
 
           if (message.value.rootPath) {
-            const params = await directory.getHomeFS(false, message.value.rootPath, false)
+            const params = await Directory.getHomeFS(false, message.value.rootPath, false)
             powDAL = new PowDAL(message.value.rootPath, params.fs)
           }
 
diff --git a/app/modules/reapply.ts b/app/modules/reapply.ts
index 0fcb1b206d56b29ae4c75cd268b73ff161a4c191..ac58ece38c4b6e54c86c399cd96ad1a50681b7f9 100644
--- a/app/modules/reapply.ts
+++ b/app/modules/reapply.ts
@@ -34,6 +34,18 @@ module.exports = {
           await server.disconnect();
         }
       }
+    }, {
+      name: 'db-dump',
+      desc: 'Dump some db data',
+      preventIfRunning: true,
+      onDatabaseExecute: async (server:Server, conf:ConfDTO, program:any, params:any) => {
+        const data = await server.dal.iindexDAL.findAllByWrittenOn()
+        for (const d of data) {
+          if (d.pub === "9DDn592RMWfka6fPtTGkmAS54CkYxohDGuk41EECxioD") {
+            console.log("%s %s", d.pub, d.kick)
+          }
+        }
+      }
     }]
   }
 }
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/WS2PBlockPuller.ts b/app/modules/ws2p/lib/WS2PBlockPuller.ts
index 1a3445bc2ea16c02e58c492a768d1a5c91960464..638db4b9381070f3ca4d55274afcbbe8e1008797 100644
--- a/app/modules/ws2p/lib/WS2PBlockPuller.ts
+++ b/app/modules/ws2p/lib/WS2PBlockPuller.ts
@@ -84,7 +84,7 @@ class WS2PDao extends AbstractDAO {
   }
 
   async getLocalBlock(number: number): Promise<DBBlock> {
-    return this.server.dal.getBlock(number)
+    return this.server.dal.getBlockWeHaveItForSure(number)
   }
 
   async getRemoteBlock(thePeer: any, number: number): Promise<BlockDTO> {
diff --git a/app/modules/ws2p/lib/WS2PClient.ts b/app/modules/ws2p/lib/WS2PClient.ts
index f4b03b46a03d3c0552ccf3a910f0610d8a6148a1..6f3602cb9a9146a299aeb324954a487720047673 100644
--- a/app/modules/ws2p/lib/WS2PClient.ts
+++ b/app/modules/ws2p/lib/WS2PClient.ts
@@ -11,7 +11,6 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-import { WS2PCluster } from './WS2PCluster';
 import {Server} from "../../../../server"
 import {WS2PConnection, WS2PPubkeyLocalAuth, WS2PPubkeyRemoteAuth} from "./WS2PConnection"
 import {Key} from "../../../lib/common-libs/crypto/keyring"
@@ -19,12 +18,18 @@ import {WS2PMessageHandler} from "./impl/WS2PMessageHandler"
 import {WS2PConstants} from "./constants"
 import {WS2PStreamer} from "./WS2PStreamer"
 import {WS2PSingleWriteStream} from "./WS2PSingleWriteStream"
-import { ProxiesConf } from '../../../lib/proxy';
-import { server } from '../../../../test/integration/tools/toolbox';
+import {ProxiesConf} from '../../../lib/proxy';
 
 export class WS2PClient {
 
-  private constructor(public connection:WS2PConnection) {}
+  private constructor(
+    public connection:WS2PConnection,
+    private streamer:WS2PStreamer) {
+  }
+
+  disableStream() {
+    this.streamer.disable()
+  }
 
   static async connectTo(server:Server, fullEndpointAddress:string, endpointVersion:number, expectedWS2PUID:string, messageHandler:WS2PMessageHandler, expectedPub:string, allowKey:(pub:string)=>Promise<boolean> ) {
     const k2 = new Key(server.conf.pair.pub, server.conf.pair.sec)
@@ -69,6 +74,6 @@ export class WS2PClient {
       c.close()
       throw e
     }
-    return new WS2PClient(c)
+    return new WS2PClient(c, streamer)
   }
 }
\ No newline at end of file
diff --git a/app/modules/ws2p/lib/WS2PCluster.ts b/app/modules/ws2p/lib/WS2PCluster.ts
index 5a92233d678f4e571f506dffe588d0940d580048..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
@@ -257,7 +257,7 @@ export class WS2PCluster {
     }
     if (!exists) {
       // Do we have this block in the DB?
-      exists = !!(await this.server.dal.getAbsoluteBlockByBlockstamp(blockstamp))
+      exists = !!(await this.server.dal.getAbsoluteBlockInForkWindowByBlockstamp(blockstamp))
     }
     // Update the last time it was checked
     this.blockstampsCache[blockstamp] = Date.now()
@@ -336,7 +336,7 @@ export class WS2PCluster {
     }
   }
 
-  async connectToRemoteWS(endpointVersion:number, host: string, port: number, path:string, messageHandler:WS2PMessageHandler, expectedPub:string, ws2pEndpointUUID:string = ""): Promise<WS2PConnection> {
+  async connectToRemoteWS(endpointVersion:number, host: string, port: number, path:string, messageHandler:WS2PMessageHandler, expectedPub:string, ws2pEndpointUUID:string = ""): Promise<WS2PClient> {
     const uuid = nuuid.v4()
     let pub = expectedPub.slice(0, 8)
     const api:string = (host.match(WS2PConstants.HOST_ONION_REGEX) !== null) ? 'WS2PTOR':'WS2P'
@@ -368,7 +368,7 @@ export class WS2PCluster {
         to: { host, port, pubkey: pub }
       })
       await this.server.dal.setPeerUP(pub)
-      return ws2pc.connection
+      return ws2pc
     } catch (e) {
       this.server.logger.info(api+': Could not connect to peer %s using `'+api+' %s %s: %s`', pub.slice(0, 8), host, port, (e && e.message || e))
       throw e
@@ -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) {
@@ -889,7 +889,7 @@ export class WS2PCluster {
 
   async pullBlocks() {
     let current:{number:number} = { number: -1 }
-    let newCurrent:{number:number} = { number: 0 }
+    let newCurrent:{number:number}|null = { number: 0 }
     while (current && newCurrent && newCurrent.number > current.number) {
       current = newCurrent
       await this.makeApullShot()
diff --git a/app/modules/ws2p/lib/WS2PConnection.ts b/app/modules/ws2p/lib/WS2PConnection.ts
index dad3bdbeebe643d18d3bbe02db234d483c126ccb..0f8cf34a77e5f6aeafb579f1b7fc5132eb32b93e 100644
--- a/app/modules/ws2p/lib/WS2PConnection.ts
+++ b/app/modules/ws2p/lib/WS2PConnection.ts
@@ -20,8 +20,8 @@ import {MembershipDTO} from "../../../lib/dto/MembershipDTO"
 import {TransactionDTO} from "../../../lib/dto/TransactionDTO"
 import {PeerDTO} from "../../../lib/dto/PeerDTO"
 import {WS2PConstants} from './constants';
+import {WebSocket} from "../../../lib/common-libs/websocket"
 
-const ws = require('ws')
 const SocksProxyAgent = require('socks-proxy-agent');
 const nuuid = require('node-uuid');
 const logger = require('../../../lib/logger').NewLogger('ws2p')
@@ -334,7 +334,7 @@ export class WS2PConnection {
           requestTimeout: WS2PConstants.REQUEST_TOR_TIMEOUT
         }
       }
-      const websocket = (proxySocksAddress !== undefined) ? new ws(address, { agent: SocksProxyAgent("socks://"+proxySocksAddress) }):new ws(address)
+      const websocket = (proxySocksAddress !== undefined) ? new WebSocket(address, { agent: SocksProxyAgent("socks://"+proxySocksAddress) }):new WebSocket(address)
     const onWsOpened:Promise<void> = new Promise(res => {
       websocket.on('open', () => res())
     })
diff --git a/app/modules/ws2p/lib/WS2PServer.ts b/app/modules/ws2p/lib/WS2PServer.ts
index d0eec6b8fdd663a6a615acb7bef158490ce67c83..a9091d43ebd0b4fb221c755f99682bc2203c19c2 100644
--- a/app/modules/ws2p/lib/WS2PServer.ts
+++ b/app/modules/ws2p/lib/WS2PServer.ts
@@ -20,8 +20,7 @@ import {WS2PConstants} from "./constants"
 import {WS2PMessageHandler} from "./impl/WS2PMessageHandler"
 import {WS2PStreamer} from "./WS2PStreamer"
 import {WS2PSingleWriteStream} from "./WS2PSingleWriteStream"
-
-const WebSocketServer = require('ws').Server
+import {WebSocketServer} from "../../../lib/common-libs/websocket"
 
 export class WS2PServer extends events.EventEmitter {
 
diff --git a/app/modules/ws2p/lib/WS2PStreamer.ts b/app/modules/ws2p/lib/WS2PStreamer.ts
index f96b10a026396ff5953e02a9efaa9ff990111c93..045f06ca65bdbbe58e22a8646034ae72afd2bd4b 100644
--- a/app/modules/ws2p/lib/WS2PStreamer.ts
+++ b/app/modules/ws2p/lib/WS2PStreamer.ts
@@ -12,18 +12,31 @@
 // GNU Affero General Public License for more details.
 
 import * as stream from "stream"
-import { NewLogger } from "../../../lib/logger";
-import { WS2PConnection } from "./WS2PConnection";
+import {NewLogger} from "../../../lib/logger";
+import {WS2PConnection} from "./WS2PConnection";
 
 const logger = NewLogger()
 
 export class WS2PStreamer extends stream.Transform {
 
+  private enabled = true
+
   constructor(private ws2pc:WS2PConnection) {
     super({ objectMode: true })
   }
 
+  enable() {
+    this.enabled = true
+  }
+
+  disable() {
+    this.enabled = false
+  }
+
   async _write(obj:any, enc:any, done:any) {
+    if (!this.enabled) {
+      return done && done()
+    }
     try {
       if (obj.joiners) {
         await this.ws2pc.pushBlock(obj)
diff --git a/app/modules/ws2p/lib/impl/WS2PReqMapperByServer.ts b/app/modules/ws2p/lib/impl/WS2PReqMapperByServer.ts
index b5bd1e954ae501f8e0331f49e8d0f9f43d0d507e..ae805fdc2d5a5abe34c3027940db285ea03d9504 100644
--- a/app/modules/ws2p/lib/impl/WS2PReqMapperByServer.ts
+++ b/app/modules/ws2p/lib/impl/WS2PReqMapperByServer.ts
@@ -11,11 +11,11 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-import { IdentityForRequirements } from './../../../../service/BlockchainService';
+import {IdentityForRequirements} from './../../../../service/BlockchainService';
 import {Server} from "../../../../../server"
 import {WS2PReqMapper} from "../interface/WS2PReqMapper"
 import {BlockDTO} from "../../../../lib/dto/BlockDTO"
-import { IindexEntry } from '../../../../lib/indexer';
+import {DBBlock} from "../../../../lib/db/DBBlock"
 
 export class WS2PReqMapperByServer implements WS2PReqMapper {
 
@@ -25,8 +25,8 @@ export class WS2PReqMapperByServer implements WS2PReqMapper {
     return this.server.BlockchainService.current()
   }
 
-  getBlock(number: number): Promise<BlockDTO[]> {
-    return this.server.dal.getBlock(number)
+  async getBlock(number: number): Promise<BlockDTO> {
+    return Promise.resolve(BlockDTO.fromJSONObject(await this.server.dal.getFullBlockOf(number)))
   }
 
   async getBlocks(count: number, from: number): Promise<BlockDTO[]> {
@@ -34,37 +34,34 @@ export class WS2PReqMapperByServer implements WS2PReqMapper {
       throw 'Count is too high'
     }
     const current = await this.server.dal.getCurrentBlockOrNull()
+    if (!current) {
+      return []
+    }
     count = Math.min(current.number - from + 1, count)
     if (!current || current.number < from) {
       return []
     }
-    return this.server.dal.getBlocksBetween(from, from + count - 1)
+    return (await this.server.dal.getBlocksBetween(from, from + count - 1)).map((b:DBBlock) => BlockDTO.fromJSONObject(b))
   }
 
   async getRequirementsOfPending(minsig: number): Promise<any> {
-    let identities:IdentityForRequirements[] = await this.server.dal.idtyDAL.query(
+    let identities:IdentityForRequirements[] = (await this.server.dal.idtyDAL.query(
       'SELECT i.*, count(c.sig) as nbSig ' +
       'FROM idty i, cert c ' +
       'WHERE c.target = i.hash group by i.hash having nbSig >= ?',
-      minsig)
-    const members:IdentityForRequirements[] = (await this.server.dal.idtyDAL.query(
-      'SELECT i.*, count(c.sig) as nbSig ' +
-      'FROM i_index i, cert c ' +
-      'WHERE c.`to` = i.pub group by i.pub having nbSig >= ?',
-      minsig)).map((i:IindexEntry):IdentityForRequirements => {
-        return {
-          hash: i.hash || "",
-          member: i.member || false,
-          wasMember: i.wasMember || false,
-          pubkey: i.pub,
-          uid: i.uid || "",
-          buid: i.created_on || "",
-          sig: i.sig || "",
-          revocation_sig: "",
-          revoked: false,
-          revoked_on: 0
-        }
-      })
+      [minsig])).map(i => ({
+      hash: i.hash || "",
+      member: i.member || false,
+      wasMember: i.wasMember || false,
+      pubkey: i.pubkey,
+      uid: i.uid || "",
+      buid: i.buid || "",
+      sig: i.sig || "",
+      revocation_sig: i.revocation_sig,
+      revoked: i.revoked,
+      revoked_on: i.revoked_on ? 1 : 0
+    }))
+    const members = await this.server.dal.findReceiversAbove(minsig)
     identities = identities.concat(members)
     const all = await this.server.BlockchainService.requirementsOfIdentities(identities, false)
     return {
diff --git a/app/modules/ws2p/lib/interface/WS2PReqMapper.ts b/app/modules/ws2p/lib/interface/WS2PReqMapper.ts
index 651fb22cb59cd04d70c09f2b549df0f5728a55ec..b2575e4a26c5beb51d43b1fbfe67137b37d69822 100644
--- a/app/modules/ws2p/lib/interface/WS2PReqMapper.ts
+++ b/app/modules/ws2p/lib/interface/WS2PReqMapper.ts
@@ -12,11 +12,12 @@
 // GNU Affero General Public License for more details.
 
 import {BlockDTO} from "../../../../lib/dto/BlockDTO"
+import {DBBlock} from "../../../../lib/db/DBBlock"
 
 export interface WS2PReqMapper {
 
-  getCurrent(): Promise<BlockDTO>
-  getBlock(number:number): Promise<BlockDTO[]>
+  getCurrent(): Promise<DBBlock|null>
+  getBlock(number:number): Promise<BlockDTO>
   getBlocks(count:number, fromNumber:number): Promise<BlockDTO[]>
   getRequirementsOfPending(minCert:number): Promise<any>
 }
\ No newline at end of file
diff --git a/app/service/BlockchainService.ts b/app/service/BlockchainService.ts
index 1337f3ee83218e721d46d77ae9141e8ac1c619c1..27eb39a7f082786c1e83b66032ac2d8937d01e8b 100644
--- a/app/service/BlockchainService.ts
+++ b/app/service/BlockchainService.ts
@@ -28,10 +28,9 @@ import {CommonConstants} from "../lib/common-libs/constants"
 import {LOCAL_RULES_FUNCTIONS} from "../lib/rules/local_rules"
 import {Switcher, SwitcherDao} from "../lib/blockchain/Switcher"
 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 {
@@ -42,10 +41,19 @@ export interface IdentityForRequirements {
   uid:string
   buid:string
   sig:string
-  revocation_sig:string
+  revocation_sig:string|null
   revoked:boolean
   revoked_on:number
 }
+
+export interface ValidCert {
+  from:string
+  to:string
+  sig:string
+  timestamp:number
+  expiresIn:number
+}
+
 export class BlockchainService extends FIFOService {
 
   mainContext:BlockchainContext
@@ -64,8 +72,12 @@ export class BlockchainService extends FIFOService {
 
       constructor(private bcService:BlockchainService) {}
 
-      getCurrent(): Promise<BlockDTO> {
-        return this.bcService.current()
+      async getCurrent(): Promise<BlockDTO|null> {
+        const current = await this.bcService.current()
+        if (!current) {
+          return null
+        }
+        return BlockDTO.fromJSONObject(current)
       }
 
       async getPotentials(numberStart: number, timeStart: number, maxNumber:number): Promise<BlockDTO[]> {
@@ -74,16 +86,14 @@ export class BlockchainService extends FIFOService {
       }
 
       async getBlockchainBlock(number: number, hash: string): Promise<BlockDTO | null> {
-        try {
-          return BlockDTO.fromJSONObject(await this.bcService.dal.getBlockByNumberAndHash(number, hash))
-        } catch (e) {
-          return null
-        }
+        const b = await this.bcService.dal.getAbsoluteValidBlockInForkWindow(number, hash)
+        if (!b) return null
+        return BlockDTO.fromJSONObject(b)
       }
 
-      async getSandboxBlock(number: number, hash: string): Promise<BlockDTO | null> {
-        const block = await this.bcService.dal.getAbsoluteBlockByNumberAndHash(number, hash)
-        if (block && block.fork) {
+      async getAbsoluteBlockInForkWindow(number: number, hash: string): Promise<BlockDTO | null> {
+        const block = await this.bcService.dal.getAbsoluteBlockInForkWindow(number, hash)
+        if (block) {
           return BlockDTO.fromJSONObject(block)
         } else {
           return null
@@ -93,6 +103,9 @@ export class BlockchainService extends FIFOService {
       async revertTo(number: number): Promise<BlockDTO[]> {
         const blocks:BlockDTO[] = []
         const current = await this.bcService.current();
+        if (!current) {
+          throw Error(DataErrors[DataErrors.CANNOT_REVERT_NO_CURRENT_BLOCK])
+        }
         for (let i = 0, count = current.number - number; i < count; i++) {
           const reverted = await this.bcService.mainContext.revertCurrentBlock()
           blocks.push(BlockDTO.fromJSONObject(reverted))
@@ -124,8 +137,8 @@ export class BlockchainService extends FIFOService {
     this.dal = newDAL;
     this.conf = newConf;
     this.logger = require('../lib/logger').NewLogger(this.dal.profile)
-    this.quickSynchronizer = new QuickSynchronizer(this.server.blockchain, this.conf, this.dal, this.logger)
-    this.mainContext.setConfDAL(this.conf, this.dal, this.server.blockchain, this.quickSynchronizer)
+    this.quickSynchronizer = new QuickSynchronizer(this.conf, this.dal, this.logger)
+    this.mainContext.setConfDAL(this.conf, this.dal, this.quickSynchronizer)
     this.selfPubkey = newKeyPair.publicKey;
   }
 
@@ -145,11 +158,18 @@ export class BlockchainService extends FIFOService {
     return this.mainContext.checkBlock(dto, withPoWAndSignature)
   }
 
+  /**
+   * Return the potential HEADs we could fork to (necessarily above us, since we don't fork on older branches).
+   * @returns {Promise<any>}
+   */
   async branches() {
     const current = await this.current()
+    if (!current) {
+      throw Error(DataErrors[DataErrors.CANNOT_REVERT_NO_CURRENT_BLOCK])
+    }
     const switcher = new Switcher(this.switcherDao, this.invalidForks, this.conf.avgGenTime, this.conf.forksize, this.conf.switchOnHeadAdvance, this.logger)
     const heads = await switcher.findPotentialSuitesHeads(current)
-    return heads.concat([current])
+    return heads.concat([BlockDTO.fromJSONObject(current)])
   }
 
   submitBlock(blockToAdd:any, noResolution = false): Promise<BlockDTO> {
@@ -173,7 +193,7 @@ export class BlockchainService extends FIFOService {
           throw CommonConstants.ERRORS.OUT_OF_FORK_WINDOW
         }
       }
-      const absolute = await this.dal.getAbsoluteBlockByNumberAndHash(obj.number, obj.hash)
+      const absolute = await this.dal.existsAbsoluteBlockInForkWindow(parseInt(obj.number), obj.hash)
       if (!absolute) {
         // Save the block in the sandbox
         await this.mainContext.addSideBlock(dto);
@@ -202,9 +222,11 @@ export class BlockchainService extends FIFOService {
     })
   }
 
-  async blockResolution() {
-    let added = true
-    while (added) {
+  async blockResolution(max = 0): Promise<BlockDTO|null> {
+    let lastAdded:BlockDTO|null = null
+    let added:BlockDTO|null
+    let nbAdded = 0
+    do {
       const current = await this.current()
       let potentials = []
       if (current) {
@@ -214,9 +236,9 @@ export class BlockchainService extends FIFOService {
         potentials = await this.dal.getPotentialRootBlocks()
         this.logger.info('Block resolution: %s potential blocks for root block...', potentials.length)
       }
-      added = false
+      added = null
       let i = 0
-      while (!added && i < potentials.length) {
+      while (!added && i < potentials.length && (!max || nbAdded < max)) {
         const dto = BlockDTO.fromJSONObject(potentials[i])
         try {
           if (dto.issuer === this.conf.pair.pub) {
@@ -224,17 +246,17 @@ export class BlockchainService extends FIFOService {
               await this.dal.removeTxByHash(tx.hash);
             }
           }
-          const addedBlock = await this.mainContext.checkAndAddBlock(dto)
-          added = true
+          lastAdded = added = await this.mainContext.checkAndAddBlock(dto)
           this.push({
             bcEvent: OtherConstants.BC_EVENT.HEAD_CHANGED,
-            block: addedBlock
+            block: added
           })
+          nbAdded++
           // Clear invalid forks' cache
           this.invalidForks.splice(0, this.invalidForks.length)
         } catch (e) {
           this.logger.error(e)
-          added = false
+          added = null
           const theError = e && (e.message || e)
           this.push({
             blockResolutionError: theError
@@ -242,7 +264,8 @@ export class BlockchainService extends FIFOService {
         }
         i++
       }
-    }
+    } while (added)
+    return lastAdded
   }
 
   async forkResolution() {
@@ -259,6 +282,10 @@ export class BlockchainService extends FIFOService {
   revertCurrentBlock() {
     return this.pushFIFO("revertCurrentBlock", () => this.mainContext.revertCurrentBlock())
   }
+
+  revertCurrentHead() {
+    return this.pushFIFO("revertCurrentHead", () => this.mainContext.revertCurrentHead())
+  }
   
 
   applyNextAvailableFork() {
@@ -280,7 +307,7 @@ export class BlockchainService extends FIFOService {
     return all;
   }
 
-  async requirementsOfIdentity(idty:IdentityForRequirements, current:DBBlock, computeDistance = true): Promise<HttpIdentityRequirement> {
+  async requirementsOfIdentity(idty:IdentityForRequirements, current:DBBlock|null, computeDistance = true): Promise<HttpIdentityRequirement> {
     // TODO: this is not clear
     let expired = false;
     let outdistanced = false;
@@ -288,7 +315,7 @@ export class BlockchainService extends FIFOService {
     let wasMember = false;
     let expiresMS = 0;
     let expiresPending = 0;
-    let certs = [];
+    let certs:ValidCert[] = [];
     let certsPending = [];
     let mssPending = [];
     try {
@@ -315,7 +342,7 @@ export class BlockchainService extends FIFOService {
       const newCerts = await this.server.generatorComputeNewCerts(nextBlockNumber, [join.identity.pubkey], joinData, updates);
       const newLinks = await this.server.generatorNewCertsToLinks(newCerts, updates);
       const currentTime = current ? current.medianTime : 0;
-      certs = await this.getValidCerts(pubkey, newCerts);
+      certs = await this.getValidCerts(pubkey, newCerts, currentTime);
       if (computeDistance) {
         outdistanced = await GLOBAL_RULES_HELPERS.isOver3Hops(pubkey, newLinks, someNewcomers, current, this.conf, this.dal);
       }
@@ -324,8 +351,8 @@ export class BlockchainService extends FIFOService {
       const currentMSN = currentMembership ? parseInt(currentMembership.created_on) : -1;
       if (currentMSN >= 0) {
         if (join.identity.member) {
-          const msBlock = await this.dal.getBlock(currentMSN);
-          if (msBlock && msBlock.medianTime) { // special case for block #0
+          const msBlock = await this.dal.getTristampOf(currentMSN)
+          if (msBlock) { // special case for block #0
             expiresMS = Math.max(0, (msBlock.medianTime + this.conf.msValidity - currentTime));
           }
           else {
@@ -338,8 +365,8 @@ export class BlockchainService extends FIFOService {
       // Expiration of pending membership
       const lastJoin = await this.dal.lastJoinOfIdentity(idty.hash);
       if (lastJoin) {
-        const msBlock = await this.dal.getBlock(lastJoin.blockNumber);
-        if (msBlock && msBlock.medianTime) { // Special case for block#0
+        const msBlock = await this.dal.getTristampOf(lastJoin.blockNumber)
+        if (msBlock) { // Special case for block#0
           expiresPending = Math.max(0, (msBlock.medianTime + this.conf.msValidity - currentTime));
         }
         else {
@@ -348,10 +375,6 @@ export class BlockchainService extends FIFOService {
       }
       wasMember = idty.wasMember;
       isSentry = idty.member && (await this.dal.isSentry(idty.pubkey, this.conf));
-      // Expiration of certifications
-      for (const cert of certs) {
-        cert.expiresIn = Math.max(0, cert.timestamp + this.conf.sigValidity - currentTime);
-      }
     } catch (e) {
       // We throw whatever isn't "Too old identity" error
       if (!(e && e.uerr && e.uerr.ucode == constants.ERRORS.TOO_OLD_IDENTITY.uerr.ucode)) {
@@ -382,21 +405,34 @@ export class BlockchainService extends FIFOService {
     };
   }
 
-  async getValidCerts(newcomer:string, newCerts:any) {
+  async getValidCerts(newcomer:string, newCerts:any, currentTime:number): Promise<ValidCert[]> {
     const links = await this.dal.getValidLinksTo(newcomer);
-    const certsFromLinks = links.map((lnk:any) => { return { from: lnk.issuer, to: lnk.receiver, timestamp: lnk.expires_on - this.conf.sigValidity }; });
+    const certsFromLinks = links.map((lnk:any) => { return {
+        from: lnk.issuer,
+        to: lnk.receiver,
+        sig: lnk.sig,
+        timestamp: lnk.expires_on - this.conf.sigValidity,
+        expiresIn: 0
+      }
+    })
     const certsFromCerts = [];
     const certs = newCerts[newcomer] || [];
     for (const cert of certs) {
-      const block = await this.dal.getBlock(cert.block_number);
-      certsFromCerts.push({
-        from: cert.from,
-        to: cert.to,
-        sig: cert.sig,
-        timestamp: block.medianTime
-      });
+      const block = await this.dal.getTristampOf(cert.block_number)
+      if (block) {
+        certsFromCerts.push({
+          from: cert.from,
+          to: cert.to,
+          sig: cert.sig,
+          timestamp: block.medianTime,
+          expiresIn: 0
+        })
+      }
     }
-    return certsFromLinks.concat(certsFromCerts);
+    return certsFromLinks.concat(certsFromCerts).map(c => {
+      c.expiresIn = Math.max(0, c.timestamp + this.conf.sigValidity - currentTime)
+      return c
+    })
   }
 
   isMember() {
@@ -410,14 +446,17 @@ export class BlockchainService extends FIFOService {
 
   // This method is called by duniter-crawler 1.3.x
   saveParametersForRootBlock(block:BlockDTO) {
-    return this.server.blockchain.saveParametersForRoot(block, this.conf, this.dal)
+    return DuniterBlockchain.saveParametersForRoot(block, this.conf, this.dal)
   }
 
-  async blocksBetween(from:number, count:number) {
+  async blocksBetween(from:number, count:number): Promise<DBBlock[]> {
     if (count > 5000) {
       throw 'Count is too high';
     }
     const current = await this.current()
+    if (!current) {
+      return []
+    }
     count = Math.min(current.number - from + 1, count);
     if (!current || current.number < from) {
       return [];
diff --git a/app/service/IdentityService.ts b/app/service/IdentityService.ts
index 4237cdebf83236da80cfb053642142e91038b1ae..dba4089fc4d5d858dd36b3c26f9a743f3926c05a 100644
--- a/app/service/IdentityService.ts
+++ b/app/service/IdentityService.ts
@@ -14,7 +14,7 @@
 import {GlobalFifoPromise} from "./GlobalFifoPromise"
 import {FileDAL} from "../lib/dal/fileDAL"
 import {ConfDTO} from "../lib/dto/ConfDTO"
-import {DBIdentity, ExistingDBIdentity} from "../lib/dal/sqliteDAL/IdentityDAL"
+import {DBIdentity} from "../lib/dal/sqliteDAL/IdentityDAL"
 import {GLOBAL_RULES_FUNCTIONS, GLOBAL_RULES_HELPERS} from "../lib/rules/global_rules"
 import {BlockDTO} from "../lib/dto/BlockDTO"
 import {RevocationDTO} from "../lib/dto/RevocationDTO"
@@ -23,6 +23,9 @@ import {CertificationDTO} from "../lib/dto/CertificationDTO"
 import {DBCert} from "../lib/dal/sqliteDAL/CertDAL"
 import {verify} from "../lib/common-libs/crypto/keyring"
 import {FIFOService} from "./FIFOService"
+import {MindexEntry} from "../lib/indexer"
+import {DataErrors} from "../lib/common-libs/errors"
+import {Tristamp} from "../lib/common/Tristamp"
 
 "use strict";
 const constants       = require('../lib/constants');
@@ -49,38 +52,58 @@ export class IdentityService extends FIFOService {
     return this.dal.searchJustIdentities(search)
   }
 
-  async findMember(search:string): Promise<ExistingDBIdentity> {
+  async findMember(search:string) {
     let idty = null;
     if (search.match(constants.PUBLIC_KEY)) {
-      idty = await this.dal.getWrittenIdtyByPubkey(search);
+      idty = await this.dal.getWrittenIdtyByPubkeyForHashing(search);
     }
     else {
-      idty = await this.dal.getWrittenIdtyByUID(search);
+      idty = await this.dal.getWrittenIdtyByUidForHashing(search);
     }
     if (!idty) {
       throw constants.ERRORS.NO_MEMBER_MATCHING_PUB_OR_UID;
     }
-    const obj = DBIdentity.copyFromExisting(idty)
-    await this.dal.fillInMembershipsOfIdentity(Promise.resolve(obj));
-    return obj
-  }
 
-  async findMemberWithoutMemberships(search:string) {
-    let idty = null;
-    if (search.match(constants.PUBLIC_KEY)) {
-      idty = await this.dal.getWrittenIdtyByPubkey(search)
-    }
-    else {
-      idty = await this.dal.getWrittenIdtyByUID(search)
-    }
-    if (!idty) {
-      throw constants.ERRORS.NO_MEMBER_MATCHING_PUB_OR_UID;
+    let memberships: {
+      blockstamp:string
+      membership:string
+      number:number
+      fpr:string
+      written_number:number|null
+    }[] = []
+
+    if (idty) {
+      const mss = await this.dal.msDAL.getMembershipsOfIssuer(idty.pub);
+      const mssFromMindex = await this.dal.mindexDAL.reducable(idty.pub);
+      memberships = mss.map(m => {
+        return {
+          blockstamp: [m.blockNumber, m.blockHash].join('-'),
+          membership: m.membership,
+          number: m.blockNumber,
+          fpr: m.blockHash,
+          written_number: m.written_number
+        }
+      })
+      memberships = memberships.concat(mssFromMindex.map((ms:MindexEntry) => {
+        const sp = ms.created_on.split('-');
+        return {
+          blockstamp: ms.created_on,
+          membership: ms.leaving ? 'OUT' : 'IN',
+          number: parseInt(sp[0]),
+          fpr: sp[1],
+          written_number: parseInt(ms.written_on)
+        }
+      }))
     }
-    return DBIdentity.copyFromExisting(idty)
-  }
 
-  getWrittenByPubkey(pubkey:string) {
-    return this.dal.getWrittenIdtyByPubkey(pubkey)
+    return {
+      idty: {
+        pubkey: idty.pub,
+        uid: idty.uid,
+        buid: idty.created_on
+      },
+      memberships
+    }
   }
 
   getPendingFromPubkey(pubkey:string) {
@@ -101,17 +124,17 @@ export class IdentityService extends FIFOService {
       if (!verified) {
         throw constants.ERRORS.SIGNATURE_DOES_NOT_MATCH;
       }
-      let existing = await this.dal.getIdentityByHashOrNull(toSave.hash);
+      let existing = await this.dal.getGlobalIdentityByHashForExistence(toSave.hash);
       if (existing) {
         throw constants.ERRORS.ALREADY_UP_TO_DATE;
       }
       else {
         // Create if not already written uid/pubkey
-        let used = await this.dal.getWrittenIdtyByPubkey(idty.pubkey);
+        let used = await GLOBAL_RULES_HELPERS.checkExistsPubkey(idty.pubkey, this.dal)
         if (used) {
           throw constants.ERRORS.PUBKEY_ALREADY_USED;
         }
-        used = await this.dal.getWrittenIdtyByUID(idty.uid);
+        used = await GLOBAL_RULES_HELPERS.checkExistsUserID(idty.uid, this.dal)
         if (used) {
           throw constants.ERRORS.UID_ALREADY_USED;
         }
@@ -119,7 +142,7 @@ export class IdentityService extends FIFOService {
         if (idty.buid == '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855' && current) {
           throw constants.ERRORS.BLOCKSTAMP_DOES_NOT_MATCH_A_BLOCK;
         } else if (current) {
-          let basedBlock = await this.dal.getBlockByBlockstamp(idty.buid);
+          let basedBlock = await this.dal.getAbsoluteValidBlockInForkWindowByBlockstamp(idty.buid);
           if (!basedBlock) {
             throw constants.ERRORS.BLOCKSTAMP_DOES_NOT_MATCH_A_BLOCK;
           }
@@ -128,6 +151,7 @@ export class IdentityService extends FIFOService {
         await GLOBAL_RULES_FUNCTIONS.checkIdentitiesAreWritable({ identities: [idtyObj.inline()], version: (current && current.version) || constants.BLOCK_GENERATED_VERSION }, this.conf, this.dal);
         if (byAbsorption !== BY_ABSORPTION) {
           if (!(await this.dal.idtyDAL.sandbox.acceptNewSandBoxEntry({
+              certsCount: 0,
               issuers: [idty.pubkey],
               ref_block: parseInt(idty.buid.split('-')[0])
             }, this.conf.pair && this.conf.pair.pub))) {
@@ -149,35 +173,44 @@ export class IdentityService extends FIFOService {
     obj.currency = this.conf.currency || obj.currency;
     const cert = CertificationDTO.fromJSONObject(obj)
     const targetHash = cert.getTargetHash();
-    let idty = await this.dal.getIdentityByHashOrNull(targetHash);
+    let possiblyNullIdty = await this.dal.getGlobalIdentityByHashForHashingAndSig(targetHash);
     let idtyAbsorbed = false
-    if (!idty) {
+    const idty:{
+      pubkey:string
+      uid:string
+      buid:string
+      sig:string
+    } = possiblyNullIdty !== null ? possiblyNullIdty : await this.submitIdentity({
+      pubkey: cert.idty_issuer,
+      uid: cert.idty_uid,
+      buid: cert.idty_buid,
+      sig: cert.idty_sig
+    }, BY_ABSORPTION);
+    if (possiblyNullIdty === null) {
       idtyAbsorbed = true
-      idty = await this.submitIdentity({
-        pubkey: cert.idty_issuer,
-        uid: cert.idty_uid,
-        buid: cert.idty_buid,
-        sig: cert.idty_sig
-      }, BY_ABSORPTION);
     }
     let anErr:any
     const hash = cert.getHash()
     return this.pushFIFO<CertificationDTO>(hash, async () => {
       this.logger.info('⬇ CERT %s block#%s -> %s', cert.from, cert.block_number, idty.uid);
       try {
-        await GLOBAL_RULES_HELPERS.checkCertificationIsValid(cert, potentialNext, () => Promise.resolve(idty), this.conf, this.dal);
+        await GLOBAL_RULES_HELPERS.checkCertificationIsValidInSandbox(cert, potentialNext, () => Promise.resolve(idty), this.conf, this.dal);
       } catch (e) {
         anErr = e;
       }
       if (!anErr) {
         try {
-          let basedBlock = await this.dal.getBlock(cert.block_number);
+          let basedBlock: Tristamp|null = await this.dal.getTristampOf(cert.block_number);
           if (cert.block_number == 0 && !basedBlock) {
             basedBlock = {
               number: 0,
-              hash: 'E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855'
+              hash: 'E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855',
+              medianTime: 0
             };
           }
+          if (!basedBlock) {
+            throw Error(DataErrors[DataErrors.CERT_BASED_ON_UNKNOWN_BLOCK])
+          }
           const mCert:DBCert = {
             issuers: [cert.from],
             from: cert.from,
@@ -234,7 +267,7 @@ export class IdentityService extends FIFOService {
         if (!verified) {
           throw 'Wrong signature for revocation';
         }
-        const existing = await this.dal.getIdentityByHashOrNull(obj.hash);
+        const existing = await this.dal.getGlobalIdentityByHashForRevocation(obj.hash)
         if (existing) {
           // Modify
           if (existing.revoked) {
@@ -243,7 +276,15 @@ export class IdentityService extends FIFOService {
           else if (existing.revocation_sig) {
             throw 'Revocation already registered';
           } else {
-            await this.dal.setRevocating(existing, revoc.revocation);
+            await this.dal.setRevocating({
+              pubkey: existing.pub,
+              buid: existing.created_on,
+              sig: existing.sig,
+              uid: existing.uid,
+              expires_on: existing.expires_on,
+              member: existing.member,
+              wasMember: existing.wasMember,
+            }, revoc.revocation);
             this.logger.info('✔ REVOCATION %s %s', revoc.pubkey, revoc.idty_uid);
             return revoc
           }
diff --git a/app/service/MembershipService.ts b/app/service/MembershipService.ts
index a02eaa76866b79045cbe37e650e17940c1e47274..3dfe33fd6d9d27f261c30e088d34167539077795 100644
--- a/app/service/MembershipService.ts
+++ b/app/service/MembershipService.ts
@@ -19,6 +19,7 @@ import {LOCAL_RULES_HELPERS} from "../lib/rules/local_rules";
 import {GLOBAL_RULES_HELPERS} from "../lib/rules/global_rules";
 import {MembershipDTO} from "../lib/dto/MembershipDTO";
 import {FIFOService} from "./FIFOService";
+import {DBBlock} from "../lib/db/DBBlock"
 
 const constants       = require('../lib/constants');
 
@@ -38,7 +39,7 @@ export class MembershipService extends FIFOService {
     this.logger = require('../lib/logger').NewLogger(this.dal.profile);
   }
 
-  current() {
+  current(): Promise<DBBlock | null> {
     return this.dal.getCurrentBlockOrNull()
   }
 
@@ -89,7 +90,7 @@ export class MembershipService extends FIFOService {
         idtyHash: entry.getIdtyHash(),
         written: false,
         written_number: null,
-        expires_on: basedBlock ? basedBlock.medianTime + this.conf.msWindow : null,
+        expires_on: basedBlock ? basedBlock.medianTime + this.conf.msWindow : 0,
         signature: entry.signature,
         expired: false,
         block_number: entry.number
diff --git a/app/service/PeeringService.ts b/app/service/PeeringService.ts
old mode 100644
new mode 100755
index e72f6a172fb826d12f382eede5e9351b1a84f7a7..41c6660701257fabc01e3c34db4777d3328845df
--- 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,12 @@ 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"
+import {CommonConstants} from "../lib/common-libs/constants"
+import {DataErrors} from "../lib/common-libs/errors"
 
 const util           = require('util');
-const _              = require('underscore');
 const events         = require('events');
 const logger         = require('../lib/logger').NewLogger('peering');
 const constants      = require('../lib/constants');
@@ -104,10 +106,11 @@ export class PeeringService {
           }
         }
         if (thePeer.block == constants.PEER.SPECIAL_BLOCK) {
+          thePeer.block = constants.PEER.SPECIAL_BLOCK;
           thePeer.statusTS = 0;
           thePeer.status = 'UP';
         } else {
-          block = await this.dal.getBlockByNumberAndHashOrNull(blockNumber, blockHash);
+          block = await this.dal.getAbsoluteValidBlockInForkWindow(blockNumber, blockHash)
           if (!block && makeCheckings) {
             throw constants.ERROR.PEER.UNKNOWN_REFERENCE_BLOCK;
           } else if (!block) {
@@ -115,6 +118,10 @@ export class PeeringService {
             thePeer.statusTS = 0;
             thePeer.status = 'UP';
           }
+          const current = await this.dal.getBlockCurrent()
+          if ((!block && current.number > CommonConstants.MAX_AGE_OF_PEER_IN_BLOCKS) || (block && current.number - block.number > CommonConstants.MAX_AGE_OF_PEER_IN_BLOCKS)) {
+            throw Error(DataErrors[DataErrors.TOO_OLD_PEER])
+          }
         }
         sigTime = block ? block.medianTime : 0;
         thePeer.statusTS = sigTime;
@@ -131,8 +138,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 +193,7 @@ export class PeeringService {
     return this.server.writePeer(pretendedNewer)
   }
 
-  async generateSelfPeer(theConf:ConfDTO, signalTimeInterval = 0) {
+  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 +201,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)
@@ -213,7 +222,7 @@ export class PeeringService {
       logger.error('It seems there is an issue with your configuration.');
       logger.error('Please restart your node with:');
       logger.error('$ duniter restart');
-      return new Promise(() => null);
+      return null
     }
     const endpointsToDeclare = localEndpoints.concat(toConserve).concat(this.conf.endpoints || [])
     if (currentSelfPeer && endpointsToDeclare.length === 0 && currentSelfPeer.endpoints.length === 0) {
@@ -233,13 +242,13 @@ export class PeeringService {
       }
       // The number cannot be superior to current block
       minBlock = Math.min(minBlock, current ? current.number : minBlock);
-      let targetBlock = await this.server.dal.getBlock(minBlock);
+      const targetBlockstamp: string|null = await this.server.dal.getBlockstampOf(minBlock)
       const p2:any = {
         version: constants.DOCUMENTS_VERSION,
         currency: currency,
         pubkey: this.selfPubkey,
-        block: targetBlock ? [targetBlock.number, targetBlock.hash].join('-') : constants.PEER.SPECIAL_BLOCK,
-        endpoints: _.uniq(endpointsToDeclare)
+        block: targetBlockstamp ? targetBlockstamp : constants.PEER.SPECIAL_BLOCK,
+        endpoints: Underscore.uniq(endpointsToDeclare)
       };
       const raw2 = dos2unix(PeerDTO.fromJSONObject(p2).getRaw());
       const bmaAccess = PeerDTO.fromJSONObject(p2).getURL()
diff --git a/app/service/TransactionsService.ts b/app/service/TransactionsService.ts
index c8608f6e7b47a63924f0ff69290fdf4a604271d0..489ed660e1aaf794f3324cf60a3dab2045350bc5 100644
--- a/app/service/TransactionsService.ts
+++ b/app/service/TransactionsService.ts
@@ -11,15 +11,15 @@
 // 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 {FileDAL} from "../lib/dal/fileDAL";
 import {TransactionDTO} from "../lib/dto/TransactionDTO";
 import {LOCAL_RULES_HELPERS} from "../lib/rules/local_rules";
 import {GLOBAL_RULES_HELPERS} from "../lib/rules/global_rules";
-import {DBTx} from "../lib/dal/sqliteDAL/TxsDAL";
 import {FIFOService} from "./FIFOService";
 import {GlobalFifoPromise} from "./GlobalFifoPromise";
+import {DataErrors} from "../lib/common-libs/errors"
+import {DBTx} from "../lib/db/DBTx"
 
 const constants       = require('../lib/constants');
 
@@ -47,6 +47,9 @@ export class TransactionService extends FIFOService {
         this.logger.info('⬇ TX %s:%s from %s', tx.output_amount, tx.output_base, tx.issuers);
         const existing = await this.dal.getTxByHash(tx.hash);
         const current = await this.dal.getCurrentBlockOrNull();
+        if (!current) {
+          throw Error(DataErrors[DataErrors.NO_TRANSACTION_POSSIBLE_IF_NOT_CURRENT_BLOCK])
+        }
         if (existing) {
           throw constants.ERRORS.TX_ALREADY_PROCESSED;
         }
diff --git a/bin/duniter b/bin/duniter
index 60946d8e66b60339c941fc107373764248fe9a38..d91cfe530ace9b8cea85db550a72ba92ab9d32be 100755
--- a/bin/duniter
+++ b/bin/duniter
@@ -1,7 +1,6 @@
 #!/usr/bin/env node
 "use strict";
 
-const co = require('co');
 const logger = require("../app/lib/logger").NewLogger();
 
 // Specific errors handling
@@ -13,12 +12,12 @@ process.on('uncaughtException', (err) => {
   }
 });
 
-return co(function*() {
+(async () => {
 
   try {
     const duniter = require('../index');
     const stack = duniter.statics.autoStack();
-    yield stack.executeStack(process.argv);
+    await stack.executeStack(process.argv);
     // Everything went well, close Duniter quietly.
     process.exit();
   } catch (e) {
@@ -29,4 +28,4 @@ return co(function*() {
     // If we did not succeed to close before, force close with error.
     process.exit(100);
   }
-});
+})()
diff --git a/doc/Protocol.md b/doc/Protocol.md
index 62d8f3ddf9276fa0d797354940e5b899cc81dfca..68a4022c4e3affffb3c9499ad8a568a79035ac19 100644
--- a/doc/Protocol.md
+++ b/doc/Protocol.md
@@ -1,4 +1,4 @@
-# DUP - Duniter Protocol
+DifferentIssuersCount# DUP - Duniter Protocol
 
 > This document reflects Duniter in-production protocol. It is updated only for clarifications (2017).
 
diff --git a/index.ts b/index.ts
index 646e2bf6d44eda8f96e31c50e96818629fa7f3da..92ff49b31faacd701a135bab1ea812a0498244be 100644
--- a/index.ts
+++ b/index.ts
@@ -21,12 +21,13 @@ import {CrawlerDependency} from "./app/modules/crawler/index"
 import {BmaDependency} from "./app/modules/bma/index"
 import {WS2PDependency} from "./app/modules/ws2p/index"
 import {ProverConstants} from "./app/modules/prover/lib/constants"
-import { ProxiesConf } from './app/lib/proxy';
+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 directory = require('./app/lib/system/directory');
 const constants = require('./app/lib/constants');
 const logger = require('./app/lib/logger').NewLogger('duniter');
 
@@ -40,6 +41,7 @@ const revertDependency    = require('./app/modules/revert');
 const daemonDependency    = require('./app/modules/daemon');
 const pSignalDependency   = require('./app/modules/peersignal');
 const pluginDependency    = require('./app/modules/plugin');
+const dumpDependency      = require('./app/modules/dump');
 
 let sigintListening = false
 
@@ -129,7 +131,8 @@ const DEFAULT_DEPENDENCIES = MINIMAL_DEPENDENCIES.concat([
   { name: 'duniter-keypair',   required: KeypairDependency },
   { name: 'duniter-crawler',   required: CrawlerDependency },
   { name: 'duniter-bma',       required: BmaDependency },
-  { name: 'duniter-ws2p',      required: WS2PDependency }
+  { name: 'duniter-ws2p',      required: WS2PDependency },
+  { name: 'duniter-dump',      required: dumpDependency },
 ]);
 
 const PRODUCTION_DEPENDENCIES = DEFAULT_DEPENDENCIES.concat([
@@ -288,9 +291,10 @@ class Stack {
     const params  = args.slice(2);
     params.pop(); // Don't need the command argument
 
+    OtherConstants.SQL_TRACES = program.sqlTraces === true
     const dbName = program.mdb;
     const dbHome = program.home;
-    const home = directory.getHome(dbName, dbHome);
+    const home = Directory.getHome(dbName, dbHome);
 
     if (command.logs === false) {
       logger.mute();
@@ -349,7 +353,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/npm-shrinkwrap.json b/npm-shrinkwrap.json
new file mode 100644
index 0000000000000000000000000000000000000000..66a98a3bb7a4bf3c336fdcd8b43d9e0c789a5c78
--- /dev/null
+++ b/npm-shrinkwrap.json
@@ -0,0 +1,10697 @@
+{
+  "name": "duniter",
+  "version": "1.6.25",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "@types/events": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz",
+      "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA=="
+    },
+    "@types/fs-extra": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-5.0.1.tgz",
+      "integrity": "sha512-h3wnflb+jMTipvbbZnClgA2BexrT4w0GcfoCz5qyxd0IRsbqhLSyesM6mqZTAnhbVmhyTm5tuxfRu9R+8l+lGw==",
+      "requires": {
+        "@types/node": "10.5.1"
+      },
+      "dependencies": {
+        "@types/node": {
+          "version": "10.5.1",
+          "resolved": "https://registry.npmjs.org/@types/node/-/node-10.5.1.tgz",
+          "integrity": "sha512-AFLl1IALIuyt6oK4AYZsgWVJ/5rnyzQWud7IebaZWWV3YmgtPZkQmYio9R5Ze/2pdd7XfqF5bP+hWS11mAKoOQ=="
+        }
+      }
+    },
+    "@types/glob": {
+      "version": "5.0.35",
+      "resolved": "https://registry.npmjs.org/@types/glob/-/glob-5.0.35.tgz",
+      "integrity": "sha512-wc+VveszMLyMWFvXLkloixT4n0harUIVZjnpzztaZ0nKLuul7Z32iMt2fUFGAaZ4y1XWjFRMtCI5ewvyh4aIeg==",
+      "requires": {
+        "@types/events": "1.2.0",
+        "@types/minimatch": "3.0.3",
+        "@types/node": "10.5.1"
+      },
+      "dependencies": {
+        "@types/node": {
+          "version": "10.5.1",
+          "resolved": "https://registry.npmjs.org/@types/node/-/node-10.5.1.tgz",
+          "integrity": "sha512-AFLl1IALIuyt6oK4AYZsgWVJ/5rnyzQWud7IebaZWWV3YmgtPZkQmYio9R5Ze/2pdd7XfqF5bP+hWS11mAKoOQ=="
+        }
+      }
+    },
+    "@types/handlebars": {
+      "version": "4.0.36",
+      "resolved": "https://registry.npmjs.org/@types/handlebars/-/handlebars-4.0.36.tgz",
+      "integrity": "sha512-LjNiTX7TY7wtuC6y3QwC93hKMuqYhgV9A1uXBKNvZtVC8ZvyWAjZkJ5BvT0K7RKqORRYRLMrqCxpw5RgS+MdrQ=="
+    },
+    "@types/highlight.js": {
+      "version": "9.12.2",
+      "resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.12.2.tgz",
+      "integrity": "sha512-y5x0XD/WXDaGSyiTaTcKS4FurULJtSiYbGTeQd0m2LYZGBcZZ/7fM6t5H/DzeUF+kv8y6UfmF6yJABQsHcp9VQ=="
+    },
+    "@types/lodash": {
+      "version": "4.14.104",
+      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.104.tgz",
+      "integrity": "sha512-ufQcVg4daO8xQ5kopxRHanqFdL4AI7ondQkV+2f+7mz3gvp0LkBx2zBRC6hfs3T87mzQFmf5Fck7Fi145Ul6NQ=="
+    },
+    "@types/lokijs": {
+      "version": "1.5.2",
+      "resolved": "https://registry.npmjs.org/@types/lokijs/-/lokijs-1.5.2.tgz",
+      "integrity": "sha512-ZF14v1P1Bjbw8VJRu+p4WS9V926CAOjWF4yq23QmSBWRPe0/GXlUKzSxjP1fi/xi8nrq6zr9ECo8Z/8KsRqroQ==",
+      "dev": true
+    },
+    "@types/marked": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/@types/marked/-/marked-0.3.0.tgz",
+      "integrity": "sha512-CSf9YWJdX1DkTNu9zcNtdCcn6hkRtB5ILjbhRId4ZOQqx30fXmdecuaXhugQL6eyrhuXtaHJ7PHI+Vm7k9ZJjg=="
+    },
+    "@types/minimatch": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
+      "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA=="
+    },
+    "@types/mocha": {
+      "version": "2.2.48",
+      "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.48.tgz",
+      "integrity": "sha512-nlK/iyETgafGli8Zh9zJVCTicvU3iajSkRwOh3Hhiva598CMqNJ4NcVCGMTGKpGpTYj/9R8RLzS9NAykSSCqGw==",
+      "dev": true
+    },
+    "@types/node": {
+      "version": "8.10.20",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.20.tgz",
+      "integrity": "sha512-M7x8+5D1k/CuA6jhiwuSCmE8sbUWJF0wYsjcig9WrXvwUI5ArEoUBdOXpV4JcEMrLp02/QbDjw+kI+vQeKyQgg==",
+      "dev": true
+    },
+    "@types/shelljs": {
+      "version": "0.7.8",
+      "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.7.8.tgz",
+      "integrity": "sha512-M2giRw93PxKS7YjU6GZjtdV9HASdB7TWqizBXe4Ju7AqbKlWvTr0gNO92XH56D/gMxqD/jNHLNfC5hA34yGqrQ==",
+      "requires": {
+        "@types/glob": "5.0.35",
+        "@types/node": "10.5.1"
+      },
+      "dependencies": {
+        "@types/node": {
+          "version": "10.5.1",
+          "resolved": "https://registry.npmjs.org/@types/node/-/node-10.5.1.tgz",
+          "integrity": "sha512-AFLl1IALIuyt6oK4AYZsgWVJ/5rnyzQWud7IebaZWWV3YmgtPZkQmYio9R5Ze/2pdd7XfqF5bP+hWS11mAKoOQ=="
+        }
+      }
+    },
+    "@types/should": {
+      "version": "8.3.0",
+      "resolved": "https://registry.npmjs.org/@types/should/-/should-8.3.0.tgz",
+      "integrity": "sha1-4rRgJDaF2+N3GC857zjTf00Veto=",
+      "dev": true
+    },
+    "JSONSelect": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/JSONSelect/-/JSONSelect-0.4.0.tgz",
+      "integrity": "sha1-oI7cxn6z/L6Z7WMIVTRKDPKCu40="
+    },
+    "JSV": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/JSV/-/JSV-4.0.2.tgz",
+      "integrity": "sha1-0Hf2glVx+CEy+d/67Vh7QCn+/1c="
+    },
+    "abbrev": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+      "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
+    },
+    "accept-encoding": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/accept-encoding/-/accept-encoding-0.1.0.tgz",
+      "integrity": "sha1-XdiLjfcfHcLlzGuVZezOHjmaMz4="
+    },
+    "accepts": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz",
+      "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=",
+      "requires": {
+        "mime-types": "2.1.18",
+        "negotiator": "0.6.1"
+      }
+    },
+    "acorn": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz",
+      "integrity": "sha512-d+nbxBUGKg7Arpsvbnlq61mc12ek3EY8EQldM3GPAhWJ1UVxC6TDGbIvUMNU6obBX3i1+ptCIzV4vq0gFPEGVQ==",
+      "dev": true
+    },
+    "acorn-jsx": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz",
+      "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=",
+      "dev": true,
+      "requires": {
+        "acorn": "3.3.0"
+      },
+      "dependencies": {
+        "acorn": {
+          "version": "3.3.0",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz",
+          "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=",
+          "dev": true
+        }
+      }
+    },
+    "agent-base": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.0.tgz",
+      "integrity": "sha512-c+R/U5X+2zz2+UCrCFv6odQzJdoqI+YecuhnAJLa1zYaMc13zPfwMwZrr91Pd1DYNo/yPRbiM4WVf9whgwFsIg==",
+      "requires": {
+        "es6-promisify": "5.0.0"
+      }
+    },
+    "ajv": {
+      "version": "4.11.8",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz",
+      "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=",
+      "requires": {
+        "co": "4.6.0",
+        "json-stable-stringify": "1.0.1"
+      }
+    },
+    "ajv-keywords": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz",
+      "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=",
+      "dev": true
+    },
+    "align-text": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
+      "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
+      "requires": {
+        "kind-of": "3.2.2",
+        "longest": "1.0.1",
+        "repeat-string": "1.6.1"
+      }
+    },
+    "amdefine": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
+      "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU="
+    },
+    "ansi-escapes": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz",
+      "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4="
+    },
+    "ansi-regex": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+      "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+    },
+    "ansi-styles": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+      "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
+    },
+    "aproba": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
+      "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
+    },
+    "archiver": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/archiver/-/archiver-1.3.0.tgz",
+      "integrity": "sha1-TyGU1tj5nfP1MeaIHxTxXVX6ryI=",
+      "requires": {
+        "archiver-utils": "1.3.0",
+        "async": "2.2.0",
+        "buffer-crc32": "0.2.13",
+        "glob": "7.1.2",
+        "lodash": "4.17.10",
+        "readable-stream": "2.3.6",
+        "tar-stream": "1.6.1",
+        "walkdir": "0.0.11",
+        "zip-stream": "1.2.0"
+      }
+    },
+    "archiver-utils": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-1.3.0.tgz",
+      "integrity": "sha1-5QtMCccL89aA4y/xt5lOn52JUXQ=",
+      "requires": {
+        "glob": "7.1.2",
+        "graceful-fs": "4.1.11",
+        "lazystream": "1.0.0",
+        "lodash": "4.17.10",
+        "normalize-path": "2.1.1",
+        "readable-stream": "2.3.6"
+      }
+    },
+    "are-we-there-yet": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
+      "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
+      "requires": {
+        "delegates": "1.0.0",
+        "readable-stream": "2.3.6"
+      }
+    },
+    "argparse": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "requires": {
+        "sprintf-js": "1.0.3"
+      }
+    },
+    "array-flatten": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+      "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+    },
+    "array-union": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+      "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
+      "dev": true,
+      "requires": {
+        "array-uniq": "1.0.3"
+      }
+    },
+    "array-uniq": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
+      "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
+      "dev": true
+    },
+    "arrify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+      "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
+      "dev": true
+    },
+    "asn1": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
+      "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y="
+    },
+    "assert-plus": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz",
+      "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ="
+    },
+    "async": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/async/-/async-2.2.0.tgz",
+      "integrity": "sha1-wyTroBCiN+T71VoS3uhjZ9XA7zI=",
+      "requires": {
+        "lodash": "4.17.10"
+      }
+    },
+    "asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
+    },
+    "aws-sign2": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz",
+      "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8="
+    },
+    "aws4": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz",
+      "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w=="
+    },
+    "babel-code-frame": {
+      "version": "6.26.0",
+      "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
+      "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
+      "dev": true,
+      "requires": {
+        "chalk": "1.1.3",
+        "esutils": "2.0.2",
+        "js-tokens": "3.0.2"
+      },
+      "dependencies": {
+        "esutils": {
+          "version": "2.0.2",
+          "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+          "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
+          "dev": true
+        }
+      }
+    },
+    "balanced-match": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+    },
+    "base-x": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.4.tgz",
+      "integrity": "sha512-UYOadoSIkEI/VrRGSG6qp93rp2WdokiAiNYDfGW5qURAY8GiAQkvMbwNNSDYiVJopqv4gCna7xqf4rrNGp+5AA==",
+      "requires": {
+        "safe-buffer": "5.1.2"
+      }
+    },
+    "basic-auth": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz",
+      "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ="
+    },
+    "bcrypt-pbkdf": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+      "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+      "optional": true,
+      "requires": {
+        "tweetnacl": "0.14.3"
+      }
+    },
+    "best-encoding": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/best-encoding/-/best-encoding-0.1.1.tgz",
+      "integrity": "sha1-GVIT2rysBFgYuAe3ox+Dn63cl04=",
+      "requires": {
+        "accept-encoding": "0.1.0"
+      }
+    },
+    "binary": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz",
+      "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=",
+      "requires": {
+        "buffers": "0.1.1",
+        "chainsaw": "0.1.0"
+      }
+    },
+    "bindings": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz",
+      "integrity": "sha1-FK1hE4EtLTfXLme0ystLtyZQXxE="
+    },
+    "bl": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
+      "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
+      "requires": {
+        "readable-stream": "2.3.6",
+        "safe-buffer": "5.1.2"
+      }
+    },
+    "block-stream": {
+      "version": "0.0.9",
+      "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
+      "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=",
+      "requires": {
+        "inherits": "2.0.3"
+      }
+    },
+    "bluebird": {
+      "version": "3.5.1",
+      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
+      "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA=="
+    },
+    "body-parser": {
+      "version": "1.17.1",
+      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.17.1.tgz",
+      "integrity": "sha1-dbO8mN3W5+DY/+dQ36ylxmmT+kc=",
+      "requires": {
+        "bytes": "2.4.0",
+        "content-type": "1.0.4",
+        "debug": "2.6.1",
+        "depd": "1.1.2",
+        "http-errors": "1.6.3",
+        "iconv-lite": "0.4.15",
+        "on-finished": "2.3.0",
+        "qs": "6.4.0",
+        "raw-body": "2.2.0",
+        "type-is": "1.6.16"
+      }
+    },
+    "boom": {
+      "version": "2.10.1",
+      "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
+      "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
+      "requires": {
+        "hoek": "2.16.3"
+      }
+    },
+    "brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "requires": {
+        "balanced-match": "1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "browser-stdout": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz",
+      "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=",
+      "dev": true
+    },
+    "bs58": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
+      "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=",
+      "requires": {
+        "base-x": "3.0.4"
+      }
+    },
+    "buffer-alloc": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
+      "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==",
+      "requires": {
+        "buffer-alloc-unsafe": "1.1.0",
+        "buffer-fill": "1.0.0"
+      }
+    },
+    "buffer-alloc-unsafe": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
+      "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg=="
+    },
+    "buffer-crc32": {
+      "version": "0.2.13",
+      "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+      "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI="
+    },
+    "buffer-fill": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
+      "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw="
+    },
+    "buffer-from": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz",
+      "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==",
+      "dev": true
+    },
+    "buffers": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz",
+      "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s="
+    },
+    "busboy": {
+      "version": "0.2.14",
+      "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz",
+      "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=",
+      "requires": {
+        "dicer": "0.2.5",
+        "readable-stream": "1.1.14"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "0.0.1",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+          "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+        },
+        "readable-stream": {
+          "version": "1.1.14",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
+          "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
+          "requires": {
+            "core-util-is": "1.0.2",
+            "inherits": "2.0.3",
+            "isarray": "0.0.1",
+            "string_decoder": "0.10.31"
+          }
+        },
+        "string_decoder": {
+          "version": "0.10.31",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+          "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+        }
+      }
+    },
+    "bytes": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz",
+      "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk="
+    },
+    "caller-path": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz",
+      "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=",
+      "dev": true,
+      "requires": {
+        "callsites": "0.2.0"
+      }
+    },
+    "callsites": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz",
+      "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=",
+      "dev": true
+    },
+    "camelcase": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
+      "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=",
+      "optional": true
+    },
+    "caseless": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.3.0.tgz",
+      "integrity": "sha1-U06XkWOH07cGtk/eu6xGQ4RQk08="
+    },
+    "center-align": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
+      "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
+      "optional": true,
+      "requires": {
+        "align-text": "0.1.4",
+        "lazy-cache": "1.0.4"
+      }
+    },
+    "chainsaw": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz",
+      "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=",
+      "requires": {
+        "traverse": "0.3.9"
+      },
+      "dependencies": {
+        "traverse": {
+          "version": "0.3.9",
+          "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz",
+          "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk="
+        }
+      }
+    },
+    "chalk": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+      "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+      "requires": {
+        "ansi-styles": "2.2.1",
+        "escape-string-regexp": "1.0.5",
+        "has-ansi": "2.0.0",
+        "strip-ansi": "3.0.1",
+        "supports-color": "2.0.0"
+      }
+    },
+    "chardet": {
+      "version": "0.4.2",
+      "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
+      "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I="
+    },
+    "charenc": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
+      "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc="
+    },
+    "charm": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/charm/-/charm-0.1.2.tgz",
+      "integrity": "sha1-BsIe7RobBq62dVPNxT4jJ0usIpY="
+    },
+    "circular-json": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
+      "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==",
+      "dev": true
+    },
+    "cjson": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/cjson/-/cjson-0.3.0.tgz",
+      "integrity": "sha1-5kObkHA9MS/24iJAl76pLOPQKhQ=",
+      "requires": {
+        "jsonlint": "1.6.0"
+      }
+    },
+    "cli-cursor": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
+      "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
+      "requires": {
+        "restore-cursor": "2.0.0"
+      }
+    },
+    "cli-table": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz",
+      "integrity": "sha1-9TsFJmqLGguTSz0IIebi3FkUriM=",
+      "requires": {
+        "colors": "1.0.3"
+      },
+      "dependencies": {
+        "colors": {
+          "version": "1.0.3",
+          "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
+          "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs="
+        }
+      }
+    },
+    "cli-width": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
+      "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk="
+    },
+    "cliui": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
+      "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=",
+      "optional": true,
+      "requires": {
+        "center-align": "0.1.3",
+        "right-align": "0.1.3",
+        "wordwrap": "0.0.2"
+      },
+      "dependencies": {
+        "wordwrap": {
+          "version": "0.0.2",
+          "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
+          "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=",
+          "optional": true
+        }
+      }
+    },
+    "co": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
+      "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
+    },
+    "code-point-at": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+      "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
+    },
+    "collections": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/collections/-/collections-0.2.2.tgz",
+      "integrity": "sha1-HyMCay7zb5J+7MkB6ZxfDUj6M04=",
+      "requires": {
+        "weak-map": "1.0.0"
+      }
+    },
+    "color-convert": {
+      "version": "1.9.2",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz",
+      "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==",
+      "dev": true,
+      "requires": {
+        "color-name": "1.1.1"
+      }
+    },
+    "color-name": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz",
+      "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=",
+      "dev": true
+    },
+    "colors": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
+      "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM="
+    },
+    "combined-stream": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
+      "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
+      "requires": {
+        "delayed-stream": "1.0.0"
+      }
+    },
+    "commander": {
+      "version": "2.9.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
+      "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=",
+      "requires": {
+        "graceful-readlink": "1.0.1"
+      }
+    },
+    "component-emitter": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
+      "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
+    },
+    "compress-commons": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-1.2.2.tgz",
+      "integrity": "sha1-UkqfEJA/OoEzibAiXSfEi7dRiQ8=",
+      "requires": {
+        "buffer-crc32": "0.2.13",
+        "crc32-stream": "2.0.0",
+        "normalize-path": "2.1.1",
+        "readable-stream": "2.3.6"
+      }
+    },
+    "concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+    },
+    "concat-stream": {
+      "version": "1.6.2",
+      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+      "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+      "dev": true,
+      "requires": {
+        "buffer-from": "1.1.0",
+        "inherits": "2.0.3",
+        "readable-stream": "2.3.6",
+        "typedarray": "0.0.6"
+      }
+    },
+    "connect-busboy": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/connect-busboy/-/connect-busboy-0.0.2.tgz",
+      "integrity": "sha1-rFyclmchcYheV2xmsr/ZXTuxEJc=",
+      "requires": {
+        "busboy": "0.2.14"
+      }
+    },
+    "console-control-strings": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+      "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
+    },
+    "content-disposition": {
+      "version": "0.5.2",
+      "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
+      "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ="
+    },
+    "content-type": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+      "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
+    },
+    "cookie": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
+      "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
+    },
+    "cookie-signature": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+      "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+    },
+    "cookiejar": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz",
+      "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA=="
+    },
+    "core-util-is": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+    },
+    "cors": {
+      "version": "2.8.2",
+      "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.2.tgz",
+      "integrity": "sha1-Omwx9aOYyHOU4xVVtifqNSODkIA=",
+      "requires": {
+        "object-assign": "4.1.1",
+        "vary": "1.1.2"
+      }
+    },
+    "coveralls": {
+      "version": "2.11.4",
+      "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-2.11.4.tgz",
+      "integrity": "sha1-tC9OFW9rqUGdJ0NKQokJTyGSZ/c=",
+      "dev": true,
+      "requires": {
+        "js-yaml": "3.0.1",
+        "lcov-parse": "0.0.6",
+        "log-driver": "1.2.4",
+        "request": "2.40.0"
+      },
+      "dependencies": {
+        "argparse": {
+          "version": "0.1.16",
+          "resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz",
+          "integrity": "sha1-z9AeD7uj1srtBJ+9dY1A9lGW9Xw=",
+          "dev": true,
+          "requires": {
+            "underscore": "1.7.0",
+            "underscore.string": "2.4.0"
+          }
+        },
+        "asn1": {
+          "version": "0.1.11",
+          "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz",
+          "integrity": "sha1-VZvhg3bQik7E2+gId9J4GGObLfc=",
+          "dev": true,
+          "optional": true
+        },
+        "assert-plus": {
+          "version": "0.1.5",
+          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz",
+          "integrity": "sha1-7nQAlBMALYTOxyGcasgRgS5yMWA=",
+          "dev": true,
+          "optional": true
+        },
+        "async": {
+          "version": "0.9.2",
+          "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
+          "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=",
+          "dev": true,
+          "optional": true
+        },
+        "aws-sign2": {
+          "version": "0.5.0",
+          "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz",
+          "integrity": "sha1-xXED96F/wDfwLXwuZLYC6iI/fWM=",
+          "dev": true,
+          "optional": true
+        },
+        "boom": {
+          "version": "0.4.2",
+          "resolved": "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz",
+          "integrity": "sha1-emNune1O/O+xnO9JR6PGffrukRs=",
+          "dev": true,
+          "requires": {
+            "hoek": "0.9.1"
+          }
+        },
+        "combined-stream": {
+          "version": "0.0.7",
+          "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz",
+          "integrity": "sha1-ATfmV7qlp1QcV6w3rF/AfXO03B8=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "delayed-stream": "0.0.5"
+          }
+        },
+        "cryptiles": {
+          "version": "0.2.2",
+          "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz",
+          "integrity": "sha1-7ZH/HxetE9N0gohZT4pIoNJvMlw=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "boom": "0.4.2"
+          }
+        },
+        "delayed-stream": {
+          "version": "0.0.5",
+          "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz",
+          "integrity": "sha1-1LH0OpPoKW3+AmlPRoC8N6MTxz8=",
+          "dev": true,
+          "optional": true
+        },
+        "esprima": {
+          "version": "1.0.4",
+          "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz",
+          "integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0=",
+          "dev": true
+        },
+        "forever-agent": {
+          "version": "0.5.2",
+          "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz",
+          "integrity": "sha1-bQ4JxJIflKJ/Y9O0nF/v8epMUTA=",
+          "dev": true
+        },
+        "form-data": {
+          "version": "0.1.4",
+          "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz",
+          "integrity": "sha1-kavXiKupcCsaq/qLwBAxoqyeOxI=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "async": "0.9.2",
+            "combined-stream": "0.0.7",
+            "mime": "1.2.11"
+          }
+        },
+        "hawk": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/hawk/-/hawk-1.1.1.tgz",
+          "integrity": "sha1-h81JH5tG5OKurKM1QWdmiF0tHtk=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "boom": "0.4.2",
+            "cryptiles": "0.2.2",
+            "hoek": "0.9.1",
+            "sntp": "0.2.4"
+          }
+        },
+        "hoek": {
+          "version": "0.9.1",
+          "resolved": "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz",
+          "integrity": "sha1-PTIkYrrfB3Fup+uFuviAec3c5QU=",
+          "dev": true
+        },
+        "http-signature": {
+          "version": "0.10.1",
+          "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz",
+          "integrity": "sha1-T72sEyVZqoMjEh5UB3nAoBKyfmY=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "asn1": "0.1.11",
+            "assert-plus": "0.1.5",
+            "ctype": "0.5.3"
+          }
+        },
+        "js-yaml": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.0.1.tgz",
+          "integrity": "sha1-dkBf6lvOMPyPQF1Ixtyn8KMsav4=",
+          "dev": true,
+          "requires": {
+            "argparse": "0.1.16",
+            "esprima": "1.0.4"
+          }
+        },
+        "mime-types": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz",
+          "integrity": "sha1-mVrhOSq4r/y/yyZB3QVOlDwNXc4=",
+          "dev": true
+        },
+        "oauth-sign": {
+          "version": "0.3.0",
+          "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz",
+          "integrity": "sha1-y1QPk7srIqfVlBaRoojWDo6pOG4=",
+          "dev": true,
+          "optional": true
+        },
+        "qs": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-1.0.2.tgz",
+          "integrity": "sha1-UKk+K1r2aRwxvOpdrnjubqGQN2g=",
+          "dev": true
+        },
+        "request": {
+          "version": "2.40.0",
+          "resolved": "https://registry.npmjs.org/request/-/request-2.40.0.tgz",
+          "integrity": "sha1-TdZw9pbx5uhC5mtLXoOTAaub62c=",
+          "dev": true,
+          "requires": {
+            "aws-sign2": "0.5.0",
+            "forever-agent": "0.5.2",
+            "form-data": "0.1.4",
+            "hawk": "1.1.1",
+            "http-signature": "0.10.1",
+            "json-stringify-safe": "5.0.1",
+            "mime-types": "1.0.2",
+            "node-uuid": "1.4.8",
+            "oauth-sign": "0.3.0",
+            "qs": "1.0.2",
+            "stringstream": "0.0.6",
+            "tough-cookie": "2.3.4",
+            "tunnel-agent": "0.4.3"
+          }
+        },
+        "sntp": {
+          "version": "0.2.4",
+          "resolved": "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz",
+          "integrity": "sha1-+4hfGLDzqtGJ+CSGJTa87ux1CQA=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "hoek": "0.9.1"
+          }
+        },
+        "tunnel-agent": {
+          "version": "0.4.3",
+          "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz",
+          "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=",
+          "dev": true,
+          "optional": true
+        },
+        "underscore": {
+          "version": "1.7.0",
+          "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz",
+          "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=",
+          "dev": true
+        }
+      }
+    },
+    "crc": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/crc/-/crc-3.5.0.tgz",
+      "integrity": "sha1-mLi6fUiWZbo5efWbITgTdBAaGWQ="
+    },
+    "crc32-stream": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-2.0.0.tgz",
+      "integrity": "sha1-483TtN8xaN10494/u8t7KX/pCPQ=",
+      "requires": {
+        "crc": "3.5.0",
+        "readable-stream": "2.3.6"
+      }
+    },
+    "crypt": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
+      "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs="
+    },
+    "cryptiles": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
+      "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=",
+      "requires": {
+        "boom": "2.10.1"
+      }
+    },
+    "ctype": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz",
+      "integrity": "sha1-gsGMJGH3QRTvFsE1IkrQuRRMoS8=",
+      "dev": true,
+      "optional": true
+    },
+    "cycle": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz",
+      "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI="
+    },
+    "d": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz",
+      "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
+      "dev": true,
+      "requires": {
+        "es5-ext": "0.10.45"
+      }
+    },
+    "daemonize2": {
+      "version": "0.4.2",
+      "resolved": "https://registry.npmjs.org/daemonize2/-/daemonize2-0.4.2.tgz",
+      "integrity": "sha1-xuR0B4vs+n16gUACUUxHEvZP4G8="
+    },
+    "dashdash": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+      "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+      "requires": {
+        "assert-plus": "1.0.0"
+      },
+      "dependencies": {
+        "assert-plus": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+          "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+        }
+      }
+    },
+    "ddos": {
+      "version": "0.1.16",
+      "resolved": "https://registry.npmjs.org/ddos/-/ddos-0.1.16.tgz",
+      "integrity": "sha1-RcfMd+vNP3pBpQDSPZbb6yvKNMk=",
+      "requires": {
+        "hashish": "0.0.4",
+        "response": "0.18.0"
+      }
+    },
+    "debug": {
+      "version": "2.6.1",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.1.tgz",
+      "integrity": "sha1-eYVQkLosTjEVzH2HaUkdWPBJE1E=",
+      "requires": {
+        "ms": "0.7.2"
+      }
+    },
+    "decamelize": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+      "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+      "optional": true
+    },
+    "deep-extend": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+      "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
+    },
+    "deep-is": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+      "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
+      "dev": true
+    },
+    "del": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz",
+      "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=",
+      "dev": true,
+      "requires": {
+        "globby": "5.0.0",
+        "is-path-cwd": "1.0.0",
+        "is-path-in-cwd": "1.0.1",
+        "object-assign": "4.1.1",
+        "pify": "2.3.0",
+        "pinkie-promise": "2.0.1",
+        "rimraf": "2.6.2"
+      }
+    },
+    "delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
+    },
+    "delegates": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+      "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
+    },
+    "depd": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+      "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
+    },
+    "destroy": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+      "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
+    },
+    "dicer": {
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz",
+      "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=",
+      "requires": {
+        "readable-stream": "1.1.14",
+        "streamsearch": "0.1.2"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "0.0.1",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+          "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+        },
+        "readable-stream": {
+          "version": "1.1.14",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
+          "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
+          "requires": {
+            "core-util-is": "1.0.2",
+            "inherits": "2.0.3",
+            "isarray": "0.0.1",
+            "string_decoder": "0.10.31"
+          }
+        },
+        "string_decoder": {
+          "version": "0.10.31",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+          "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+        }
+      }
+    },
+    "diff": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz",
+      "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=",
+      "dev": true
+    },
+    "doctrine": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz",
+      "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=",
+      "dev": true,
+      "requires": {
+        "esutils": "2.0.2",
+        "isarray": "1.0.0"
+      },
+      "dependencies": {
+        "esutils": {
+          "version": "2.0.2",
+          "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+          "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
+          "dev": true
+        }
+      }
+    },
+    "duplexer": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
+      "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E="
+    },
+    "ebnf-parser": {
+      "version": "0.1.10",
+      "resolved": "https://registry.npmjs.org/ebnf-parser/-/ebnf-parser-0.1.10.tgz",
+      "integrity": "sha1-zR9rpHfFY4xAyX7ZtXLbW6tdgzE="
+    },
+    "ecc-jsbn": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
+      "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
+      "optional": true,
+      "requires": {
+        "jsbn": "0.1.1"
+      }
+    },
+    "ee-first": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+      "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+    },
+    "encodeurl": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+      "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
+    },
+    "end-of-stream": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
+      "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
+      "requires": {
+        "once": "1.4.0"
+      }
+    },
+    "errorhandler": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/errorhandler/-/errorhandler-1.5.0.tgz",
+      "integrity": "sha1-6rpkyl1UKjEayUX1gt78M2Fl2fQ=",
+      "requires": {
+        "accepts": "1.3.5",
+        "escape-html": "1.0.3"
+      }
+    },
+    "es5-ext": {
+      "version": "0.10.45",
+      "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.45.tgz",
+      "integrity": "sha512-FkfM6Vxxfmztilbxxz5UKSD4ICMf5tSpRFtDNtkAhOxZ0EKtX6qwmXNyH/sFyIbX2P/nU5AMiA9jilWsUGJzCQ==",
+      "dev": true,
+      "requires": {
+        "es6-iterator": "2.0.3",
+        "es6-symbol": "3.1.1",
+        "next-tick": "1.0.0"
+      }
+    },
+    "es6-iterator": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+      "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
+      "dev": true,
+      "requires": {
+        "d": "1.0.0",
+        "es5-ext": "0.10.45",
+        "es6-symbol": "3.1.1"
+      }
+    },
+    "es6-map": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz",
+      "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=",
+      "dev": true,
+      "requires": {
+        "d": "1.0.0",
+        "es5-ext": "0.10.45",
+        "es6-iterator": "2.0.3",
+        "es6-set": "0.1.5",
+        "es6-symbol": "3.1.1",
+        "event-emitter": "0.3.5"
+      }
+    },
+    "es6-promise": {
+      "version": "4.2.4",
+      "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz",
+      "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ=="
+    },
+    "es6-promisify": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
+      "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
+      "requires": {
+        "es6-promise": "4.2.4"
+      }
+    },
+    "es6-set": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz",
+      "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=",
+      "dev": true,
+      "requires": {
+        "d": "1.0.0",
+        "es5-ext": "0.10.45",
+        "es6-iterator": "2.0.3",
+        "es6-symbol": "3.1.1",
+        "event-emitter": "0.3.5"
+      }
+    },
+    "es6-symbol": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz",
+      "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=",
+      "dev": true,
+      "requires": {
+        "d": "1.0.0",
+        "es5-ext": "0.10.45"
+      }
+    },
+    "es6-weak-map": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz",
+      "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=",
+      "dev": true,
+      "requires": {
+        "d": "1.0.0",
+        "es5-ext": "0.10.45",
+        "es6-iterator": "2.0.3",
+        "es6-symbol": "3.1.1"
+      }
+    },
+    "escape-html": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+      "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+    },
+    "escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
+    },
+    "escodegen": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.3.3.tgz",
+      "integrity": "sha1-8CQBb1qI4Eb9EgBQVek5gC5sXyM=",
+      "requires": {
+        "esprima": "1.1.1",
+        "estraverse": "1.5.1",
+        "esutils": "1.0.0",
+        "source-map": "0.1.43"
+      }
+    },
+    "escope": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz",
+      "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=",
+      "dev": true,
+      "requires": {
+        "es6-map": "0.1.5",
+        "es6-weak-map": "2.0.2",
+        "esrecurse": "4.2.1",
+        "estraverse": "4.2.0"
+      },
+      "dependencies": {
+        "estraverse": {
+          "version": "4.2.0",
+          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
+          "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=",
+          "dev": true
+        }
+      }
+    },
+    "eslint": {
+      "version": "3.13.1",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.13.1.tgz",
+      "integrity": "sha1-Vk0mRrXv3thd+WmFMy7dkaI7/yU=",
+      "dev": true,
+      "requires": {
+        "babel-code-frame": "6.26.0",
+        "chalk": "1.1.3",
+        "concat-stream": "1.6.2",
+        "debug": "2.6.1",
+        "doctrine": "1.5.0",
+        "escope": "3.6.0",
+        "espree": "3.5.4",
+        "estraverse": "4.2.0",
+        "esutils": "2.0.2",
+        "file-entry-cache": "2.0.0",
+        "glob": "7.1.2",
+        "globals": "9.18.0",
+        "ignore": "3.3.10",
+        "imurmurhash": "0.1.4",
+        "inquirer": "0.12.0",
+        "is-my-json-valid": "2.17.2",
+        "is-resolvable": "1.1.0",
+        "js-yaml": "3.8.2",
+        "json-stable-stringify": "1.0.1",
+        "levn": "0.3.0",
+        "lodash": "4.17.10",
+        "mkdirp": "0.5.1",
+        "natural-compare": "1.4.0",
+        "optionator": "0.8.2",
+        "path-is-inside": "1.0.2",
+        "pluralize": "1.2.1",
+        "progress": "1.1.8",
+        "require-uncached": "1.0.3",
+        "shelljs": "0.7.8",
+        "strip-bom": "3.0.0",
+        "strip-json-comments": "2.0.1",
+        "table": "3.8.3",
+        "text-table": "0.2.0",
+        "user-home": "2.0.0"
+      },
+      "dependencies": {
+        "cli-cursor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz",
+          "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=",
+          "dev": true,
+          "requires": {
+            "restore-cursor": "1.0.1"
+          }
+        },
+        "estraverse": {
+          "version": "4.2.0",
+          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
+          "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=",
+          "dev": true
+        },
+        "esutils": {
+          "version": "2.0.2",
+          "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+          "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
+          "dev": true
+        },
+        "figures": {
+          "version": "1.7.0",
+          "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
+          "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=",
+          "dev": true,
+          "requires": {
+            "escape-string-regexp": "1.0.5",
+            "object-assign": "4.1.1"
+          }
+        },
+        "inquirer": {
+          "version": "0.12.0",
+          "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz",
+          "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=",
+          "dev": true,
+          "requires": {
+            "ansi-escapes": "1.4.0",
+            "ansi-regex": "2.1.1",
+            "chalk": "1.1.3",
+            "cli-cursor": "1.0.2",
+            "cli-width": "2.2.0",
+            "figures": "1.7.0",
+            "lodash": "4.17.10",
+            "readline2": "1.0.1",
+            "run-async": "0.1.0",
+            "rx-lite": "3.1.2",
+            "string-width": "1.0.2",
+            "strip-ansi": "3.0.1",
+            "through": "2.3.8"
+          }
+        },
+        "is-fullwidth-code-point": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+          "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+          "dev": true,
+          "requires": {
+            "number-is-nan": "1.0.1"
+          }
+        },
+        "onetime": {
+          "version": "1.1.0",
+          "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz",
+          "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=",
+          "dev": true
+        },
+        "progress": {
+          "version": "1.1.8",
+          "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz",
+          "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=",
+          "dev": true
+        },
+        "restore-cursor": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz",
+          "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=",
+          "dev": true,
+          "requires": {
+            "exit-hook": "1.1.1",
+            "onetime": "1.1.0"
+          }
+        },
+        "run-async": {
+          "version": "0.1.0",
+          "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz",
+          "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=",
+          "dev": true,
+          "requires": {
+            "once": "1.4.0"
+          }
+        },
+        "shelljs": {
+          "version": "0.7.8",
+          "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz",
+          "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=",
+          "dev": true,
+          "requires": {
+            "glob": "7.1.2",
+            "interpret": "1.1.0",
+            "rechoir": "0.6.2"
+          }
+        },
+        "string-width": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+          "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+          "dev": true,
+          "requires": {
+            "code-point-at": "1.1.0",
+            "is-fullwidth-code-point": "1.0.0",
+            "strip-ansi": "3.0.1"
+          }
+        }
+      }
+    },
+    "eslint-plugin-mocha": {
+      "version": "4.8.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-4.8.0.tgz",
+      "integrity": "sha1-diezWmHlpyBBLaluqwbw4DodzbY=",
+      "dev": true,
+      "requires": {
+        "ramda": "0.22.1"
+      }
+    },
+    "espree": {
+      "version": "3.5.4",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz",
+      "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==",
+      "dev": true,
+      "requires": {
+        "acorn": "5.7.1",
+        "acorn-jsx": "3.0.1"
+      }
+    },
+    "esprima": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.1.1.tgz",
+      "integrity": "sha1-W28VR/TRAuZw4UDFCb5ncdautUk="
+    },
+    "esrecurse": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
+      "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
+      "dev": true,
+      "requires": {
+        "estraverse": "4.2.0"
+      },
+      "dependencies": {
+        "estraverse": {
+          "version": "4.2.0",
+          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
+          "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=",
+          "dev": true
+        }
+      }
+    },
+    "estraverse": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.5.1.tgz",
+      "integrity": "sha1-hno+jlip+EYYr7bC3bzZFrfLr3E="
+    },
+    "estraverse-fb": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/estraverse-fb/-/estraverse-fb-1.3.2.tgz",
+      "integrity": "sha1-0yOky15awzHOoDNBOpJT4WQ+B8Q=",
+      "dev": true
+    },
+    "esutils": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.0.0.tgz",
+      "integrity": "sha1-gVHTWOIMisx/t0XnRywAJf5JZXA="
+    },
+    "etag": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+      "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
+    },
+    "event-emitter": {
+      "version": "0.3.5",
+      "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
+      "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=",
+      "dev": true,
+      "requires": {
+        "d": "1.0.0",
+        "es5-ext": "0.10.45"
+      }
+    },
+    "event-stream": {
+      "version": "3.3.4",
+      "resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz",
+      "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=",
+      "requires": {
+        "duplexer": "0.1.1",
+        "from": "0.1.7",
+        "map-stream": "0.1.0",
+        "pause-stream": "0.0.11",
+        "split": "0.3.3",
+        "stream-combiner": "0.0.4",
+        "through": "2.3.8"
+      }
+    },
+    "exit-hook": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz",
+      "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=",
+      "dev": true
+    },
+    "express": {
+      "version": "4.15.2",
+      "resolved": "https://registry.npmjs.org/express/-/express-4.15.2.tgz",
+      "integrity": "sha1-rxB/wUhQRFfy3Kmm8lcdcSm5ezU=",
+      "requires": {
+        "accepts": "1.3.5",
+        "array-flatten": "1.1.1",
+        "content-disposition": "0.5.2",
+        "content-type": "1.0.4",
+        "cookie": "0.3.1",
+        "cookie-signature": "1.0.6",
+        "debug": "2.6.1",
+        "depd": "1.1.2",
+        "encodeurl": "1.0.2",
+        "escape-html": "1.0.3",
+        "etag": "1.8.1",
+        "finalhandler": "1.0.6",
+        "fresh": "0.5.0",
+        "merge-descriptors": "1.0.1",
+        "methods": "1.1.2",
+        "on-finished": "2.3.0",
+        "parseurl": "1.3.2",
+        "path-to-regexp": "0.1.7",
+        "proxy-addr": "1.1.5",
+        "qs": "6.4.0",
+        "range-parser": "1.2.0",
+        "send": "0.15.1",
+        "serve-static": "1.12.1",
+        "setprototypeof": "1.0.3",
+        "statuses": "1.3.1",
+        "type-is": "1.6.16",
+        "utils-merge": "1.0.0",
+        "vary": "1.1.2"
+      },
+      "dependencies": {
+        "setprototypeof": {
+          "version": "1.0.3",
+          "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz",
+          "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ="
+        },
+        "statuses": {
+          "version": "1.3.1",
+          "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz",
+          "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4="
+        }
+      }
+    },
+    "express-fileupload": {
+      "version": "0.0.5",
+      "resolved": "https://registry.npmjs.org/express-fileupload/-/express-fileupload-0.0.5.tgz",
+      "integrity": "sha1-QzpxJSWvqYtMkxYlIui/ecaNguc=",
+      "requires": {
+        "connect-busboy": "0.0.2",
+        "fs-extra": "0.22.1",
+        "streamifier": "0.1.1"
+      }
+    },
+    "extend": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
+      "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ="
+    },
+    "external-editor": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
+      "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==",
+      "requires": {
+        "chardet": "0.4.2",
+        "iconv-lite": "0.4.23",
+        "tmp": "0.0.33"
+      },
+      "dependencies": {
+        "iconv-lite": {
+          "version": "0.4.23",
+          "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
+          "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
+          "requires": {
+            "safer-buffer": "2.1.2"
+          }
+        },
+        "tmp": {
+          "version": "0.0.33",
+          "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+          "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+          "requires": {
+            "os-tmpdir": "1.0.2"
+          }
+        }
+      }
+    },
+    "extsprintf": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+      "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
+    },
+    "eyes": {
+      "version": "0.1.8",
+      "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz",
+      "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A="
+    },
+    "fast-levenshtein": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+      "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+      "dev": true
+    },
+    "figures": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
+      "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
+      "requires": {
+        "escape-string-regexp": "1.0.5"
+      }
+    },
+    "file-entry-cache": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz",
+      "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=",
+      "dev": true,
+      "requires": {
+        "flat-cache": "1.3.0",
+        "object-assign": "4.1.1"
+      }
+    },
+    "finalhandler": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.6.tgz",
+      "integrity": "sha1-AHrqM9Gk0+QgF/YkhIrVjSEvgU8=",
+      "requires": {
+        "debug": "2.6.9",
+        "encodeurl": "1.0.2",
+        "escape-html": "1.0.3",
+        "on-finished": "2.3.0",
+        "parseurl": "1.3.2",
+        "statuses": "1.3.1",
+        "unpipe": "1.0.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+        },
+        "statuses": {
+          "version": "1.3.1",
+          "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz",
+          "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4="
+        }
+      }
+    },
+    "flat-cache": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz",
+      "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=",
+      "dev": true,
+      "requires": {
+        "circular-json": "0.3.3",
+        "del": "2.2.2",
+        "graceful-fs": "4.1.11",
+        "write": "0.2.1"
+      }
+    },
+    "forever-agent": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+      "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
+    },
+    "form-data": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz",
+      "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=",
+      "requires": {
+        "asynckit": "0.4.0",
+        "combined-stream": "1.0.6",
+        "mime-types": "2.1.18"
+      }
+    },
+    "formidable": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz",
+      "integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg=="
+    },
+    "forwarded": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
+      "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
+    },
+    "fresh": {
+      "version": "0.5.0",
+      "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.0.tgz",
+      "integrity": "sha1-9HTKXmqSRtb9jglTz6m5yAWvp44="
+    },
+    "from": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz",
+      "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4="
+    },
+    "fs-constants": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+      "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
+    },
+    "fs-extra": {
+      "version": "0.22.1",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.22.1.tgz",
+      "integrity": "sha1-X9b4BJ3JdsoZ6yNV1lgXPKvM4FY=",
+      "requires": {
+        "graceful-fs": "4.1.11",
+        "jsonfile": "2.4.0",
+        "rimraf": "2.6.2"
+      }
+    },
+    "fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+    },
+    "fstream": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz",
+      "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=",
+      "requires": {
+        "graceful-fs": "4.1.11",
+        "inherits": "2.0.3",
+        "mkdirp": "0.5.1",
+        "rimraf": "2.6.2"
+      }
+    },
+    "fstream-ignore": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz",
+      "integrity": "sha1-nDHa40dnAY/h0kmyTa2mfQktoQU=",
+      "requires": {
+        "fstream": "1.0.11",
+        "inherits": "2.0.3",
+        "minimatch": "3.0.4"
+      }
+    },
+    "gauge": {
+      "version": "2.7.4",
+      "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
+      "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+      "requires": {
+        "aproba": "1.2.0",
+        "console-control-strings": "1.1.0",
+        "has-unicode": "2.0.1",
+        "object-assign": "4.1.1",
+        "signal-exit": "3.0.2",
+        "string-width": "1.0.2",
+        "strip-ansi": "3.0.1",
+        "wide-align": "1.1.3"
+      },
+      "dependencies": {
+        "is-fullwidth-code-point": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+          "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+          "requires": {
+            "number-is-nan": "1.0.1"
+          }
+        },
+        "string-width": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+          "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+          "requires": {
+            "code-point-at": "1.1.0",
+            "is-fullwidth-code-point": "1.0.0",
+            "strip-ansi": "3.0.1"
+          }
+        }
+      }
+    },
+    "generate-function": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz",
+      "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=",
+      "dev": true
+    },
+    "generate-object-property": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
+      "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=",
+      "dev": true,
+      "requires": {
+        "is-property": "1.0.2"
+      }
+    },
+    "getpass": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+      "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+      "requires": {
+        "assert-plus": "1.0.0"
+      },
+      "dependencies": {
+        "assert-plus": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+          "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+        }
+      }
+    },
+    "glob": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+      "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+      "requires": {
+        "fs.realpath": "1.0.0",
+        "inflight": "1.0.6",
+        "inherits": "2.0.3",
+        "minimatch": "3.0.4",
+        "once": "1.4.0",
+        "path-is-absolute": "1.0.1"
+      }
+    },
+    "globals": {
+      "version": "9.18.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
+      "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==",
+      "dev": true
+    },
+    "globby": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz",
+      "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=",
+      "dev": true,
+      "requires": {
+        "array-union": "1.0.2",
+        "arrify": "1.0.1",
+        "glob": "7.1.2",
+        "object-assign": "4.1.1",
+        "pify": "2.3.0",
+        "pinkie-promise": "2.0.1"
+      }
+    },
+    "graceful-fs": {
+      "version": "4.1.11",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
+      "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
+    },
+    "graceful-readlink": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
+      "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU="
+    },
+    "growl": {
+      "version": "1.9.2",
+      "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz",
+      "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=",
+      "dev": true
+    },
+    "handlebars": {
+      "version": "4.0.11",
+      "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz",
+      "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=",
+      "requires": {
+        "async": "1.5.2",
+        "optimist": "0.6.1",
+        "source-map": "0.4.4",
+        "uglify-js": "2.8.29"
+      },
+      "dependencies": {
+        "async": {
+          "version": "1.5.2",
+          "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+          "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
+        },
+        "source-map": {
+          "version": "0.4.4",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
+          "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
+          "requires": {
+            "amdefine": "1.0.1"
+          }
+        }
+      }
+    },
+    "har-schema": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz",
+      "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4="
+    },
+    "har-validator": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz",
+      "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=",
+      "requires": {
+        "ajv": "4.11.8",
+        "har-schema": "1.0.5"
+      }
+    },
+    "has-ansi": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+      "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+      "requires": {
+        "ansi-regex": "2.1.1"
+      }
+    },
+    "has-flag": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+      "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+      "dev": true
+    },
+    "has-unicode": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+      "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
+    },
+    "hashish": {
+      "version": "0.0.4",
+      "resolved": "https://registry.npmjs.org/hashish/-/hashish-0.0.4.tgz",
+      "integrity": "sha1-bWC8b/r3Ebav1g5CbQd5iAFOZVQ=",
+      "requires": {
+        "traverse": "0.6.6"
+      }
+    },
+    "hawk": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
+      "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=",
+      "requires": {
+        "boom": "2.10.1",
+        "cryptiles": "2.0.5",
+        "hoek": "2.16.3",
+        "sntp": "1.0.9"
+      }
+    },
+    "he": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
+      "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=",
+      "dev": true
+    },
+    "highlight.js": {
+      "version": "9.12.0",
+      "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.12.0.tgz",
+      "integrity": "sha1-5tnb5Xy+/mB1HwKvM2GVhwyQwB4="
+    },
+    "hoek": {
+      "version": "2.16.3",
+      "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
+      "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0="
+    },
+    "homedir-polyfill": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz",
+      "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=",
+      "dev": true,
+      "requires": {
+        "parse-passwd": "1.0.0"
+      }
+    },
+    "http-errors": {
+      "version": "1.6.3",
+      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
+      "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
+      "requires": {
+        "depd": "1.1.2",
+        "inherits": "2.0.3",
+        "setprototypeof": "1.1.0",
+        "statuses": "1.5.0"
+      }
+    },
+    "http-signature": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz",
+      "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=",
+      "requires": {
+        "assert-plus": "0.2.0",
+        "jsprim": "1.4.1",
+        "sshpk": "1.14.2"
+      }
+    },
+    "iconv-lite": {
+      "version": "0.4.15",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz",
+      "integrity": "sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es="
+    },
+    "ignore": {
+      "version": "3.3.10",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz",
+      "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==",
+      "dev": true
+    },
+    "imurmurhash": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+      "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+      "dev": true
+    },
+    "inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+      "requires": {
+        "once": "1.4.0",
+        "wrappy": "1.0.2"
+      }
+    },
+    "inherits": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+      "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+    },
+    "ini": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+      "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
+    },
+    "inquirer": {
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.0.6.tgz",
+      "integrity": "sha1-4EqqnQW3o8ubD0B9BDdfBEcZA0c=",
+      "requires": {
+        "ansi-escapes": "1.4.0",
+        "chalk": "1.1.3",
+        "cli-cursor": "2.1.0",
+        "cli-width": "2.2.0",
+        "external-editor": "2.2.0",
+        "figures": "2.0.0",
+        "lodash": "4.17.10",
+        "mute-stream": "0.0.7",
+        "run-async": "2.3.0",
+        "rx": "4.1.0",
+        "string-width": "2.1.1",
+        "strip-ansi": "3.0.1",
+        "through": "2.3.8"
+      }
+    },
+    "interpret": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz",
+      "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ="
+    },
+    "ip": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
+      "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo="
+    },
+    "ipaddr.js": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.4.0.tgz",
+      "integrity": "sha1-KWrKh4qCGBbluF0KKFqZvP9FgvA="
+    },
+    "is-buffer": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
+    },
+    "is-fullwidth-code-point": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+      "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+    },
+    "is-my-ip-valid": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz",
+      "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==",
+      "dev": true
+    },
+    "is-my-json-valid": {
+      "version": "2.17.2",
+      "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz",
+      "integrity": "sha512-IBhBslgngMQN8DDSppmgDv7RNrlFotuuDsKcrCP3+HbFaVivIBU7u9oiiErw8sH4ynx3+gOGQ3q2otkgiSi6kg==",
+      "dev": true,
+      "requires": {
+        "generate-function": "2.0.0",
+        "generate-object-property": "1.2.0",
+        "is-my-ip-valid": "1.0.0",
+        "jsonpointer": "4.0.1",
+        "xtend": "4.0.1"
+      }
+    },
+    "is-path-cwd": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz",
+      "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=",
+      "dev": true
+    },
+    "is-path-in-cwd": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz",
+      "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==",
+      "dev": true,
+      "requires": {
+        "is-path-inside": "1.0.1"
+      }
+    },
+    "is-path-inside": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz",
+      "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=",
+      "dev": true,
+      "requires": {
+        "path-is-inside": "1.0.2"
+      }
+    },
+    "is-promise": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
+      "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o="
+    },
+    "is-property": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
+      "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=",
+      "dev": true
+    },
+    "is-resolvable": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz",
+      "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==",
+      "dev": true
+    },
+    "is-typedarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+      "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
+    },
+    "isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+    },
+    "isstream": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+      "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
+    },
+    "jison": {
+      "version": "0.4.17",
+      "resolved": "https://registry.npmjs.org/jison/-/jison-0.4.17.tgz",
+      "integrity": "sha1-vBLUbFhF5v7onM81vSqMxz66F/M=",
+      "requires": {
+        "JSONSelect": "0.4.0",
+        "cjson": "0.3.0",
+        "ebnf-parser": "0.1.10",
+        "escodegen": "1.3.3",
+        "esprima": "1.1.1",
+        "jison-lex": "0.3.4",
+        "lex-parser": "0.1.4",
+        "nomnom": "1.5.2"
+      }
+    },
+    "jison-lex": {
+      "version": "0.3.4",
+      "resolved": "https://registry.npmjs.org/jison-lex/-/jison-lex-0.3.4.tgz",
+      "integrity": "sha1-gcoo2E+ESZ36jFlNzePYo/Jux6U=",
+      "requires": {
+        "lex-parser": "0.1.4",
+        "nomnom": "1.5.2"
+      }
+    },
+    "js-tokens": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
+      "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
+      "dev": true
+    },
+    "js-yaml": {
+      "version": "3.8.2",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.2.tgz",
+      "integrity": "sha1-AtPiwPa+qyAkjUEsNSIDgn14ZyE=",
+      "requires": {
+        "argparse": "1.0.10",
+        "esprima": "3.1.3"
+      },
+      "dependencies": {
+        "esprima": {
+          "version": "3.1.3",
+          "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz",
+          "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM="
+        }
+      }
+    },
+    "jsbn": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+      "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+      "optional": true
+    },
+    "json-schema": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+      "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
+    },
+    "json-stable-stringify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
+      "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
+      "requires": {
+        "jsonify": "0.0.0"
+      }
+    },
+    "json-stringify-safe": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+      "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
+    },
+    "json3": {
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz",
+      "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=",
+      "dev": true
+    },
+    "jsonfile": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
+      "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=",
+      "requires": {
+        "graceful-fs": "4.1.11"
+      }
+    },
+    "jsonify": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
+      "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM="
+    },
+    "jsonlint": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/jsonlint/-/jsonlint-1.6.0.tgz",
+      "integrity": "sha1-iKpGvCiaesk7tGyuLVihh6m7SUo=",
+      "requires": {
+        "JSV": "4.0.2",
+        "nomnom": "1.5.2"
+      }
+    },
+    "jsonpointer": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz",
+      "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=",
+      "dev": true
+    },
+    "jsprim": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+      "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+      "requires": {
+        "assert-plus": "1.0.0",
+        "extsprintf": "1.3.0",
+        "json-schema": "0.2.3",
+        "verror": "1.10.0"
+      },
+      "dependencies": {
+        "assert-plus": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+          "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+        }
+      }
+    },
+    "kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+      "requires": {
+        "is-buffer": "1.1.6"
+      }
+    },
+    "lazy-cache": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
+      "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=",
+      "optional": true
+    },
+    "lazystream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz",
+      "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=",
+      "requires": {
+        "readable-stream": "2.3.6"
+      }
+    },
+    "lcov-parse": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.6.tgz",
+      "integrity": "sha1-gZ5dqL8HkfnT857qXtGGgYfxEXU=",
+      "dev": true
+    },
+    "levn": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+      "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+      "dev": true,
+      "requires": {
+        "prelude-ls": "1.1.2",
+        "type-check": "0.3.2"
+      }
+    },
+    "lex-parser": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/lex-parser/-/lex-parser-0.1.4.tgz",
+      "integrity": "sha1-ZMTwJfF/1Tv7RXY/rrFvAVp0dVA="
+    },
+    "lodash": {
+      "version": "4.17.10",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
+      "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg=="
+    },
+    "lodash._baseassign": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz",
+      "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=",
+      "dev": true,
+      "requires": {
+        "lodash._basecopy": "3.0.1",
+        "lodash.keys": "3.1.2"
+      }
+    },
+    "lodash._basecopy": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz",
+      "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=",
+      "dev": true
+    },
+    "lodash._basecreate": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz",
+      "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=",
+      "dev": true
+    },
+    "lodash._getnative": {
+      "version": "3.9.1",
+      "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz",
+      "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=",
+      "dev": true
+    },
+    "lodash._isiterateecall": {
+      "version": "3.0.9",
+      "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz",
+      "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=",
+      "dev": true
+    },
+    "lodash.create": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz",
+      "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=",
+      "dev": true,
+      "requires": {
+        "lodash._baseassign": "3.2.0",
+        "lodash._basecreate": "3.0.3",
+        "lodash._isiterateecall": "3.0.9"
+      }
+    },
+    "lodash.isarguments": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
+      "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=",
+      "dev": true
+    },
+    "lodash.isarray": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz",
+      "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=",
+      "dev": true
+    },
+    "lodash.keys": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz",
+      "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=",
+      "dev": true,
+      "requires": {
+        "lodash._getnative": "3.9.1",
+        "lodash.isarguments": "3.1.0",
+        "lodash.isarray": "3.0.4"
+      }
+    },
+    "log-driver": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.4.tgz",
+      "integrity": "sha1-LWLX+u9F2KcTQZYaBLB2HsqZz6M=",
+      "dev": true
+    },
+    "lokijs": {
+      "version": "1.5.5",
+      "resolved": "https://registry.npmjs.org/lokijs/-/lokijs-1.5.5.tgz",
+      "integrity": "sha1-HCH4KvdXkDf63nueSBNIXCNwi7Y="
+    },
+    "longest": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
+      "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc="
+    },
+    "make-error": {
+      "version": "1.3.4",
+      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.4.tgz",
+      "integrity": "sha512-0Dab5btKVPhibSalc9QGXb559ED7G7iLjFXBaj9Wq8O3vorueR5K5jaE3hkG6ZQINyhA/JgG6Qk4qdFQjsYV6g==",
+      "dev": true
+    },
+    "map-stream": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
+      "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ="
+    },
+    "marked": {
+      "version": "0.3.19",
+      "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz",
+      "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg=="
+    },
+    "match-stream": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/match-stream/-/match-stream-0.0.2.tgz",
+      "integrity": "sha1-mesFAJOzTf+t5CG5rAtBCpz6F88=",
+      "requires": {
+        "buffers": "0.1.1",
+        "readable-stream": "1.0.34"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "0.0.1",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+          "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+        },
+        "readable-stream": {
+          "version": "1.0.34",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
+          "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
+          "requires": {
+            "core-util-is": "1.0.2",
+            "inherits": "2.0.3",
+            "isarray": "0.0.1",
+            "string_decoder": "0.10.31"
+          }
+        },
+        "string_decoder": {
+          "version": "0.10.31",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+          "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+        }
+      }
+    },
+    "media-typer": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+      "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+    },
+    "merge-descriptors": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+      "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
+    },
+    "merkle": {
+      "version": "0.5.1",
+      "resolved": "https://registry.npmjs.org/merkle/-/merkle-0.5.1.tgz",
+      "integrity": "sha1-QuI9j28ToDWRJwScGA8rxb2W8Cg=",
+      "requires": {
+        "optimist": "0.6.1",
+        "through": "2.3.6"
+      },
+      "dependencies": {
+        "through": {
+          "version": "2.3.6",
+          "resolved": "https://registry.npmjs.org/through/-/through-2.3.6.tgz",
+          "integrity": "sha1-JmgcD1JGcQIdTinffDa84tDs8ug="
+        }
+      }
+    },
+    "methods": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+      "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
+    },
+    "mime": {
+      "version": "1.2.11",
+      "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz",
+      "integrity": "sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA="
+    },
+    "mime-db": {
+      "version": "1.33.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz",
+      "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ=="
+    },
+    "mime-types": {
+      "version": "2.1.18",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz",
+      "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==",
+      "requires": {
+        "mime-db": "1.33.0"
+      }
+    },
+    "mimeparse": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/mimeparse/-/mimeparse-0.1.4.tgz",
+      "integrity": "sha1-2vsCdSNw/SJgk64xUsJxrwGsJUo="
+    },
+    "mimic-fn": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
+      "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="
+    },
+    "minimatch": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+      "requires": {
+        "brace-expansion": "1.1.11"
+      }
+    },
+    "minimist": {
+      "version": "0.0.10",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
+      "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8="
+    },
+    "mkdirp": {
+      "version": "0.5.1",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+      "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+      "requires": {
+        "minimist": "0.0.8"
+      },
+      "dependencies": {
+        "minimist": {
+          "version": "0.0.8",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+          "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
+        }
+      }
+    },
+    "mocha": {
+      "version": "3.5.3",
+      "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.5.3.tgz",
+      "integrity": "sha512-/6na001MJWEtYxHOV1WLfsmR4YIynkUEhBwzsb+fk2qmQ3iqsi258l/Q2MWHJMImAcNpZ8DEdYAK72NHoIQ9Eg==",
+      "dev": true,
+      "requires": {
+        "browser-stdout": "1.3.0",
+        "commander": "2.9.0",
+        "debug": "2.6.8",
+        "diff": "3.2.0",
+        "escape-string-regexp": "1.0.5",
+        "glob": "7.1.1",
+        "growl": "1.9.2",
+        "he": "1.1.1",
+        "json3": "3.3.2",
+        "lodash.create": "3.1.1",
+        "mkdirp": "0.5.1",
+        "supports-color": "3.1.2"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.8",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
+          "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "glob": {
+          "version": "7.1.1",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz",
+          "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=",
+          "dev": true,
+          "requires": {
+            "fs.realpath": "1.0.0",
+            "inflight": "1.0.6",
+            "inherits": "2.0.3",
+            "minimatch": "3.0.4",
+            "once": "1.4.0",
+            "path-is-absolute": "1.0.1"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.1.2",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz",
+          "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=",
+          "dev": true,
+          "requires": {
+            "has-flag": "1.0.0"
+          }
+        }
+      }
+    },
+    "mocha-eslint": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/mocha-eslint/-/mocha-eslint-0.1.7.tgz",
+      "integrity": "sha1-tOm+Vroz9AjYOMqif1wzqfLkCZM=",
+      "dev": true,
+      "requires": {
+        "chalk": "1.1.3",
+        "eslint": "0.21.2",
+        "glob": "5.0.5"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz",
+          "integrity": "sha1-QchHGUZGN15qGl0Qw8oFTvn8mA0=",
+          "dev": true
+        },
+        "cli-width": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-1.1.1.tgz",
+          "integrity": "sha1-pNKT72frt7iNSk1CwMzwDE0eNm0=",
+          "dev": true
+        },
+        "doctrine": {
+          "version": "0.6.4",
+          "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-0.6.4.tgz",
+          "integrity": "sha1-gUKEkalC7xiwSSBW7aOADu5X1h0=",
+          "dev": true,
+          "requires": {
+            "esutils": "1.1.6",
+            "isarray": "0.0.1"
+          }
+        },
+        "eslint": {
+          "version": "0.21.2",
+          "resolved": "https://registry.npmjs.org/eslint/-/eslint-0.21.2.tgz",
+          "integrity": "sha1-vt3yR4ANSGf2sQUdIkvbg8LSAcc=",
+          "dev": true,
+          "requires": {
+            "chalk": "1.1.3",
+            "concat-stream": "1.6.2",
+            "debug": "2.6.1",
+            "doctrine": "0.6.4",
+            "escape-string-regexp": "1.0.5",
+            "escope": "3.6.0",
+            "espree": "2.2.5",
+            "estraverse": "2.0.0",
+            "estraverse-fb": "1.3.2",
+            "globals": "6.4.1",
+            "inquirer": "0.8.5",
+            "js-yaml": "3.8.2",
+            "minimatch": "2.0.10",
+            "mkdirp": "0.5.1",
+            "object-assign": "2.1.1",
+            "optionator": "0.5.0",
+            "path-is-absolute": "1.0.1",
+            "strip-json-comments": "1.0.4",
+            "text-table": "0.2.0",
+            "user-home": "1.1.1",
+            "xml-escape": "1.0.0"
+          }
+        },
+        "espree": {
+          "version": "2.2.5",
+          "resolved": "https://registry.npmjs.org/espree/-/espree-2.2.5.tgz",
+          "integrity": "sha1-32kbkxCIlAKuspzAZnCMVmkLhUs=",
+          "dev": true
+        },
+        "estraverse": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-2.0.0.tgz",
+          "integrity": "sha1-WuRpYyQ2ACBmdMyySgnhZnT83KE=",
+          "dev": true
+        },
+        "esutils": {
+          "version": "1.1.6",
+          "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz",
+          "integrity": "sha1-wBzKqa5LiXxtDD4hCuUvPHqEQ3U=",
+          "dev": true
+        },
+        "fast-levenshtein": {
+          "version": "1.0.7",
+          "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz",
+          "integrity": "sha1-AXjc3uAjuSkFGTrwlZ6KdjnP3Lk=",
+          "dev": true
+        },
+        "figures": {
+          "version": "1.7.0",
+          "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
+          "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=",
+          "dev": true,
+          "requires": {
+            "escape-string-regexp": "1.0.5",
+            "object-assign": "4.1.1"
+          },
+          "dependencies": {
+            "object-assign": {
+              "version": "4.1.1",
+              "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+              "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+              "dev": true
+            }
+          }
+        },
+        "glob": {
+          "version": "5.0.5",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.5.tgz",
+          "integrity": "sha1-eEQx5OKakArg1H+6aqHH8WqOffc=",
+          "dev": true,
+          "requires": {
+            "inflight": "1.0.6",
+            "inherits": "2.0.3",
+            "minimatch": "2.0.10",
+            "once": "1.4.0",
+            "path-is-absolute": "1.0.1"
+          }
+        },
+        "globals": {
+          "version": "6.4.1",
+          "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz",
+          "integrity": "sha1-hJgDKzttHMge68X3lpDY/in6v08=",
+          "dev": true
+        },
+        "inquirer": {
+          "version": "0.8.5",
+          "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.8.5.tgz",
+          "integrity": "sha1-29dAz2yjtzEpamPOb22WGFHzNt8=",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "1.1.1",
+            "chalk": "1.1.3",
+            "cli-width": "1.1.1",
+            "figures": "1.7.0",
+            "lodash": "3.10.1",
+            "readline2": "0.1.1",
+            "rx": "2.5.3",
+            "through": "2.3.8"
+          }
+        },
+        "isarray": {
+          "version": "0.0.1",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+          "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
+          "dev": true
+        },
+        "levn": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz",
+          "integrity": "sha1-uo0znQykphDjo/FFucr0iAcVUFQ=",
+          "dev": true,
+          "requires": {
+            "prelude-ls": "1.1.2",
+            "type-check": "0.3.2"
+          }
+        },
+        "lodash": {
+          "version": "3.10.1",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
+          "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=",
+          "dev": true
+        },
+        "minimatch": {
+          "version": "2.0.10",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz",
+          "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=",
+          "dev": true,
+          "requires": {
+            "brace-expansion": "1.1.11"
+          }
+        },
+        "mute-stream": {
+          "version": "0.0.4",
+          "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.4.tgz",
+          "integrity": "sha1-qSGZYKbV1dBGWXruUSUsZlX3F34=",
+          "dev": true
+        },
+        "object-assign": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz",
+          "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=",
+          "dev": true
+        },
+        "optionator": {
+          "version": "0.5.0",
+          "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz",
+          "integrity": "sha1-t1qJlaLUF98ltuTjhi9QqohlE2g=",
+          "dev": true,
+          "requires": {
+            "deep-is": "0.1.3",
+            "fast-levenshtein": "1.0.7",
+            "levn": "0.2.5",
+            "prelude-ls": "1.1.2",
+            "type-check": "0.3.2",
+            "wordwrap": "0.0.3"
+          }
+        },
+        "readline2": {
+          "version": "0.1.1",
+          "resolved": "https://registry.npmjs.org/readline2/-/readline2-0.1.1.tgz",
+          "integrity": "sha1-mUQ7pug7gw7zBRv9fcJBqCco1Wg=",
+          "dev": true,
+          "requires": {
+            "mute-stream": "0.0.4",
+            "strip-ansi": "2.0.1"
+          }
+        },
+        "rx": {
+          "version": "2.5.3",
+          "resolved": "https://registry.npmjs.org/rx/-/rx-2.5.3.tgz",
+          "integrity": "sha1-Ia3H2A8CACr1Da6X/Z2/JIdV9WY=",
+          "dev": true
+        },
+        "strip-ansi": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz",
+          "integrity": "sha1-32LBqpTtLxFOHQ8h/R1QSCt5pg4=",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "1.1.1"
+          }
+        },
+        "strip-json-comments": {
+          "version": "1.0.4",
+          "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz",
+          "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=",
+          "dev": true
+        },
+        "user-home": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz",
+          "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=",
+          "dev": true
+        }
+      }
+    },
+    "moment": {
+      "version": "2.19.3",
+      "resolved": "https://registry.npmjs.org/moment/-/moment-2.19.3.tgz",
+      "integrity": "sha1-vbmdJw1tf9p4zA+6zoVeJ/59pp8="
+    },
+    "morgan": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.8.1.tgz",
+      "integrity": "sha1-+TAj04h70nt439YCPOp4ku4npLE=",
+      "requires": {
+        "basic-auth": "1.1.0",
+        "debug": "2.6.1",
+        "depd": "1.1.2",
+        "on-finished": "2.3.0",
+        "on-headers": "1.0.1"
+      }
+    },
+    "ms": {
+      "version": "0.7.2",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
+      "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U="
+    },
+    "multimeter": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/multimeter/-/multimeter-0.1.1.tgz",
+      "integrity": "sha1-+FbID8PPDx1K2Os2rWhzXj7Vs+o=",
+      "requires": {
+        "charm": "0.1.2"
+      }
+    },
+    "mute-stream": {
+      "version": "0.0.7",
+      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
+      "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
+    },
+    "naclb": {
+      "version": "1.3.10",
+      "resolved": "https://registry.npmjs.org/naclb/-/naclb-1.3.10.tgz",
+      "integrity": "sha1-LE/WzPMYo87yUtzZ2tOJ+rOD2W8=",
+      "requires": {
+        "bindings": "1.2.1",
+        "nan": "2.2.0",
+        "node-pre-gyp": "0.6.33"
+      },
+      "dependencies": {
+        "abbrev": {
+          "version": "1.1.1",
+          "bundled": true
+        },
+        "ajv": {
+          "version": "5.5.2",
+          "bundled": true,
+          "requires": {
+            "co": "4.6.0",
+            "fast-deep-equal": "1.0.0",
+            "fast-json-stable-stringify": "2.0.0",
+            "json-schema-traverse": "0.3.1"
+          }
+        },
+        "ansi-regex": {
+          "version": "2.1.1",
+          "bundled": true
+        },
+        "aproba": {
+          "version": "1.2.0",
+          "bundled": true
+        },
+        "are-we-there-yet": {
+          "version": "1.1.4",
+          "bundled": true,
+          "requires": {
+            "delegates": "1.0.0",
+            "readable-stream": "2.3.3"
+          }
+        },
+        "asn1": {
+          "version": "0.2.3",
+          "bundled": true
+        },
+        "assert-plus": {
+          "version": "1.0.0",
+          "bundled": true
+        },
+        "asynckit": {
+          "version": "0.4.0",
+          "bundled": true
+        },
+        "aws-sign2": {
+          "version": "0.7.0",
+          "bundled": true
+        },
+        "aws4": {
+          "version": "1.6.0",
+          "bundled": true
+        },
+        "balanced-match": {
+          "version": "1.0.0",
+          "bundled": true
+        },
+        "bcrypt-pbkdf": {
+          "version": "1.0.1",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "tweetnacl": "0.14.3"
+          }
+        },
+        "block-stream": {
+          "version": "0.0.9",
+          "bundled": true,
+          "requires": {
+            "inherits": "2.0.3"
+          }
+        },
+        "boom": {
+          "version": "4.3.1",
+          "bundled": true,
+          "requires": {
+            "hoek": "4.2.0"
+          }
+        },
+        "brace-expansion": {
+          "version": "1.1.8",
+          "bundled": true,
+          "requires": {
+            "balanced-match": "1.0.0",
+            "concat-map": "0.0.1"
+          }
+        },
+        "buffer-shims": {
+          "version": "1.0.0",
+          "bundled": true
+        },
+        "caseless": {
+          "version": "0.12.0",
+          "bundled": true
+        },
+        "co": {
+          "version": "4.6.0",
+          "bundled": true
+        },
+        "code-point-at": {
+          "version": "1.1.0",
+          "bundled": true
+        },
+        "combined-stream": {
+          "version": "1.0.5",
+          "bundled": true,
+          "requires": {
+            "delayed-stream": "1.0.0"
+          }
+        },
+        "concat-map": {
+          "version": "0.0.1",
+          "bundled": true
+        },
+        "console-control-strings": {
+          "version": "1.1.0",
+          "bundled": true
+        },
+        "core-util-is": {
+          "version": "1.0.2",
+          "bundled": true
+        },
+        "cryptiles": {
+          "version": "3.1.2",
+          "bundled": true,
+          "requires": {
+            "boom": "5.2.0"
+          },
+          "dependencies": {
+            "boom": {
+              "version": "5.2.0",
+              "bundled": true,
+              "requires": {
+                "hoek": "4.2.0"
+              }
+            }
+          }
+        },
+        "dashdash": {
+          "version": "1.14.1",
+          "bundled": true,
+          "requires": {
+            "assert-plus": "1.0.0"
+          }
+        },
+        "debug": {
+          "version": "2.2.0",
+          "bundled": true,
+          "requires": {
+            "ms": "0.7.1"
+          }
+        },
+        "deep-extend": {
+          "version": "0.4.2",
+          "bundled": true
+        },
+        "delayed-stream": {
+          "version": "1.0.0",
+          "bundled": true
+        },
+        "delegates": {
+          "version": "1.0.0",
+          "bundled": true
+        },
+        "ecc-jsbn": {
+          "version": "0.1.1",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "jsbn": "0.1.1"
+          }
+        },
+        "extend": {
+          "version": "3.0.1",
+          "bundled": true
+        },
+        "extsprintf": {
+          "version": "1.3.0",
+          "bundled": true
+        },
+        "fast-deep-equal": {
+          "version": "1.0.0",
+          "bundled": true
+        },
+        "fast-json-stable-stringify": {
+          "version": "2.0.0",
+          "bundled": true
+        },
+        "forever-agent": {
+          "version": "0.6.1",
+          "bundled": true
+        },
+        "form-data": {
+          "version": "2.3.1",
+          "bundled": true,
+          "requires": {
+            "asynckit": "0.4.0",
+            "combined-stream": "1.0.5",
+            "mime-types": "2.1.17"
+          }
+        },
+        "fs.realpath": {
+          "version": "1.0.0",
+          "bundled": true
+        },
+        "fstream": {
+          "version": "1.0.11",
+          "bundled": true,
+          "requires": {
+            "graceful-fs": "4.1.11",
+            "inherits": "2.0.3",
+            "mkdirp": "0.5.1",
+            "rimraf": "2.5.4"
+          }
+        },
+        "fstream-ignore": {
+          "version": "1.0.5",
+          "bundled": true,
+          "requires": {
+            "fstream": "1.0.11",
+            "inherits": "2.0.3",
+            "minimatch": "3.0.4"
+          }
+        },
+        "gauge": {
+          "version": "2.7.4",
+          "bundled": true,
+          "requires": {
+            "aproba": "1.2.0",
+            "console-control-strings": "1.1.0",
+            "has-unicode": "2.0.1",
+            "object-assign": "4.1.1",
+            "signal-exit": "3.0.2",
+            "string-width": "1.0.2",
+            "strip-ansi": "3.0.1",
+            "wide-align": "1.1.2"
+          }
+        },
+        "getpass": {
+          "version": "0.1.7",
+          "bundled": true,
+          "requires": {
+            "assert-plus": "1.0.0"
+          }
+        },
+        "glob": {
+          "version": "7.1.2",
+          "bundled": true,
+          "requires": {
+            "fs.realpath": "1.0.0",
+            "inflight": "1.0.6",
+            "inherits": "2.0.3",
+            "minimatch": "3.0.4",
+            "once": "1.4.0",
+            "path-is-absolute": "1.0.1"
+          }
+        },
+        "graceful-fs": {
+          "version": "4.1.11",
+          "bundled": true
+        },
+        "har-schema": {
+          "version": "2.0.0",
+          "bundled": true
+        },
+        "har-validator": {
+          "version": "5.0.3",
+          "bundled": true,
+          "requires": {
+            "ajv": "5.5.2",
+            "har-schema": "2.0.0"
+          }
+        },
+        "has-unicode": {
+          "version": "2.0.1",
+          "bundled": true
+        },
+        "hawk": {
+          "version": "6.0.2",
+          "bundled": true,
+          "requires": {
+            "boom": "4.3.1",
+            "cryptiles": "3.1.2",
+            "hoek": "4.2.0",
+            "sntp": "2.1.0"
+          }
+        },
+        "hoek": {
+          "version": "4.2.0",
+          "bundled": true
+        },
+        "http-signature": {
+          "version": "1.2.0",
+          "bundled": true,
+          "requires": {
+            "assert-plus": "1.0.0",
+            "jsprim": "1.4.1",
+            "sshpk": "1.13.1"
+          }
+        },
+        "inflight": {
+          "version": "1.0.6",
+          "bundled": true,
+          "requires": {
+            "once": "1.4.0",
+            "wrappy": "1.0.2"
+          }
+        },
+        "inherits": {
+          "version": "2.0.3",
+          "bundled": true
+        },
+        "ini": {
+          "version": "1.3.5",
+          "bundled": true
+        },
+        "is-fullwidth-code-point": {
+          "version": "1.0.0",
+          "bundled": true,
+          "requires": {
+            "number-is-nan": "1.0.1"
+          }
+        },
+        "is-typedarray": {
+          "version": "1.0.0",
+          "bundled": true
+        },
+        "isarray": {
+          "version": "1.0.0",
+          "bundled": true
+        },
+        "isstream": {
+          "version": "0.1.2",
+          "bundled": true
+        },
+        "jsbn": {
+          "version": "0.1.1",
+          "bundled": true,
+          "optional": true
+        },
+        "json-schema": {
+          "version": "0.2.3",
+          "bundled": true
+        },
+        "json-schema-traverse": {
+          "version": "0.3.1",
+          "bundled": true
+        },
+        "json-stringify-safe": {
+          "version": "5.0.1",
+          "bundled": true
+        },
+        "jsprim": {
+          "version": "1.4.1",
+          "bundled": true,
+          "requires": {
+            "assert-plus": "1.0.0",
+            "extsprintf": "1.3.0",
+            "json-schema": "0.2.3",
+            "verror": "1.10.0"
+          }
+        },
+        "mime-db": {
+          "version": "1.30.0",
+          "bundled": true
+        },
+        "mime-types": {
+          "version": "2.1.17",
+          "bundled": true,
+          "requires": {
+            "mime-db": "1.30.0"
+          }
+        },
+        "minimatch": {
+          "version": "3.0.4",
+          "bundled": true,
+          "requires": {
+            "brace-expansion": "1.1.8"
+          }
+        },
+        "minimist": {
+          "version": "0.0.8",
+          "bundled": true
+        },
+        "mkdirp": {
+          "version": "0.5.1",
+          "bundled": true,
+          "requires": {
+            "minimist": "0.0.8"
+          }
+        },
+        "ms": {
+          "version": "0.7.1",
+          "bundled": true
+        },
+        "node-pre-gyp": {
+          "version": "0.6.33",
+          "bundled": true,
+          "requires": {
+            "mkdirp": "0.5.1",
+            "nopt": "3.0.6",
+            "npmlog": "4.1.2",
+            "rc": "1.1.7",
+            "request": "2.83.0",
+            "rimraf": "2.5.4",
+            "semver": "5.3.0",
+            "tar": "2.2.1",
+            "tar-pack": "3.3.0"
+          }
+        },
+        "nopt": {
+          "version": "3.0.6",
+          "bundled": true,
+          "requires": {
+            "abbrev": "1.1.1"
+          }
+        },
+        "npmlog": {
+          "version": "4.1.2",
+          "bundled": true,
+          "requires": {
+            "are-we-there-yet": "1.1.4",
+            "console-control-strings": "1.1.0",
+            "gauge": "2.7.4",
+            "set-blocking": "2.0.0"
+          }
+        },
+        "number-is-nan": {
+          "version": "1.0.1",
+          "bundled": true
+        },
+        "oauth-sign": {
+          "version": "0.8.2",
+          "bundled": true
+        },
+        "object-assign": {
+          "version": "4.1.1",
+          "bundled": true
+        },
+        "once": {
+          "version": "1.4.0",
+          "bundled": true,
+          "requires": {
+            "wrappy": "1.0.2"
+          }
+        },
+        "path-is-absolute": {
+          "version": "1.0.1",
+          "bundled": true
+        },
+        "performance-now": {
+          "version": "2.1.0",
+          "bundled": true
+        },
+        "process-nextick-args": {
+          "version": "1.0.7",
+          "bundled": true
+        },
+        "punycode": {
+          "version": "1.4.1",
+          "bundled": true
+        },
+        "qs": {
+          "version": "6.5.1",
+          "bundled": true
+        },
+        "rc": {
+          "version": "1.1.7",
+          "bundled": true,
+          "requires": {
+            "deep-extend": "0.4.2",
+            "ini": "1.3.5",
+            "minimist": "1.2.0",
+            "strip-json-comments": "2.0.1"
+          },
+          "dependencies": {
+            "minimist": {
+              "version": "1.2.0",
+              "bundled": true
+            }
+          }
+        },
+        "readable-stream": {
+          "version": "2.3.3",
+          "bundled": true,
+          "requires": {
+            "core-util-is": "1.0.2",
+            "inherits": "2.0.3",
+            "isarray": "1.0.0",
+            "process-nextick-args": "1.0.7",
+            "safe-buffer": "5.1.1",
+            "string_decoder": "1.0.3",
+            "util-deprecate": "1.0.2"
+          }
+        },
+        "request": {
+          "version": "2.83.0",
+          "bundled": true,
+          "requires": {
+            "aws-sign2": "0.7.0",
+            "aws4": "1.6.0",
+            "caseless": "0.12.0",
+            "combined-stream": "1.0.5",
+            "extend": "3.0.1",
+            "forever-agent": "0.6.1",
+            "form-data": "2.3.1",
+            "har-validator": "5.0.3",
+            "hawk": "6.0.2",
+            "http-signature": "1.2.0",
+            "is-typedarray": "1.0.0",
+            "isstream": "0.1.2",
+            "json-stringify-safe": "5.0.1",
+            "mime-types": "2.1.17",
+            "oauth-sign": "0.8.2",
+            "performance-now": "2.1.0",
+            "qs": "6.5.1",
+            "safe-buffer": "5.1.1",
+            "stringstream": "0.0.5",
+            "tough-cookie": "2.3.3",
+            "tunnel-agent": "0.6.0",
+            "uuid": "3.2.1"
+          }
+        },
+        "rimraf": {
+          "version": "2.5.4",
+          "bundled": true,
+          "requires": {
+            "glob": "7.1.2"
+          }
+        },
+        "safe-buffer": {
+          "version": "5.1.1",
+          "bundled": true
+        },
+        "semver": {
+          "version": "5.3.0",
+          "bundled": true
+        },
+        "set-blocking": {
+          "version": "2.0.0",
+          "bundled": true
+        },
+        "signal-exit": {
+          "version": "3.0.2",
+          "bundled": true
+        },
+        "sntp": {
+          "version": "2.1.0",
+          "bundled": true,
+          "requires": {
+            "hoek": "4.2.0"
+          }
+        },
+        "sshpk": {
+          "version": "1.13.1",
+          "bundled": true,
+          "requires": {
+            "asn1": "0.2.3",
+            "assert-plus": "1.0.0",
+            "bcrypt-pbkdf": "1.0.1",
+            "dashdash": "1.14.1",
+            "ecc-jsbn": "0.1.1",
+            "getpass": "0.1.7",
+            "jsbn": "0.1.1",
+            "tweetnacl": "0.14.3"
+          }
+        },
+        "string-width": {
+          "version": "1.0.2",
+          "bundled": true,
+          "requires": {
+            "code-point-at": "1.1.0",
+            "is-fullwidth-code-point": "1.0.0",
+            "strip-ansi": "3.0.1"
+          }
+        },
+        "string_decoder": {
+          "version": "1.0.3",
+          "bundled": true,
+          "requires": {
+            "safe-buffer": "5.1.1"
+          }
+        },
+        "stringstream": {
+          "version": "0.0.5",
+          "bundled": true
+        },
+        "strip-ansi": {
+          "version": "3.0.1",
+          "bundled": true,
+          "requires": {
+            "ansi-regex": "2.1.1"
+          }
+        },
+        "strip-json-comments": {
+          "version": "2.0.1",
+          "bundled": true
+        },
+        "tar": {
+          "version": "2.2.1",
+          "bundled": true,
+          "requires": {
+            "block-stream": "0.0.9",
+            "fstream": "1.0.11",
+            "inherits": "2.0.3"
+          }
+        },
+        "tar-pack": {
+          "version": "3.3.0",
+          "bundled": true,
+          "requires": {
+            "debug": "2.2.0",
+            "fstream": "1.0.11",
+            "fstream-ignore": "1.0.5",
+            "once": "1.3.3",
+            "readable-stream": "2.1.5",
+            "rimraf": "2.5.4",
+            "tar": "2.2.1",
+            "uid-number": "0.0.6"
+          },
+          "dependencies": {
+            "once": {
+              "version": "1.3.3",
+              "bundled": true,
+              "requires": {
+                "wrappy": "1.0.2"
+              }
+            },
+            "readable-stream": {
+              "version": "2.1.5",
+              "bundled": true,
+              "requires": {
+                "buffer-shims": "1.0.0",
+                "core-util-is": "1.0.2",
+                "inherits": "2.0.3",
+                "isarray": "1.0.0",
+                "process-nextick-args": "1.0.7",
+                "string_decoder": "0.10.31",
+                "util-deprecate": "1.0.2"
+              }
+            },
+            "string_decoder": {
+              "version": "0.10.31",
+              "bundled": true
+            }
+          }
+        },
+        "tough-cookie": {
+          "version": "2.3.3",
+          "bundled": true,
+          "requires": {
+            "punycode": "1.4.1"
+          }
+        },
+        "tunnel-agent": {
+          "version": "0.6.0",
+          "bundled": true,
+          "requires": {
+            "safe-buffer": "5.1.1"
+          }
+        },
+        "uid-number": {
+          "version": "0.0.6",
+          "bundled": true
+        },
+        "util-deprecate": {
+          "version": "1.0.2",
+          "bundled": true
+        },
+        "uuid": {
+          "version": "3.2.1",
+          "bundled": true
+        },
+        "verror": {
+          "version": "1.10.0",
+          "bundled": true,
+          "requires": {
+            "assert-plus": "1.0.0",
+            "core-util-is": "1.0.2",
+            "extsprintf": "1.3.0"
+          }
+        },
+        "wide-align": {
+          "version": "1.1.2",
+          "bundled": true,
+          "requires": {
+            "string-width": "1.0.2"
+          }
+        },
+        "wrappy": {
+          "version": "1.0.2",
+          "bundled": true
+        }
+      }
+    },
+    "nan": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/nan/-/nan-2.2.0.tgz",
+      "integrity": "sha1-d5wHE1YpUDz2p7fmqrMwSbPDhTw="
+    },
+    "nat-upnp": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/nat-upnp/-/nat-upnp-1.1.1.tgz",
+      "integrity": "sha512-b1Q+sf9fHGCXhlWErNgTTEto8A02MnNysw3vx3kD1657+/Ae23vPEAB6QBh+9RqLL4+xw/LmjVTiLy6A7Cx0xw==",
+      "requires": {
+        "async": "2.2.0",
+        "ip": "1.1.5",
+        "request": "2.81.0",
+        "xml2js": "0.1.14"
+      }
+    },
+    "natives": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.4.tgz",
+      "integrity": "sha512-Q29yeg9aFKwhLVdkTAejM/HvYG0Y1Am1+HUkFQGn5k2j8GS+v60TVmZh6nujpEAj/qql+wGUrlryO8bF+b1jEg=="
+    },
+    "natural-compare": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+      "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
+      "dev": true
+    },
+    "negotiator": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
+      "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
+    },
+    "next-tick": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
+      "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=",
+      "dev": true
+    },
+    "node-pre-gyp": {
+      "version": "0.6.34",
+      "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.6.34.tgz",
+      "integrity": "sha1-lK0ceYoR1/xnOBtQ1H+MwY2Xmfc=",
+      "requires": {
+        "mkdirp": "0.5.1",
+        "nopt": "4.0.1",
+        "npmlog": "4.1.2",
+        "rc": "1.2.8",
+        "request": "2.81.0",
+        "rimraf": "2.6.2",
+        "semver": "5.5.0",
+        "tar": "2.2.1",
+        "tar-pack": "3.4.1"
+      }
+    },
+    "node-uuid": {
+      "version": "1.4.8",
+      "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz",
+      "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc="
+    },
+    "nomnom": {
+      "version": "1.5.2",
+      "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.5.2.tgz",
+      "integrity": "sha1-9DRUSKhTz71cDSYyDyR3qwUm/i8=",
+      "requires": {
+        "colors": "0.5.1",
+        "underscore": "1.1.7"
+      },
+      "dependencies": {
+        "colors": {
+          "version": "0.5.1",
+          "resolved": "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz",
+          "integrity": "sha1-fQAj6usVTo7p/Oddy5I9DtFmd3Q="
+        },
+        "underscore": {
+          "version": "1.1.7",
+          "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.1.7.tgz",
+          "integrity": "sha1-QLq4S60Z0jAJbo1u9ii/8FXYPbA="
+        }
+      }
+    },
+    "nopt": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
+      "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
+      "requires": {
+        "abbrev": "1.1.1",
+        "osenv": "0.1.5"
+      }
+    },
+    "normalize-path": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+      "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+      "requires": {
+        "remove-trailing-separator": "1.1.0"
+      }
+    },
+    "npmlog": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
+      "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+      "requires": {
+        "are-we-there-yet": "1.1.5",
+        "console-control-strings": "1.1.0",
+        "gauge": "2.7.4",
+        "set-blocking": "2.0.0"
+      }
+    },
+    "number-is-nan": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+      "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
+    },
+    "nyc": {
+      "version": "11.9.0",
+      "resolved": "https://registry.npmjs.org/nyc/-/nyc-11.9.0.tgz",
+      "integrity": "sha512-w8OdJAhXL5izerzZMdqzYKMj/pgHJyY3qEPYBjLLxrhcVoHEY9pU5ENIiZyCgG9OR7x3VcUMoD40o6PtVpfR4g==",
+      "dev": true,
+      "requires": {
+        "archy": "1.0.0",
+        "arrify": "1.0.1",
+        "caching-transform": "1.0.1",
+        "convert-source-map": "1.5.1",
+        "debug-log": "1.0.1",
+        "default-require-extensions": "1.0.0",
+        "find-cache-dir": "0.1.1",
+        "find-up": "2.1.0",
+        "foreground-child": "1.5.6",
+        "glob": "7.1.2",
+        "istanbul-lib-coverage": "1.2.0",
+        "istanbul-lib-hook": "1.1.0",
+        "istanbul-lib-instrument": "1.10.1",
+        "istanbul-lib-report": "1.1.3",
+        "istanbul-lib-source-maps": "1.2.3",
+        "istanbul-reports": "1.4.0",
+        "md5-hex": "1.3.0",
+        "merge-source-map": "1.1.0",
+        "micromatch": "3.1.10",
+        "mkdirp": "0.5.1",
+        "resolve-from": "2.0.0",
+        "rimraf": "2.6.2",
+        "signal-exit": "3.0.2",
+        "spawn-wrap": "1.4.2",
+        "test-exclude": "4.2.1",
+        "yargs": "11.1.0",
+        "yargs-parser": "8.1.0"
+      },
+      "dependencies": {
+        "align-text": {
+          "version": "0.1.4",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "kind-of": "3.2.2",
+            "longest": "1.0.1",
+            "repeat-string": "1.6.1"
+          }
+        },
+        "amdefine": {
+          "version": "1.0.1",
+          "bundled": true,
+          "dev": true
+        },
+        "ansi-regex": {
+          "version": "2.1.1",
+          "bundled": true,
+          "dev": true
+        },
+        "ansi-styles": {
+          "version": "2.2.1",
+          "bundled": true,
+          "dev": true
+        },
+        "append-transform": {
+          "version": "0.4.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "default-require-extensions": "1.0.0"
+          }
+        },
+        "archy": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "arr-diff": {
+          "version": "4.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "arr-flatten": {
+          "version": "1.1.0",
+          "bundled": true,
+          "dev": true
+        },
+        "arr-union": {
+          "version": "3.1.0",
+          "bundled": true,
+          "dev": true
+        },
+        "array-unique": {
+          "version": "0.3.2",
+          "bundled": true,
+          "dev": true
+        },
+        "arrify": {
+          "version": "1.0.1",
+          "bundled": true,
+          "dev": true
+        },
+        "assign-symbols": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "async": {
+          "version": "1.5.2",
+          "bundled": true,
+          "dev": true
+        },
+        "atob": {
+          "version": "2.1.1",
+          "bundled": true,
+          "dev": true
+        },
+        "babel-code-frame": {
+          "version": "6.26.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "chalk": "1.1.3",
+            "esutils": "2.0.2",
+            "js-tokens": "3.0.2"
+          }
+        },
+        "babel-generator": {
+          "version": "6.26.1",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "babel-messages": "6.23.0",
+            "babel-runtime": "6.26.0",
+            "babel-types": "6.26.0",
+            "detect-indent": "4.0.0",
+            "jsesc": "1.3.0",
+            "lodash": "4.17.10",
+            "source-map": "0.5.7",
+            "trim-right": "1.0.1"
+          }
+        },
+        "babel-messages": {
+          "version": "6.23.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "babel-runtime": "6.26.0"
+          }
+        },
+        "babel-runtime": {
+          "version": "6.26.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "core-js": "2.5.6",
+            "regenerator-runtime": "0.11.1"
+          }
+        },
+        "babel-template": {
+          "version": "6.26.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "babel-runtime": "6.26.0",
+            "babel-traverse": "6.26.0",
+            "babel-types": "6.26.0",
+            "babylon": "6.18.0",
+            "lodash": "4.17.10"
+          }
+        },
+        "babel-traverse": {
+          "version": "6.26.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "babel-code-frame": "6.26.0",
+            "babel-messages": "6.23.0",
+            "babel-runtime": "6.26.0",
+            "babel-types": "6.26.0",
+            "babylon": "6.18.0",
+            "debug": "2.6.9",
+            "globals": "9.18.0",
+            "invariant": "2.2.4",
+            "lodash": "4.17.10"
+          }
+        },
+        "babel-types": {
+          "version": "6.26.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "babel-runtime": "6.26.0",
+            "esutils": "2.0.2",
+            "lodash": "4.17.10",
+            "to-fast-properties": "1.0.3"
+          }
+        },
+        "babylon": {
+          "version": "6.18.0",
+          "bundled": true,
+          "dev": true
+        },
+        "balanced-match": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "base": {
+          "version": "0.11.2",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "cache-base": "1.0.1",
+            "class-utils": "0.3.6",
+            "component-emitter": "1.2.1",
+            "define-property": "1.0.0",
+            "isobject": "3.0.1",
+            "mixin-deep": "1.3.1",
+            "pascalcase": "0.1.1"
+          },
+          "dependencies": {
+            "define-property": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "is-descriptor": "1.0.2"
+              }
+            },
+            "is-accessor-descriptor": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "kind-of": "6.0.2"
+              }
+            },
+            "is-data-descriptor": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "kind-of": "6.0.2"
+              }
+            },
+            "is-descriptor": {
+              "version": "1.0.2",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "is-accessor-descriptor": "1.0.0",
+                "is-data-descriptor": "1.0.0",
+                "kind-of": "6.0.2"
+              }
+            },
+            "isobject": {
+              "version": "3.0.1",
+              "bundled": true,
+              "dev": true
+            },
+            "kind-of": {
+              "version": "6.0.2",
+              "bundled": true,
+              "dev": true
+            }
+          }
+        },
+        "brace-expansion": {
+          "version": "1.1.11",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "balanced-match": "1.0.0",
+            "concat-map": "0.0.1"
+          }
+        },
+        "braces": {
+          "version": "2.3.2",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "arr-flatten": "1.1.0",
+            "array-unique": "0.3.2",
+            "extend-shallow": "2.0.1",
+            "fill-range": "4.0.0",
+            "isobject": "3.0.1",
+            "repeat-element": "1.1.2",
+            "snapdragon": "0.8.2",
+            "snapdragon-node": "2.1.1",
+            "split-string": "3.1.0",
+            "to-regex": "3.0.2"
+          },
+          "dependencies": {
+            "extend-shallow": {
+              "version": "2.0.1",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "is-extendable": "0.1.1"
+              }
+            }
+          }
+        },
+        "builtin-modules": {
+          "version": "1.1.1",
+          "bundled": true,
+          "dev": true
+        },
+        "cache-base": {
+          "version": "1.0.1",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "collection-visit": "1.0.0",
+            "component-emitter": "1.2.1",
+            "get-value": "2.0.6",
+            "has-value": "1.0.0",
+            "isobject": "3.0.1",
+            "set-value": "2.0.0",
+            "to-object-path": "0.3.0",
+            "union-value": "1.0.0",
+            "unset-value": "1.0.0"
+          },
+          "dependencies": {
+            "isobject": {
+              "version": "3.0.1",
+              "bundled": true,
+              "dev": true
+            }
+          }
+        },
+        "caching-transform": {
+          "version": "1.0.1",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "md5-hex": "1.3.0",
+            "mkdirp": "0.5.1",
+            "write-file-atomic": "1.3.4"
+          }
+        },
+        "camelcase": {
+          "version": "1.2.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "center-align": {
+          "version": "0.1.3",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "align-text": "0.1.4",
+            "lazy-cache": "1.0.4"
+          }
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "ansi-styles": "2.2.1",
+            "escape-string-regexp": "1.0.5",
+            "has-ansi": "2.0.0",
+            "strip-ansi": "3.0.1",
+            "supports-color": "2.0.0"
+          }
+        },
+        "class-utils": {
+          "version": "0.3.6",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "arr-union": "3.1.0",
+            "define-property": "0.2.5",
+            "isobject": "3.0.1",
+            "static-extend": "0.1.2"
+          },
+          "dependencies": {
+            "define-property": {
+              "version": "0.2.5",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "is-descriptor": "0.1.6"
+              }
+            },
+            "isobject": {
+              "version": "3.0.1",
+              "bundled": true,
+              "dev": true
+            }
+          }
+        },
+        "cliui": {
+          "version": "2.1.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "center-align": "0.1.3",
+            "right-align": "0.1.3",
+            "wordwrap": "0.0.2"
+          },
+          "dependencies": {
+            "wordwrap": {
+              "version": "0.0.2",
+              "bundled": true,
+              "dev": true,
+              "optional": true
+            }
+          }
+        },
+        "code-point-at": {
+          "version": "1.1.0",
+          "bundled": true,
+          "dev": true
+        },
+        "collection-visit": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "map-visit": "1.0.0",
+            "object-visit": "1.0.1"
+          }
+        },
+        "commondir": {
+          "version": "1.0.1",
+          "bundled": true,
+          "dev": true
+        },
+        "component-emitter": {
+          "version": "1.2.1",
+          "bundled": true,
+          "dev": true
+        },
+        "concat-map": {
+          "version": "0.0.1",
+          "bundled": true,
+          "dev": true
+        },
+        "convert-source-map": {
+          "version": "1.5.1",
+          "bundled": true,
+          "dev": true
+        },
+        "copy-descriptor": {
+          "version": "0.1.1",
+          "bundled": true,
+          "dev": true
+        },
+        "core-js": {
+          "version": "2.5.6",
+          "bundled": true,
+          "dev": true
+        },
+        "cross-spawn": {
+          "version": "4.0.2",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "lru-cache": "4.1.3",
+            "which": "1.3.0"
+          }
+        },
+        "debug": {
+          "version": "2.6.9",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "debug-log": {
+          "version": "1.0.1",
+          "bundled": true,
+          "dev": true
+        },
+        "decamelize": {
+          "version": "1.2.0",
+          "bundled": true,
+          "dev": true
+        },
+        "decode-uri-component": {
+          "version": "0.2.0",
+          "bundled": true,
+          "dev": true
+        },
+        "default-require-extensions": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "strip-bom": "2.0.0"
+          }
+        },
+        "define-property": {
+          "version": "2.0.2",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "is-descriptor": "1.0.2",
+            "isobject": "3.0.1"
+          },
+          "dependencies": {
+            "is-accessor-descriptor": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "kind-of": "6.0.2"
+              }
+            },
+            "is-data-descriptor": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "kind-of": "6.0.2"
+              }
+            },
+            "is-descriptor": {
+              "version": "1.0.2",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "is-accessor-descriptor": "1.0.0",
+                "is-data-descriptor": "1.0.0",
+                "kind-of": "6.0.2"
+              }
+            },
+            "isobject": {
+              "version": "3.0.1",
+              "bundled": true,
+              "dev": true
+            },
+            "kind-of": {
+              "version": "6.0.2",
+              "bundled": true,
+              "dev": true
+            }
+          }
+        },
+        "detect-indent": {
+          "version": "4.0.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "repeating": "2.0.1"
+          }
+        },
+        "error-ex": {
+          "version": "1.3.1",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "is-arrayish": "0.2.1"
+          }
+        },
+        "escape-string-regexp": {
+          "version": "1.0.5",
+          "bundled": true,
+          "dev": true
+        },
+        "esutils": {
+          "version": "2.0.2",
+          "bundled": true,
+          "dev": true
+        },
+        "execa": {
+          "version": "0.7.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "cross-spawn": "5.1.0",
+            "get-stream": "3.0.0",
+            "is-stream": "1.1.0",
+            "npm-run-path": "2.0.2",
+            "p-finally": "1.0.0",
+            "signal-exit": "3.0.2",
+            "strip-eof": "1.0.0"
+          },
+          "dependencies": {
+            "cross-spawn": {
+              "version": "5.1.0",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "lru-cache": "4.1.3",
+                "shebang-command": "1.2.0",
+                "which": "1.3.0"
+              }
+            }
+          }
+        },
+        "expand-brackets": {
+          "version": "2.1.4",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "debug": "2.6.9",
+            "define-property": "0.2.5",
+            "extend-shallow": "2.0.1",
+            "posix-character-classes": "0.1.1",
+            "regex-not": "1.0.2",
+            "snapdragon": "0.8.2",
+            "to-regex": "3.0.2"
+          },
+          "dependencies": {
+            "define-property": {
+              "version": "0.2.5",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "is-descriptor": "0.1.6"
+              }
+            },
+            "extend-shallow": {
+              "version": "2.0.1",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "is-extendable": "0.1.1"
+              }
+            }
+          }
+        },
+        "extend-shallow": {
+          "version": "3.0.2",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "assign-symbols": "1.0.0",
+            "is-extendable": "1.0.1"
+          },
+          "dependencies": {
+            "is-extendable": {
+              "version": "1.0.1",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "is-plain-object": "2.0.4"
+              }
+            }
+          }
+        },
+        "extglob": {
+          "version": "2.0.4",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "array-unique": "0.3.2",
+            "define-property": "1.0.0",
+            "expand-brackets": "2.1.4",
+            "extend-shallow": "2.0.1",
+            "fragment-cache": "0.2.1",
+            "regex-not": "1.0.2",
+            "snapdragon": "0.8.2",
+            "to-regex": "3.0.2"
+          },
+          "dependencies": {
+            "define-property": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "is-descriptor": "1.0.2"
+              }
+            },
+            "extend-shallow": {
+              "version": "2.0.1",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "is-extendable": "0.1.1"
+              }
+            },
+            "is-accessor-descriptor": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "kind-of": "6.0.2"
+              }
+            },
+            "is-data-descriptor": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "kind-of": "6.0.2"
+              }
+            },
+            "is-descriptor": {
+              "version": "1.0.2",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "is-accessor-descriptor": "1.0.0",
+                "is-data-descriptor": "1.0.0",
+                "kind-of": "6.0.2"
+              }
+            },
+            "kind-of": {
+              "version": "6.0.2",
+              "bundled": true,
+              "dev": true
+            }
+          }
+        },
+        "fill-range": {
+          "version": "4.0.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "extend-shallow": "2.0.1",
+            "is-number": "3.0.0",
+            "repeat-string": "1.6.1",
+            "to-regex-range": "2.1.1"
+          },
+          "dependencies": {
+            "extend-shallow": {
+              "version": "2.0.1",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "is-extendable": "0.1.1"
+              }
+            }
+          }
+        },
+        "find-cache-dir": {
+          "version": "0.1.1",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "commondir": "1.0.1",
+            "mkdirp": "0.5.1",
+            "pkg-dir": "1.0.0"
+          }
+        },
+        "find-up": {
+          "version": "2.1.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "locate-path": "2.0.0"
+          }
+        },
+        "for-in": {
+          "version": "1.0.2",
+          "bundled": true,
+          "dev": true
+        },
+        "foreground-child": {
+          "version": "1.5.6",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "cross-spawn": "4.0.2",
+            "signal-exit": "3.0.2"
+          }
+        },
+        "fragment-cache": {
+          "version": "0.2.1",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "map-cache": "0.2.2"
+          }
+        },
+        "fs.realpath": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "get-caller-file": {
+          "version": "1.0.2",
+          "bundled": true,
+          "dev": true
+        },
+        "get-stream": {
+          "version": "3.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "get-value": {
+          "version": "2.0.6",
+          "bundled": true,
+          "dev": true
+        },
+        "glob": {
+          "version": "7.1.2",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "fs.realpath": "1.0.0",
+            "inflight": "1.0.6",
+            "inherits": "2.0.3",
+            "minimatch": "3.0.4",
+            "once": "1.4.0",
+            "path-is-absolute": "1.0.1"
+          }
+        },
+        "globals": {
+          "version": "9.18.0",
+          "bundled": true,
+          "dev": true
+        },
+        "graceful-fs": {
+          "version": "4.1.11",
+          "bundled": true,
+          "dev": true
+        },
+        "handlebars": {
+          "version": "4.0.11",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "async": "1.5.2",
+            "optimist": "0.6.1",
+            "source-map": "0.4.4",
+            "uglify-js": "2.8.29"
+          },
+          "dependencies": {
+            "source-map": {
+              "version": "0.4.4",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "amdefine": "1.0.1"
+              }
+            }
+          }
+        },
+        "has-ansi": {
+          "version": "2.0.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "ansi-regex": "2.1.1"
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "has-value": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "get-value": "2.0.6",
+            "has-values": "1.0.0",
+            "isobject": "3.0.1"
+          },
+          "dependencies": {
+            "isobject": {
+              "version": "3.0.1",
+              "bundled": true,
+              "dev": true
+            }
+          }
+        },
+        "has-values": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "is-number": "3.0.0",
+            "kind-of": "4.0.0"
+          },
+          "dependencies": {
+            "is-number": {
+              "version": "3.0.0",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "kind-of": "3.2.2"
+              },
+              "dependencies": {
+                "kind-of": {
+                  "version": "3.2.2",
+                  "bundled": true,
+                  "dev": true,
+                  "requires": {
+                    "is-buffer": "1.1.6"
+                  }
+                }
+              }
+            },
+            "kind-of": {
+              "version": "4.0.0",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "is-buffer": "1.1.6"
+              }
+            }
+          }
+        },
+        "hosted-git-info": {
+          "version": "2.6.0",
+          "bundled": true,
+          "dev": true
+        },
+        "imurmurhash": {
+          "version": "0.1.4",
+          "bundled": true,
+          "dev": true
+        },
+        "inflight": {
+          "version": "1.0.6",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "once": "1.4.0",
+            "wrappy": "1.0.2"
+          }
+        },
+        "inherits": {
+          "version": "2.0.3",
+          "bundled": true,
+          "dev": true
+        },
+        "invariant": {
+          "version": "2.2.4",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "loose-envify": "1.3.1"
+          }
+        },
+        "invert-kv": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "is-accessor-descriptor": {
+          "version": "0.1.6",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "kind-of": "3.2.2"
+          }
+        },
+        "is-arrayish": {
+          "version": "0.2.1",
+          "bundled": true,
+          "dev": true
+        },
+        "is-buffer": {
+          "version": "1.1.6",
+          "bundled": true,
+          "dev": true
+        },
+        "is-builtin-module": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "builtin-modules": "1.1.1"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "0.1.4",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "kind-of": "3.2.2"
+          }
+        },
+        "is-descriptor": {
+          "version": "0.1.6",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "0.1.6",
+            "is-data-descriptor": "0.1.4",
+            "kind-of": "5.1.0"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "5.1.0",
+              "bundled": true,
+              "dev": true
+            }
+          }
+        },
+        "is-extendable": {
+          "version": "0.1.1",
+          "bundled": true,
+          "dev": true
+        },
+        "is-finite": {
+          "version": "1.0.2",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "number-is-nan": "1.0.1"
+          }
+        },
+        "is-fullwidth-code-point": {
+          "version": "2.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "is-number": {
+          "version": "3.0.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "kind-of": "3.2.2"
+          }
+        },
+        "is-odd": {
+          "version": "2.0.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "is-number": "4.0.0"
+          },
+          "dependencies": {
+            "is-number": {
+              "version": "4.0.0",
+              "bundled": true,
+              "dev": true
+            }
+          }
+        },
+        "is-plain-object": {
+          "version": "2.0.4",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "isobject": "3.0.1"
+          },
+          "dependencies": {
+            "isobject": {
+              "version": "3.0.1",
+              "bundled": true,
+              "dev": true
+            }
+          }
+        },
+        "is-stream": {
+          "version": "1.1.0",
+          "bundled": true,
+          "dev": true
+        },
+        "is-utf8": {
+          "version": "0.2.1",
+          "bundled": true,
+          "dev": true
+        },
+        "is-windows": {
+          "version": "1.0.2",
+          "bundled": true,
+          "dev": true
+        },
+        "isarray": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "isexe": {
+          "version": "2.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "isobject": {
+          "version": "3.0.1",
+          "bundled": true,
+          "dev": true
+        },
+        "istanbul-lib-coverage": {
+          "version": "1.2.0",
+          "bundled": true,
+          "dev": true
+        },
+        "istanbul-lib-hook": {
+          "version": "1.1.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "append-transform": "0.4.0"
+          }
+        },
+        "istanbul-lib-instrument": {
+          "version": "1.10.1",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "babel-generator": "6.26.1",
+            "babel-template": "6.26.0",
+            "babel-traverse": "6.26.0",
+            "babel-types": "6.26.0",
+            "babylon": "6.18.0",
+            "istanbul-lib-coverage": "1.2.0",
+            "semver": "5.5.0"
+          }
+        },
+        "istanbul-lib-report": {
+          "version": "1.1.3",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "istanbul-lib-coverage": "1.2.0",
+            "mkdirp": "0.5.1",
+            "path-parse": "1.0.5",
+            "supports-color": "3.2.3"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "3.2.3",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "has-flag": "1.0.0"
+              }
+            }
+          }
+        },
+        "istanbul-lib-source-maps": {
+          "version": "1.2.3",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "debug": "3.1.0",
+            "istanbul-lib-coverage": "1.2.0",
+            "mkdirp": "0.5.1",
+            "rimraf": "2.6.2",
+            "source-map": "0.5.7"
+          },
+          "dependencies": {
+            "debug": {
+              "version": "3.1.0",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "ms": "2.0.0"
+              }
+            }
+          }
+        },
+        "istanbul-reports": {
+          "version": "1.4.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "handlebars": "4.0.11"
+          }
+        },
+        "js-tokens": {
+          "version": "3.0.2",
+          "bundled": true,
+          "dev": true
+        },
+        "jsesc": {
+          "version": "1.3.0",
+          "bundled": true,
+          "dev": true
+        },
+        "kind-of": {
+          "version": "3.2.2",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "is-buffer": "1.1.6"
+          }
+        },
+        "lazy-cache": {
+          "version": "1.0.4",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "lcid": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "invert-kv": "1.0.0"
+          }
+        },
+        "load-json-file": {
+          "version": "1.1.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "graceful-fs": "4.1.11",
+            "parse-json": "2.2.0",
+            "pify": "2.3.0",
+            "pinkie-promise": "2.0.1",
+            "strip-bom": "2.0.0"
+          }
+        },
+        "locate-path": {
+          "version": "2.0.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "p-locate": "2.0.0",
+            "path-exists": "3.0.0"
+          },
+          "dependencies": {
+            "path-exists": {
+              "version": "3.0.0",
+              "bundled": true,
+              "dev": true
+            }
+          }
+        },
+        "lodash": {
+          "version": "4.17.10",
+          "bundled": true,
+          "dev": true
+        },
+        "longest": {
+          "version": "1.0.1",
+          "bundled": true,
+          "dev": true
+        },
+        "loose-envify": {
+          "version": "1.3.1",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "js-tokens": "3.0.2"
+          }
+        },
+        "lru-cache": {
+          "version": "4.1.3",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "pseudomap": "1.0.2",
+            "yallist": "2.1.2"
+          }
+        },
+        "map-cache": {
+          "version": "0.2.2",
+          "bundled": true,
+          "dev": true
+        },
+        "map-visit": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "object-visit": "1.0.1"
+          }
+        },
+        "md5-hex": {
+          "version": "1.3.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "md5-o-matic": "0.1.1"
+          }
+        },
+        "md5-o-matic": {
+          "version": "0.1.1",
+          "bundled": true,
+          "dev": true
+        },
+        "mem": {
+          "version": "1.1.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "mimic-fn": "1.2.0"
+          }
+        },
+        "merge-source-map": {
+          "version": "1.1.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "source-map": "0.6.1"
+          },
+          "dependencies": {
+            "source-map": {
+              "version": "0.6.1",
+              "bundled": true,
+              "dev": true
+            }
+          }
+        },
+        "micromatch": {
+          "version": "3.1.10",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "arr-diff": "4.0.0",
+            "array-unique": "0.3.2",
+            "braces": "2.3.2",
+            "define-property": "2.0.2",
+            "extend-shallow": "3.0.2",
+            "extglob": "2.0.4",
+            "fragment-cache": "0.2.1",
+            "kind-of": "6.0.2",
+            "nanomatch": "1.2.9",
+            "object.pick": "1.3.0",
+            "regex-not": "1.0.2",
+            "snapdragon": "0.8.2",
+            "to-regex": "3.0.2"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "6.0.2",
+              "bundled": true,
+              "dev": true
+            }
+          }
+        },
+        "mimic-fn": {
+          "version": "1.2.0",
+          "bundled": true,
+          "dev": true
+        },
+        "minimatch": {
+          "version": "3.0.4",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "brace-expansion": "1.1.11"
+          }
+        },
+        "minimist": {
+          "version": "0.0.8",
+          "bundled": true,
+          "dev": true
+        },
+        "mixin-deep": {
+          "version": "1.3.1",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "for-in": "1.0.2",
+            "is-extendable": "1.0.1"
+          },
+          "dependencies": {
+            "is-extendable": {
+              "version": "1.0.1",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "is-plain-object": "2.0.4"
+              }
+            }
+          }
+        },
+        "mkdirp": {
+          "version": "0.5.1",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "minimist": "0.0.8"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "nanomatch": {
+          "version": "1.2.9",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "arr-diff": "4.0.0",
+            "array-unique": "0.3.2",
+            "define-property": "2.0.2",
+            "extend-shallow": "3.0.2",
+            "fragment-cache": "0.2.1",
+            "is-odd": "2.0.0",
+            "is-windows": "1.0.2",
+            "kind-of": "6.0.2",
+            "object.pick": "1.3.0",
+            "regex-not": "1.0.2",
+            "snapdragon": "0.8.2",
+            "to-regex": "3.0.2"
+          },
+          "dependencies": {
+            "arr-diff": {
+              "version": "4.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "array-unique": {
+              "version": "0.3.2",
+              "bundled": true,
+              "dev": true
+            },
+            "kind-of": {
+              "version": "6.0.2",
+              "bundled": true,
+              "dev": true
+            }
+          }
+        },
+        "normalize-package-data": {
+          "version": "2.4.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "hosted-git-info": "2.6.0",
+            "is-builtin-module": "1.0.0",
+            "semver": "5.5.0",
+            "validate-npm-package-license": "3.0.3"
+          }
+        },
+        "npm-run-path": {
+          "version": "2.0.2",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "path-key": "2.0.1"
+          }
+        },
+        "number-is-nan": {
+          "version": "1.0.1",
+          "bundled": true,
+          "dev": true
+        },
+        "object-assign": {
+          "version": "4.1.1",
+          "bundled": true,
+          "dev": true
+        },
+        "object-copy": {
+          "version": "0.1.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "copy-descriptor": "0.1.1",
+            "define-property": "0.2.5",
+            "kind-of": "3.2.2"
+          },
+          "dependencies": {
+            "define-property": {
+              "version": "0.2.5",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "is-descriptor": "0.1.6"
+              }
+            }
+          }
+        },
+        "object-visit": {
+          "version": "1.0.1",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "isobject": "3.0.1"
+          },
+          "dependencies": {
+            "isobject": {
+              "version": "3.0.1",
+              "bundled": true,
+              "dev": true
+            }
+          }
+        },
+        "object.pick": {
+          "version": "1.3.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "isobject": "3.0.1"
+          },
+          "dependencies": {
+            "isobject": {
+              "version": "3.0.1",
+              "bundled": true,
+              "dev": true
+            }
+          }
+        },
+        "once": {
+          "version": "1.4.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "wrappy": "1.0.2"
+          }
+        },
+        "optimist": {
+          "version": "0.6.1",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "minimist": "0.0.8",
+            "wordwrap": "0.0.3"
+          }
+        },
+        "os-homedir": {
+          "version": "1.0.2",
+          "bundled": true,
+          "dev": true
+        },
+        "os-locale": {
+          "version": "2.1.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "execa": "0.7.0",
+            "lcid": "1.0.0",
+            "mem": "1.1.0"
+          }
+        },
+        "p-finally": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "p-limit": {
+          "version": "1.2.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "p-try": "1.0.0"
+          }
+        },
+        "p-locate": {
+          "version": "2.0.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "p-limit": "1.2.0"
+          }
+        },
+        "p-try": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "parse-json": {
+          "version": "2.2.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "error-ex": "1.3.1"
+          }
+        },
+        "pascalcase": {
+          "version": "0.1.1",
+          "bundled": true,
+          "dev": true
+        },
+        "path-exists": {
+          "version": "2.1.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "pinkie-promise": "2.0.1"
+          }
+        },
+        "path-is-absolute": {
+          "version": "1.0.1",
+          "bundled": true,
+          "dev": true
+        },
+        "path-key": {
+          "version": "2.0.1",
+          "bundled": true,
+          "dev": true
+        },
+        "path-parse": {
+          "version": "1.0.5",
+          "bundled": true,
+          "dev": true
+        },
+        "path-type": {
+          "version": "1.1.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "graceful-fs": "4.1.11",
+            "pify": "2.3.0",
+            "pinkie-promise": "2.0.1"
+          }
+        },
+        "pify": {
+          "version": "2.3.0",
+          "bundled": true,
+          "dev": true
+        },
+        "pinkie": {
+          "version": "2.0.4",
+          "bundled": true,
+          "dev": true
+        },
+        "pinkie-promise": {
+          "version": "2.0.1",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "pinkie": "2.0.4"
+          }
+        },
+        "pkg-dir": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "find-up": "1.1.2"
+          },
+          "dependencies": {
+            "find-up": {
+              "version": "1.1.2",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "path-exists": "2.1.0",
+                "pinkie-promise": "2.0.1"
+              }
+            }
+          }
+        },
+        "posix-character-classes": {
+          "version": "0.1.1",
+          "bundled": true,
+          "dev": true
+        },
+        "pseudomap": {
+          "version": "1.0.2",
+          "bundled": true,
+          "dev": true
+        },
+        "read-pkg": {
+          "version": "1.1.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "load-json-file": "1.1.0",
+            "normalize-package-data": "2.4.0",
+            "path-type": "1.1.0"
+          }
+        },
+        "read-pkg-up": {
+          "version": "1.0.1",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "find-up": "1.1.2",
+            "read-pkg": "1.1.0"
+          },
+          "dependencies": {
+            "find-up": {
+              "version": "1.1.2",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "path-exists": "2.1.0",
+                "pinkie-promise": "2.0.1"
+              }
+            }
+          }
+        },
+        "regenerator-runtime": {
+          "version": "0.11.1",
+          "bundled": true,
+          "dev": true
+        },
+        "regex-not": {
+          "version": "1.0.2",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "extend-shallow": "3.0.2",
+            "safe-regex": "1.1.0"
+          }
+        },
+        "repeat-element": {
+          "version": "1.1.2",
+          "bundled": true,
+          "dev": true
+        },
+        "repeat-string": {
+          "version": "1.6.1",
+          "bundled": true,
+          "dev": true
+        },
+        "repeating": {
+          "version": "2.0.1",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "is-finite": "1.0.2"
+          }
+        },
+        "require-directory": {
+          "version": "2.1.1",
+          "bundled": true,
+          "dev": true
+        },
+        "require-main-filename": {
+          "version": "1.0.1",
+          "bundled": true,
+          "dev": true
+        },
+        "resolve-from": {
+          "version": "2.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "resolve-url": {
+          "version": "0.2.1",
+          "bundled": true,
+          "dev": true
+        },
+        "ret": {
+          "version": "0.1.15",
+          "bundled": true,
+          "dev": true
+        },
+        "right-align": {
+          "version": "0.1.3",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "align-text": "0.1.4"
+          }
+        },
+        "rimraf": {
+          "version": "2.6.2",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "glob": "7.1.2"
+          }
+        },
+        "safe-regex": {
+          "version": "1.1.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "ret": "0.1.15"
+          }
+        },
+        "semver": {
+          "version": "5.5.0",
+          "bundled": true,
+          "dev": true
+        },
+        "set-blocking": {
+          "version": "2.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "set-value": {
+          "version": "2.0.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "extend-shallow": "2.0.1",
+            "is-extendable": "0.1.1",
+            "is-plain-object": "2.0.4",
+            "split-string": "3.1.0"
+          },
+          "dependencies": {
+            "extend-shallow": {
+              "version": "2.0.1",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "is-extendable": "0.1.1"
+              }
+            }
+          }
+        },
+        "shebang-command": {
+          "version": "1.2.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "shebang-regex": "1.0.0"
+          }
+        },
+        "shebang-regex": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "signal-exit": {
+          "version": "3.0.2",
+          "bundled": true,
+          "dev": true
+        },
+        "slide": {
+          "version": "1.1.6",
+          "bundled": true,
+          "dev": true
+        },
+        "snapdragon": {
+          "version": "0.8.2",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "base": "0.11.2",
+            "debug": "2.6.9",
+            "define-property": "0.2.5",
+            "extend-shallow": "2.0.1",
+            "map-cache": "0.2.2",
+            "source-map": "0.5.7",
+            "source-map-resolve": "0.5.1",
+            "use": "3.1.0"
+          },
+          "dependencies": {
+            "define-property": {
+              "version": "0.2.5",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "is-descriptor": "0.1.6"
+              }
+            },
+            "extend-shallow": {
+              "version": "2.0.1",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "is-extendable": "0.1.1"
+              }
+            }
+          }
+        },
+        "snapdragon-node": {
+          "version": "2.1.1",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "define-property": "1.0.0",
+            "isobject": "3.0.1",
+            "snapdragon-util": "3.0.1"
+          },
+          "dependencies": {
+            "define-property": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "is-descriptor": "1.0.2"
+              }
+            },
+            "is-accessor-descriptor": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "kind-of": "6.0.2"
+              }
+            },
+            "is-data-descriptor": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "kind-of": "6.0.2"
+              }
+            },
+            "is-descriptor": {
+              "version": "1.0.2",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "is-accessor-descriptor": "1.0.0",
+                "is-data-descriptor": "1.0.0",
+                "kind-of": "6.0.2"
+              }
+            },
+            "isobject": {
+              "version": "3.0.1",
+              "bundled": true,
+              "dev": true
+            },
+            "kind-of": {
+              "version": "6.0.2",
+              "bundled": true,
+              "dev": true
+            }
+          }
+        },
+        "snapdragon-util": {
+          "version": "3.0.1",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "kind-of": "3.2.2"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "bundled": true,
+          "dev": true
+        },
+        "source-map-resolve": {
+          "version": "0.5.1",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "atob": "2.1.1",
+            "decode-uri-component": "0.2.0",
+            "resolve-url": "0.2.1",
+            "source-map-url": "0.4.0",
+            "urix": "0.1.0"
+          }
+        },
+        "source-map-url": {
+          "version": "0.4.0",
+          "bundled": true,
+          "dev": true
+        },
+        "spawn-wrap": {
+          "version": "1.4.2",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "foreground-child": "1.5.6",
+            "mkdirp": "0.5.1",
+            "os-homedir": "1.0.2",
+            "rimraf": "2.6.2",
+            "signal-exit": "3.0.2",
+            "which": "1.3.0"
+          }
+        },
+        "spdx-correct": {
+          "version": "3.0.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "spdx-expression-parse": "3.0.0",
+            "spdx-license-ids": "3.0.0"
+          }
+        },
+        "spdx-exceptions": {
+          "version": "2.1.0",
+          "bundled": true,
+          "dev": true
+        },
+        "spdx-expression-parse": {
+          "version": "3.0.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "spdx-exceptions": "2.1.0",
+            "spdx-license-ids": "3.0.0"
+          }
+        },
+        "spdx-license-ids": {
+          "version": "3.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "split-string": {
+          "version": "3.1.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "extend-shallow": "3.0.2"
+          }
+        },
+        "static-extend": {
+          "version": "0.1.2",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "define-property": "0.2.5",
+            "object-copy": "0.1.0"
+          },
+          "dependencies": {
+            "define-property": {
+              "version": "0.2.5",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "is-descriptor": "0.1.6"
+              }
+            }
+          }
+        },
+        "string-width": {
+          "version": "2.1.1",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "is-fullwidth-code-point": "2.0.0",
+            "strip-ansi": "4.0.0"
+          },
+          "dependencies": {
+            "ansi-regex": {
+              "version": "3.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "strip-ansi": {
+              "version": "4.0.0",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "ansi-regex": "3.0.0"
+              }
+            }
+          }
+        },
+        "strip-ansi": {
+          "version": "3.0.1",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "ansi-regex": "2.1.1"
+          }
+        },
+        "strip-bom": {
+          "version": "2.0.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "is-utf8": "0.2.1"
+          }
+        },
+        "strip-eof": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "supports-color": {
+          "version": "2.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "test-exclude": {
+          "version": "4.2.1",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "arrify": "1.0.1",
+            "micromatch": "3.1.10",
+            "object-assign": "4.1.1",
+            "read-pkg-up": "1.0.1",
+            "require-main-filename": "1.0.1"
+          },
+          "dependencies": {
+            "arr-diff": {
+              "version": "4.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "array-unique": {
+              "version": "0.3.2",
+              "bundled": true,
+              "dev": true
+            },
+            "braces": {
+              "version": "2.3.2",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "arr-flatten": "1.1.0",
+                "array-unique": "0.3.2",
+                "extend-shallow": "2.0.1",
+                "fill-range": "4.0.0",
+                "isobject": "3.0.1",
+                "repeat-element": "1.1.2",
+                "snapdragon": "0.8.2",
+                "snapdragon-node": "2.1.1",
+                "split-string": "3.1.0",
+                "to-regex": "3.0.2"
+              },
+              "dependencies": {
+                "extend-shallow": {
+                  "version": "2.0.1",
+                  "bundled": true,
+                  "dev": true,
+                  "requires": {
+                    "is-extendable": "0.1.1"
+                  }
+                }
+              }
+            },
+            "expand-brackets": {
+              "version": "2.1.4",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "debug": "2.6.9",
+                "define-property": "0.2.5",
+                "extend-shallow": "2.0.1",
+                "posix-character-classes": "0.1.1",
+                "regex-not": "1.0.2",
+                "snapdragon": "0.8.2",
+                "to-regex": "3.0.2"
+              },
+              "dependencies": {
+                "define-property": {
+                  "version": "0.2.5",
+                  "bundled": true,
+                  "dev": true,
+                  "requires": {
+                    "is-descriptor": "0.1.6"
+                  }
+                },
+                "extend-shallow": {
+                  "version": "2.0.1",
+                  "bundled": true,
+                  "dev": true,
+                  "requires": {
+                    "is-extendable": "0.1.1"
+                  }
+                },
+                "is-accessor-descriptor": {
+                  "version": "0.1.6",
+                  "bundled": true,
+                  "dev": true,
+                  "requires": {
+                    "kind-of": "3.2.2"
+                  },
+                  "dependencies": {
+                    "kind-of": {
+                      "version": "3.2.2",
+                      "bundled": true,
+                      "dev": true,
+                      "requires": {
+                        "is-buffer": "1.1.6"
+                      }
+                    }
+                  }
+                },
+                "is-data-descriptor": {
+                  "version": "0.1.4",
+                  "bundled": true,
+                  "dev": true,
+                  "requires": {
+                    "kind-of": "3.2.2"
+                  },
+                  "dependencies": {
+                    "kind-of": {
+                      "version": "3.2.2",
+                      "bundled": true,
+                      "dev": true,
+                      "requires": {
+                        "is-buffer": "1.1.6"
+                      }
+                    }
+                  }
+                },
+                "is-descriptor": {
+                  "version": "0.1.6",
+                  "bundled": true,
+                  "dev": true,
+                  "requires": {
+                    "is-accessor-descriptor": "0.1.6",
+                    "is-data-descriptor": "0.1.4",
+                    "kind-of": "5.1.0"
+                  }
+                },
+                "kind-of": {
+                  "version": "5.1.0",
+                  "bundled": true,
+                  "dev": true
+                }
+              }
+            },
+            "extglob": {
+              "version": "2.0.4",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "array-unique": "0.3.2",
+                "define-property": "1.0.0",
+                "expand-brackets": "2.1.4",
+                "extend-shallow": "2.0.1",
+                "fragment-cache": "0.2.1",
+                "regex-not": "1.0.2",
+                "snapdragon": "0.8.2",
+                "to-regex": "3.0.2"
+              },
+              "dependencies": {
+                "define-property": {
+                  "version": "1.0.0",
+                  "bundled": true,
+                  "dev": true,
+                  "requires": {
+                    "is-descriptor": "1.0.2"
+                  }
+                },
+                "extend-shallow": {
+                  "version": "2.0.1",
+                  "bundled": true,
+                  "dev": true,
+                  "requires": {
+                    "is-extendable": "0.1.1"
+                  }
+                }
+              }
+            },
+            "fill-range": {
+              "version": "4.0.0",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "extend-shallow": "2.0.1",
+                "is-number": "3.0.0",
+                "repeat-string": "1.6.1",
+                "to-regex-range": "2.1.1"
+              },
+              "dependencies": {
+                "extend-shallow": {
+                  "version": "2.0.1",
+                  "bundled": true,
+                  "dev": true,
+                  "requires": {
+                    "is-extendable": "0.1.1"
+                  }
+                }
+              }
+            },
+            "is-accessor-descriptor": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "kind-of": "6.0.2"
+              }
+            },
+            "is-data-descriptor": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "kind-of": "6.0.2"
+              }
+            },
+            "is-descriptor": {
+              "version": "1.0.2",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "is-accessor-descriptor": "1.0.0",
+                "is-data-descriptor": "1.0.0",
+                "kind-of": "6.0.2"
+              }
+            },
+            "is-number": {
+              "version": "3.0.0",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "kind-of": "3.2.2"
+              },
+              "dependencies": {
+                "kind-of": {
+                  "version": "3.2.2",
+                  "bundled": true,
+                  "dev": true,
+                  "requires": {
+                    "is-buffer": "1.1.6"
+                  }
+                }
+              }
+            },
+            "isobject": {
+              "version": "3.0.1",
+              "bundled": true,
+              "dev": true
+            },
+            "kind-of": {
+              "version": "6.0.2",
+              "bundled": true,
+              "dev": true
+            },
+            "micromatch": {
+              "version": "3.1.10",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "arr-diff": "4.0.0",
+                "array-unique": "0.3.2",
+                "braces": "2.3.2",
+                "define-property": "2.0.2",
+                "extend-shallow": "3.0.2",
+                "extglob": "2.0.4",
+                "fragment-cache": "0.2.1",
+                "kind-of": "6.0.2",
+                "nanomatch": "1.2.9",
+                "object.pick": "1.3.0",
+                "regex-not": "1.0.2",
+                "snapdragon": "0.8.2",
+                "to-regex": "3.0.2"
+              }
+            }
+          }
+        },
+        "to-fast-properties": {
+          "version": "1.0.3",
+          "bundled": true,
+          "dev": true
+        },
+        "to-object-path": {
+          "version": "0.3.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "kind-of": "3.2.2"
+          }
+        },
+        "to-regex": {
+          "version": "3.0.2",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "define-property": "2.0.2",
+            "extend-shallow": "3.0.2",
+            "regex-not": "1.0.2",
+            "safe-regex": "1.1.0"
+          }
+        },
+        "to-regex-range": {
+          "version": "2.1.1",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "is-number": "3.0.0",
+            "repeat-string": "1.6.1"
+          },
+          "dependencies": {
+            "is-number": {
+              "version": "3.0.0",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "kind-of": "3.2.2"
+              }
+            }
+          }
+        },
+        "trim-right": {
+          "version": "1.0.1",
+          "bundled": true,
+          "dev": true
+        },
+        "uglify-js": {
+          "version": "2.8.29",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "source-map": "0.5.7",
+            "uglify-to-browserify": "1.0.2",
+            "yargs": "3.10.0"
+          },
+          "dependencies": {
+            "yargs": {
+              "version": "3.10.0",
+              "bundled": true,
+              "dev": true,
+              "optional": true,
+              "requires": {
+                "camelcase": "1.2.1",
+                "cliui": "2.1.0",
+                "decamelize": "1.2.0",
+                "window-size": "0.1.0"
+              }
+            }
+          }
+        },
+        "uglify-to-browserify": {
+          "version": "1.0.2",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "union-value": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "arr-union": "3.1.0",
+            "get-value": "2.0.6",
+            "is-extendable": "0.1.1",
+            "set-value": "0.4.3"
+          },
+          "dependencies": {
+            "extend-shallow": {
+              "version": "2.0.1",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "is-extendable": "0.1.1"
+              }
+            },
+            "set-value": {
+              "version": "0.4.3",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "extend-shallow": "2.0.1",
+                "is-extendable": "0.1.1",
+                "is-plain-object": "2.0.4",
+                "to-object-path": "0.3.0"
+              }
+            }
+          }
+        },
+        "unset-value": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "has-value": "0.3.1",
+            "isobject": "3.0.1"
+          },
+          "dependencies": {
+            "has-value": {
+              "version": "0.3.1",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "get-value": "2.0.6",
+                "has-values": "0.1.4",
+                "isobject": "2.1.0"
+              },
+              "dependencies": {
+                "isobject": {
+                  "version": "2.1.0",
+                  "bundled": true,
+                  "dev": true,
+                  "requires": {
+                    "isarray": "1.0.0"
+                  }
+                }
+              }
+            },
+            "has-values": {
+              "version": "0.1.4",
+              "bundled": true,
+              "dev": true
+            },
+            "isobject": {
+              "version": "3.0.1",
+              "bundled": true,
+              "dev": true
+            }
+          }
+        },
+        "urix": {
+          "version": "0.1.0",
+          "bundled": true,
+          "dev": true
+        },
+        "use": {
+          "version": "3.1.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "kind-of": "6.0.2"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "6.0.2",
+              "bundled": true,
+              "dev": true
+            }
+          }
+        },
+        "validate-npm-package-license": {
+          "version": "3.0.3",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "spdx-correct": "3.0.0",
+            "spdx-expression-parse": "3.0.0"
+          }
+        },
+        "which": {
+          "version": "1.3.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "isexe": "2.0.0"
+          }
+        },
+        "which-module": {
+          "version": "2.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "window-size": {
+          "version": "0.1.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "wordwrap": {
+          "version": "0.0.3",
+          "bundled": true,
+          "dev": true
+        },
+        "wrap-ansi": {
+          "version": "2.1.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "string-width": "1.0.2",
+            "strip-ansi": "3.0.1"
+          },
+          "dependencies": {
+            "is-fullwidth-code-point": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "number-is-nan": "1.0.1"
+              }
+            },
+            "string-width": {
+              "version": "1.0.2",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "code-point-at": "1.1.0",
+                "is-fullwidth-code-point": "1.0.0",
+                "strip-ansi": "3.0.1"
+              }
+            }
+          }
+        },
+        "wrappy": {
+          "version": "1.0.2",
+          "bundled": true,
+          "dev": true
+        },
+        "write-file-atomic": {
+          "version": "1.3.4",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "graceful-fs": "4.1.11",
+            "imurmurhash": "0.1.4",
+            "slide": "1.1.6"
+          }
+        },
+        "y18n": {
+          "version": "3.2.1",
+          "bundled": true,
+          "dev": true
+        },
+        "yallist": {
+          "version": "2.1.2",
+          "bundled": true,
+          "dev": true
+        },
+        "yargs": {
+          "version": "11.1.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "cliui": "4.1.0",
+            "decamelize": "1.2.0",
+            "find-up": "2.1.0",
+            "get-caller-file": "1.0.2",
+            "os-locale": "2.1.0",
+            "require-directory": "2.1.1",
+            "require-main-filename": "1.0.1",
+            "set-blocking": "2.0.0",
+            "string-width": "2.1.1",
+            "which-module": "2.0.0",
+            "y18n": "3.2.1",
+            "yargs-parser": "9.0.2"
+          },
+          "dependencies": {
+            "ansi-regex": {
+              "version": "3.0.0",
+              "bundled": true,
+              "dev": true
+            },
+            "camelcase": {
+              "version": "4.1.0",
+              "bundled": true,
+              "dev": true
+            },
+            "cliui": {
+              "version": "4.1.0",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "string-width": "2.1.1",
+                "strip-ansi": "4.0.0",
+                "wrap-ansi": "2.1.0"
+              }
+            },
+            "strip-ansi": {
+              "version": "4.0.0",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "ansi-regex": "3.0.0"
+              }
+            },
+            "yargs-parser": {
+              "version": "9.0.2",
+              "bundled": true,
+              "dev": true,
+              "requires": {
+                "camelcase": "4.1.0"
+              }
+            }
+          }
+        },
+        "yargs-parser": {
+          "version": "8.1.0",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "camelcase": "4.1.0"
+          },
+          "dependencies": {
+            "camelcase": {
+              "version": "4.1.0",
+              "bundled": true,
+              "dev": true
+            }
+          }
+        }
+      }
+    },
+    "oauth-sign": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
+      "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM="
+    },
+    "object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+    },
+    "on-finished": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+      "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+      "requires": {
+        "ee-first": "1.1.1"
+      }
+    },
+    "on-headers": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz",
+      "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c="
+    },
+    "once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "requires": {
+        "wrappy": "1.0.2"
+      }
+    },
+    "onetime": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
+      "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+      "requires": {
+        "mimic-fn": "1.2.0"
+      }
+    },
+    "optimist": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
+      "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
+      "requires": {
+        "minimist": "0.0.10",
+        "wordwrap": "0.0.3"
+      }
+    },
+    "optionator": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
+      "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
+      "dev": true,
+      "requires": {
+        "deep-is": "0.1.3",
+        "fast-levenshtein": "2.0.6",
+        "levn": "0.3.0",
+        "prelude-ls": "1.1.2",
+        "type-check": "0.3.2",
+        "wordwrap": "1.0.0"
+      },
+      "dependencies": {
+        "wordwrap": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+          "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
+          "dev": true
+        }
+      }
+    },
+    "options": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz",
+      "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8="
+    },
+    "os-homedir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+      "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
+    },
+    "os-tmpdir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+      "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
+    },
+    "osenv": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
+      "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
+      "requires": {
+        "os-homedir": "1.0.2",
+        "os-tmpdir": "1.0.2"
+      }
+    },
+    "over": {
+      "version": "0.0.5",
+      "resolved": "https://registry.npmjs.org/over/-/over-0.0.5.tgz",
+      "integrity": "sha1-8phS5w/X4l82DgE6jsRMgq7bVwg="
+    },
+    "parse-passwd": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+      "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
+      "dev": true
+    },
+    "parseurl": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
+      "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="
+    },
+    "path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+    },
+    "path-is-inside": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
+      "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
+      "dev": true
+    },
+    "path-parse": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
+      "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME="
+    },
+    "path-to-regexp": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+      "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+    },
+    "pause-stream": {
+      "version": "0.0.11",
+      "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
+      "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=",
+      "requires": {
+        "through": "2.3.8"
+      }
+    },
+    "performance-now": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz",
+      "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU="
+    },
+    "pify": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+      "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+      "dev": true
+    },
+    "pinkie": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+      "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+      "dev": true
+    },
+    "pinkie-promise": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+      "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+      "dev": true,
+      "requires": {
+        "pinkie": "2.0.4"
+      }
+    },
+    "pluralize": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz",
+      "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=",
+      "dev": true
+    },
+    "prelude-ls": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+      "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+      "dev": true
+    },
+    "process-nextick-args": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+      "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
+    },
+    "progress": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz",
+      "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8="
+    },
+    "proxy-addr": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.5.tgz",
+      "integrity": "sha1-ccDuOxAt4/IC87ZPYI0XP8uhqRg=",
+      "requires": {
+        "forwarded": "0.1.2",
+        "ipaddr.js": "1.4.0"
+      }
+    },
+    "pullstream": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/pullstream/-/pullstream-0.4.1.tgz",
+      "integrity": "sha1-1vs79a7Wl+gxFQ6xACwlo/iuExQ=",
+      "requires": {
+        "over": "0.0.5",
+        "readable-stream": "1.0.34",
+        "setimmediate": "1.0.5",
+        "slice-stream": "1.0.0"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "0.0.1",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+          "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+        },
+        "readable-stream": {
+          "version": "1.0.34",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
+          "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
+          "requires": {
+            "core-util-is": "1.0.2",
+            "inherits": "2.0.3",
+            "isarray": "0.0.1",
+            "string_decoder": "0.10.31"
+          }
+        },
+        "string_decoder": {
+          "version": "0.10.31",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+          "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+        }
+      }
+    },
+    "punycode": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+      "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
+    },
+    "q": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
+      "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc="
+    },
+    "q-io": {
+      "version": "1.13.5",
+      "resolved": "https://registry.npmjs.org/q-io/-/q-io-1.13.5.tgz",
+      "integrity": "sha1-asOd61z+DcaENub4wz0NfD9HG7I=",
+      "requires": {
+        "collections": "0.2.2",
+        "mime": "1.2.11",
+        "mimeparse": "0.1.4",
+        "q": "1.5.1",
+        "qs": "6.4.0",
+        "url2": "0.0.0"
+      }
+    },
+    "qs": {
+      "version": "6.4.0",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz",
+      "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM="
+    },
+    "querablep": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/querablep/-/querablep-0.1.0.tgz",
+      "integrity": "sha1-ss0rPnX81F1d163kwYEatUeEmoQ="
+    },
+    "ramda": {
+      "version": "0.22.1",
+      "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.22.1.tgz",
+      "integrity": "sha1-Ax2gw99BfFszyWI0dX6zcDPzag4=",
+      "dev": true
+    },
+    "range-parser": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
+      "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4="
+    },
+    "raw-body": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.2.0.tgz",
+      "integrity": "sha1-mUl2z2pQlqQRYoQEkvC9xdbn+5Y=",
+      "requires": {
+        "bytes": "2.4.0",
+        "iconv-lite": "0.4.15",
+        "unpipe": "1.0.0"
+      }
+    },
+    "rc": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+      "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+      "requires": {
+        "deep-extend": "0.6.0",
+        "ini": "1.3.5",
+        "minimist": "1.2.0",
+        "strip-json-comments": "2.0.1"
+      },
+      "dependencies": {
+        "minimist": {
+          "version": "1.2.0",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+        }
+      }
+    },
+    "readable-stream": {
+      "version": "2.3.6",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+      "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+      "requires": {
+        "core-util-is": "1.0.2",
+        "inherits": "2.0.3",
+        "isarray": "1.0.0",
+        "process-nextick-args": "2.0.0",
+        "safe-buffer": "5.1.2",
+        "string_decoder": "1.1.1",
+        "util-deprecate": "1.0.2"
+      }
+    },
+    "readline2": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz",
+      "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=",
+      "dev": true,
+      "requires": {
+        "code-point-at": "1.1.0",
+        "is-fullwidth-code-point": "1.0.0",
+        "mute-stream": "0.0.5"
+      },
+      "dependencies": {
+        "is-fullwidth-code-point": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+          "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+          "dev": true,
+          "requires": {
+            "number-is-nan": "1.0.1"
+          }
+        },
+        "mute-stream": {
+          "version": "0.0.5",
+          "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz",
+          "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=",
+          "dev": true
+        }
+      }
+    },
+    "rechoir": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
+      "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
+      "requires": {
+        "resolve": "1.8.1"
+      }
+    },
+    "remove-trailing-separator": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+      "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8="
+    },
+    "repeat-string": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+      "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
+    },
+    "request": {
+      "version": "2.81.0",
+      "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz",
+      "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=",
+      "requires": {
+        "aws-sign2": "0.6.0",
+        "aws4": "1.7.0",
+        "caseless": "0.12.0",
+        "combined-stream": "1.0.6",
+        "extend": "3.0.1",
+        "forever-agent": "0.6.1",
+        "form-data": "2.1.4",
+        "har-validator": "4.2.1",
+        "hawk": "3.1.3",
+        "http-signature": "1.1.1",
+        "is-typedarray": "1.0.0",
+        "isstream": "0.1.2",
+        "json-stringify-safe": "5.0.1",
+        "mime-types": "2.1.18",
+        "oauth-sign": "0.8.2",
+        "performance-now": "0.2.0",
+        "qs": "6.4.0",
+        "safe-buffer": "5.1.2",
+        "stringstream": "0.0.6",
+        "tough-cookie": "2.3.4",
+        "tunnel-agent": "0.6.0",
+        "uuid": "3.3.2"
+      },
+      "dependencies": {
+        "caseless": {
+          "version": "0.12.0",
+          "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+          "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
+        },
+        "uuid": {
+          "version": "3.3.2",
+          "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
+          "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
+        }
+      }
+    },
+    "request-promise": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.0.tgz",
+      "integrity": "sha1-aE93dI1rRhe+5qTvRGmQbm0HRyA=",
+      "requires": {
+        "bluebird": "3.5.1",
+        "request-promise-core": "1.1.1",
+        "stealthy-require": "1.1.1"
+      }
+    },
+    "request-promise-core": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz",
+      "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=",
+      "requires": {
+        "lodash": "4.17.10"
+      }
+    },
+    "require-uncached": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz",
+      "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=",
+      "dev": true,
+      "requires": {
+        "caller-path": "0.1.0",
+        "resolve-from": "1.0.1"
+      }
+    },
+    "resolve": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz",
+      "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==",
+      "requires": {
+        "path-parse": "1.0.5"
+      }
+    },
+    "resolve-from": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz",
+      "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=",
+      "dev": true
+    },
+    "response": {
+      "version": "0.18.0",
+      "resolved": "https://registry.npmjs.org/response/-/response-0.18.0.tgz",
+      "integrity": "sha1-oQCfJxcz8jNYLeCpX7TLql6osgY=",
+      "requires": {
+        "best-encoding": "0.1.1",
+        "bl": "0.7.0",
+        "caseless": "0.3.0",
+        "mime": "1.2.11"
+      },
+      "dependencies": {
+        "bl": {
+          "version": "0.7.0",
+          "resolved": "https://registry.npmjs.org/bl/-/bl-0.7.0.tgz",
+          "integrity": "sha1-P7BnBgKsKHjrdw3CA58YNr5irls=",
+          "requires": {
+            "readable-stream": "1.0.34"
+          }
+        },
+        "isarray": {
+          "version": "0.0.1",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+          "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+        },
+        "readable-stream": {
+          "version": "1.0.34",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
+          "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
+          "requires": {
+            "core-util-is": "1.0.2",
+            "inherits": "2.0.3",
+            "isarray": "0.0.1",
+            "string_decoder": "0.10.31"
+          }
+        },
+        "string_decoder": {
+          "version": "0.10.31",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+          "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+        }
+      }
+    },
+    "restore-cursor": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
+      "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
+      "requires": {
+        "onetime": "2.0.1",
+        "signal-exit": "3.0.2"
+      }
+    },
+    "right-align": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
+      "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=",
+      "optional": true,
+      "requires": {
+        "align-text": "0.1.4"
+      }
+    },
+    "rimraf": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
+      "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
+      "requires": {
+        "glob": "7.1.2"
+      }
+    },
+    "run-async": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
+      "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
+      "requires": {
+        "is-promise": "2.1.0"
+      }
+    },
+    "rx": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz",
+      "integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I="
+    },
+    "rx-lite": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz",
+      "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=",
+      "dev": true
+    },
+    "safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+    },
+    "safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+    },
+    "sax": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+      "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
+    },
+    "scryptb": {
+      "version": "6.0.5",
+      "resolved": "https://registry.npmjs.org/scryptb/-/scryptb-6.0.5.tgz",
+      "integrity": "sha512-KeqKAU89M2C5rnqyk9kzY+i7Mru3yv4TKM7HJuwARUQdPJmQWdkG7x3CQITs4J/gVtyCBzkug0YCuIvsdazRvA==",
+      "requires": {
+        "bindings": "1.2.1",
+        "nan": "2.2.0",
+        "node-pre-gyp": "0.6.23"
+      },
+      "dependencies": {
+        "node-pre-gyp": {
+          "version": "0.6.23",
+          "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.6.23.tgz",
+          "integrity": "sha1-FVvzaDq8/N4Aiu2rEkiJGgdz25U=",
+          "requires": {
+            "mkdirp": "0.5.1",
+            "nopt": "3.0.6",
+            "npmlog": "2.0.2",
+            "rc": "1.1.6",
+            "request": "2.69.0",
+            "rimraf": "2.5.2",
+            "semver": "5.1.0",
+            "tar": "2.2.1",
+            "tar-pack": "3.1.3"
+          },
+          "dependencies": {
+            "mkdirp": {
+              "version": "0.5.1",
+              "bundled": true,
+              "requires": {
+                "minimist": "0.0.8"
+              },
+              "dependencies": {
+                "minimist": {
+                  "version": "0.0.8",
+                  "bundled": true
+                }
+              }
+            },
+            "nopt": {
+              "version": "3.0.6",
+              "bundled": true,
+              "requires": {
+                "abbrev": "1.0.7"
+              },
+              "dependencies": {
+                "abbrev": {
+                  "version": "1.0.7",
+                  "bundled": true
+                }
+              }
+            },
+            "npmlog": {
+              "version": "2.0.2",
+              "bundled": true,
+              "requires": {
+                "ansi": "0.3.1",
+                "are-we-there-yet": "1.0.6",
+                "gauge": "1.2.7"
+              },
+              "dependencies": {
+                "ansi": {
+                  "version": "0.3.1",
+                  "bundled": true
+                },
+                "are-we-there-yet": {
+                  "version": "1.0.6",
+                  "bundled": true,
+                  "requires": {
+                    "delegates": "1.0.0",
+                    "readable-stream": "2.0.5"
+                  },
+                  "dependencies": {
+                    "delegates": {
+                      "version": "1.0.0",
+                      "bundled": true
+                    },
+                    "readable-stream": {
+                      "version": "2.0.5",
+                      "bundled": true,
+                      "requires": {
+                        "core-util-is": "1.0.2",
+                        "inherits": "2.0.1",
+                        "isarray": "0.0.1",
+                        "process-nextick-args": "1.0.6",
+                        "string_decoder": "0.10.31",
+                        "util-deprecate": "1.0.2"
+                      },
+                      "dependencies": {
+                        "core-util-is": {
+                          "version": "1.0.2",
+                          "bundled": true
+                        },
+                        "inherits": {
+                          "version": "2.0.1",
+                          "bundled": true
+                        },
+                        "isarray": {
+                          "version": "0.0.1",
+                          "bundled": true
+                        },
+                        "process-nextick-args": {
+                          "version": "1.0.6",
+                          "bundled": true
+                        },
+                        "string_decoder": {
+                          "version": "0.10.31",
+                          "bundled": true
+                        },
+                        "util-deprecate": {
+                          "version": "1.0.2",
+                          "bundled": true
+                        }
+                      }
+                    }
+                  }
+                },
+                "gauge": {
+                  "version": "1.2.7",
+                  "bundled": true,
+                  "requires": {
+                    "ansi": "0.3.1",
+                    "has-unicode": "2.0.0",
+                    "lodash.pad": "4.1.0",
+                    "lodash.padend": "4.2.0",
+                    "lodash.padstart": "4.2.0"
+                  },
+                  "dependencies": {
+                    "has-unicode": {
+                      "version": "2.0.0",
+                      "bundled": true
+                    },
+                    "lodash.pad": {
+                      "version": "4.1.0",
+                      "bundled": true,
+                      "requires": {
+                        "lodash.repeat": "4.0.0",
+                        "lodash.tostring": "4.1.2"
+                      },
+                      "dependencies": {
+                        "lodash.repeat": {
+                          "version": "4.0.0",
+                          "bundled": true,
+                          "requires": {
+                            "lodash.tostring": "4.1.2"
+                          }
+                        },
+                        "lodash.tostring": {
+                          "version": "4.1.2",
+                          "bundled": true
+                        }
+                      }
+                    },
+                    "lodash.padend": {
+                      "version": "4.2.0",
+                      "bundled": true,
+                      "requires": {
+                        "lodash.repeat": "4.0.0",
+                        "lodash.tostring": "4.1.2"
+                      },
+                      "dependencies": {
+                        "lodash.repeat": {
+                          "version": "4.0.0",
+                          "bundled": true,
+                          "requires": {
+                            "lodash.tostring": "4.1.2"
+                          }
+                        },
+                        "lodash.tostring": {
+                          "version": "4.1.2",
+                          "bundled": true
+                        }
+                      }
+                    },
+                    "lodash.padstart": {
+                      "version": "4.2.0",
+                      "bundled": true,
+                      "requires": {
+                        "lodash.repeat": "4.0.0",
+                        "lodash.tostring": "4.1.2"
+                      },
+                      "dependencies": {
+                        "lodash.repeat": {
+                          "version": "4.0.0",
+                          "bundled": true,
+                          "requires": {
+                            "lodash.tostring": "4.1.2"
+                          }
+                        },
+                        "lodash.tostring": {
+                          "version": "4.1.2",
+                          "bundled": true
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            },
+            "rc": {
+              "version": "1.1.6",
+              "bundled": true,
+              "requires": {
+                "deep-extend": "0.4.1",
+                "ini": "1.3.4",
+                "minimist": "1.2.0",
+                "strip-json-comments": "1.0.4"
+              },
+              "dependencies": {
+                "deep-extend": {
+                  "version": "0.4.1",
+                  "bundled": true
+                },
+                "ini": {
+                  "version": "1.3.4",
+                  "bundled": true
+                },
+                "minimist": {
+                  "version": "1.2.0",
+                  "bundled": true
+                },
+                "strip-json-comments": {
+                  "version": "1.0.4",
+                  "bundled": true
+                }
+              }
+            },
+            "request": {
+              "version": "2.69.0",
+              "bundled": true,
+              "requires": {
+                "aws-sign2": "0.6.0",
+                "aws4": "1.3.2",
+                "bl": "1.0.3",
+                "caseless": "0.11.0",
+                "combined-stream": "1.0.5",
+                "extend": "3.0.0",
+                "forever-agent": "0.6.1",
+                "form-data": "1.0.0-rc3",
+                "har-validator": "2.0.6",
+                "hawk": "3.1.3",
+                "http-signature": "1.1.1",
+                "is-typedarray": "1.0.0",
+                "isstream": "0.1.2",
+                "json-stringify-safe": "5.0.1",
+                "mime-types": "2.1.10",
+                "node-uuid": "1.4.7",
+                "oauth-sign": "0.8.1",
+                "qs": "6.0.2",
+                "stringstream": "0.0.5",
+                "tough-cookie": "2.2.1",
+                "tunnel-agent": "0.4.2"
+              },
+              "dependencies": {
+                "aws-sign2": {
+                  "version": "0.6.0",
+                  "bundled": true
+                },
+                "aws4": {
+                  "version": "1.3.2",
+                  "bundled": true,
+                  "requires": {
+                    "lru-cache": "4.0.0"
+                  },
+                  "dependencies": {
+                    "lru-cache": {
+                      "version": "4.0.0",
+                      "bundled": true,
+                      "requires": {
+                        "pseudomap": "1.0.2",
+                        "yallist": "2.0.0"
+                      },
+                      "dependencies": {
+                        "pseudomap": {
+                          "version": "1.0.2",
+                          "bundled": true
+                        },
+                        "yallist": {
+                          "version": "2.0.0",
+                          "bundled": true
+                        }
+                      }
+                    }
+                  }
+                },
+                "bl": {
+                  "version": "1.0.3",
+                  "bundled": true,
+                  "requires": {
+                    "readable-stream": "2.0.5"
+                  },
+                  "dependencies": {
+                    "readable-stream": {
+                      "version": "2.0.5",
+                      "bundled": true,
+                      "requires": {
+                        "core-util-is": "1.0.2",
+                        "inherits": "2.0.1",
+                        "isarray": "0.0.1",
+                        "process-nextick-args": "1.0.6",
+                        "string_decoder": "0.10.31",
+                        "util-deprecate": "1.0.2"
+                      },
+                      "dependencies": {
+                        "core-util-is": {
+                          "version": "1.0.2",
+                          "bundled": true
+                        },
+                        "inherits": {
+                          "version": "2.0.1",
+                          "bundled": true
+                        },
+                        "isarray": {
+                          "version": "0.0.1",
+                          "bundled": true
+                        },
+                        "process-nextick-args": {
+                          "version": "1.0.6",
+                          "bundled": true
+                        },
+                        "string_decoder": {
+                          "version": "0.10.31",
+                          "bundled": true
+                        },
+                        "util-deprecate": {
+                          "version": "1.0.2",
+                          "bundled": true
+                        }
+                      }
+                    }
+                  }
+                },
+                "caseless": {
+                  "version": "0.11.0",
+                  "bundled": true
+                },
+                "combined-stream": {
+                  "version": "1.0.5",
+                  "bundled": true,
+                  "requires": {
+                    "delayed-stream": "1.0.0"
+                  },
+                  "dependencies": {
+                    "delayed-stream": {
+                      "version": "1.0.0",
+                      "bundled": true
+                    }
+                  }
+                },
+                "extend": {
+                  "version": "3.0.0",
+                  "bundled": true
+                },
+                "forever-agent": {
+                  "version": "0.6.1",
+                  "bundled": true
+                },
+                "form-data": {
+                  "version": "1.0.0-rc3",
+                  "bundled": true,
+                  "requires": {
+                    "async": "1.5.2",
+                    "combined-stream": "1.0.5",
+                    "mime-types": "2.1.10"
+                  },
+                  "dependencies": {
+                    "async": {
+                      "version": "1.5.2",
+                      "bundled": true
+                    }
+                  }
+                },
+                "har-validator": {
+                  "version": "2.0.6",
+                  "bundled": true,
+                  "requires": {
+                    "chalk": "1.1.1",
+                    "commander": "2.9.0",
+                    "is-my-json-valid": "2.13.1",
+                    "pinkie-promise": "2.0.0"
+                  },
+                  "dependencies": {
+                    "chalk": {
+                      "version": "1.1.1",
+                      "bundled": true,
+                      "requires": {
+                        "ansi-styles": "2.2.0",
+                        "escape-string-regexp": "1.0.5",
+                        "has-ansi": "2.0.0",
+                        "strip-ansi": "3.0.1",
+                        "supports-color": "2.0.0"
+                      },
+                      "dependencies": {
+                        "ansi-styles": {
+                          "version": "2.2.0",
+                          "bundled": true,
+                          "requires": {
+                            "color-convert": "1.0.0"
+                          },
+                          "dependencies": {
+                            "color-convert": {
+                              "version": "1.0.0",
+                              "bundled": true
+                            }
+                          }
+                        },
+                        "escape-string-regexp": {
+                          "version": "1.0.5",
+                          "bundled": true
+                        },
+                        "has-ansi": {
+                          "version": "2.0.0",
+                          "bundled": true,
+                          "requires": {
+                            "ansi-regex": "2.0.0"
+                          },
+                          "dependencies": {
+                            "ansi-regex": {
+                              "version": "2.0.0",
+                              "bundled": true
+                            }
+                          }
+                        },
+                        "strip-ansi": {
+                          "version": "3.0.1",
+                          "bundled": true,
+                          "requires": {
+                            "ansi-regex": "2.0.0"
+                          },
+                          "dependencies": {
+                            "ansi-regex": {
+                              "version": "2.0.0",
+                              "bundled": true
+                            }
+                          }
+                        },
+                        "supports-color": {
+                          "version": "2.0.0",
+                          "bundled": true
+                        }
+                      }
+                    },
+                    "commander": {
+                      "version": "2.9.0",
+                      "bundled": true,
+                      "requires": {
+                        "graceful-readlink": "1.0.1"
+                      },
+                      "dependencies": {
+                        "graceful-readlink": {
+                          "version": "1.0.1",
+                          "bundled": true
+                        }
+                      }
+                    },
+                    "is-my-json-valid": {
+                      "version": "2.13.1",
+                      "bundled": true,
+                      "requires": {
+                        "generate-function": "2.0.0",
+                        "generate-object-property": "1.2.0",
+                        "jsonpointer": "2.0.0",
+                        "xtend": "4.0.1"
+                      },
+                      "dependencies": {
+                        "generate-function": {
+                          "version": "2.0.0",
+                          "bundled": true
+                        },
+                        "generate-object-property": {
+                          "version": "1.2.0",
+                          "bundled": true,
+                          "requires": {
+                            "is-property": "1.0.2"
+                          },
+                          "dependencies": {
+                            "is-property": {
+                              "version": "1.0.2",
+                              "bundled": true
+                            }
+                          }
+                        },
+                        "jsonpointer": {
+                          "version": "2.0.0",
+                          "bundled": true
+                        },
+                        "xtend": {
+                          "version": "4.0.1",
+                          "bundled": true
+                        }
+                      }
+                    },
+                    "pinkie-promise": {
+                      "version": "2.0.0",
+                      "bundled": true,
+                      "requires": {
+                        "pinkie": "2.0.4"
+                      },
+                      "dependencies": {
+                        "pinkie": {
+                          "version": "2.0.4",
+                          "bundled": true
+                        }
+                      }
+                    }
+                  }
+                },
+                "hawk": {
+                  "version": "3.1.3",
+                  "bundled": true,
+                  "requires": {
+                    "boom": "2.10.1",
+                    "cryptiles": "2.0.5",
+                    "hoek": "2.16.3",
+                    "sntp": "1.0.9"
+                  },
+                  "dependencies": {
+                    "boom": {
+                      "version": "2.10.1",
+                      "bundled": true,
+                      "requires": {
+                        "hoek": "2.16.3"
+                      }
+                    },
+                    "cryptiles": {
+                      "version": "2.0.5",
+                      "bundled": true,
+                      "requires": {
+                        "boom": "2.10.1"
+                      }
+                    },
+                    "hoek": {
+                      "version": "2.16.3",
+                      "bundled": true
+                    },
+                    "sntp": {
+                      "version": "1.0.9",
+                      "bundled": true,
+                      "requires": {
+                        "hoek": "2.16.3"
+                      }
+                    }
+                  }
+                },
+                "http-signature": {
+                  "version": "1.1.1",
+                  "bundled": true,
+                  "requires": {
+                    "assert-plus": "0.2.0",
+                    "jsprim": "1.2.2",
+                    "sshpk": "1.7.4"
+                  },
+                  "dependencies": {
+                    "assert-plus": {
+                      "version": "0.2.0",
+                      "bundled": true
+                    },
+                    "jsprim": {
+                      "version": "1.2.2",
+                      "bundled": true,
+                      "requires": {
+                        "extsprintf": "1.0.2",
+                        "json-schema": "0.2.2",
+                        "verror": "1.3.6"
+                      },
+                      "dependencies": {
+                        "extsprintf": {
+                          "version": "1.0.2",
+                          "bundled": true
+                        },
+                        "json-schema": {
+                          "version": "0.2.2",
+                          "bundled": true
+                        },
+                        "verror": {
+                          "version": "1.3.6",
+                          "bundled": true,
+                          "requires": {
+                            "extsprintf": "1.0.2"
+                          }
+                        }
+                      }
+                    },
+                    "sshpk": {
+                      "version": "1.7.4",
+                      "bundled": true,
+                      "requires": {
+                        "asn1": "0.2.3",
+                        "assert-plus": "0.2.0",
+                        "dashdash": "1.13.0",
+                        "ecc-jsbn": "0.1.1",
+                        "jodid25519": "1.0.2",
+                        "jsbn": "0.1.0",
+                        "tweetnacl": "0.14.1"
+                      },
+                      "dependencies": {
+                        "asn1": {
+                          "version": "0.2.3",
+                          "bundled": true
+                        },
+                        "dashdash": {
+                          "version": "1.13.0",
+                          "bundled": true,
+                          "requires": {
+                            "assert-plus": "1.0.0"
+                          },
+                          "dependencies": {
+                            "assert-plus": {
+                              "version": "1.0.0",
+                              "bundled": true
+                            }
+                          }
+                        },
+                        "ecc-jsbn": {
+                          "version": "0.1.1",
+                          "bundled": true,
+                          "optional": true,
+                          "requires": {
+                            "jsbn": "0.1.0"
+                          }
+                        },
+                        "jodid25519": {
+                          "version": "1.0.2",
+                          "bundled": true,
+                          "optional": true,
+                          "requires": {
+                            "jsbn": "0.1.0"
+                          }
+                        },
+                        "jsbn": {
+                          "version": "0.1.0",
+                          "bundled": true,
+                          "optional": true
+                        },
+                        "tweetnacl": {
+                          "version": "0.14.1",
+                          "bundled": true,
+                          "optional": true
+                        }
+                      }
+                    }
+                  }
+                },
+                "is-typedarray": {
+                  "version": "1.0.0",
+                  "bundled": true
+                },
+                "isstream": {
+                  "version": "0.1.2",
+                  "bundled": true
+                },
+                "json-stringify-safe": {
+                  "version": "5.0.1",
+                  "bundled": true
+                },
+                "mime-types": {
+                  "version": "2.1.10",
+                  "bundled": true,
+                  "requires": {
+                    "mime-db": "1.22.0"
+                  },
+                  "dependencies": {
+                    "mime-db": {
+                      "version": "1.22.0",
+                      "bundled": true
+                    }
+                  }
+                },
+                "node-uuid": {
+                  "version": "1.4.7",
+                  "bundled": true
+                },
+                "oauth-sign": {
+                  "version": "0.8.1",
+                  "bundled": true
+                },
+                "qs": {
+                  "version": "6.0.2",
+                  "bundled": true
+                },
+                "stringstream": {
+                  "version": "0.0.5",
+                  "bundled": true
+                },
+                "tough-cookie": {
+                  "version": "2.2.1",
+                  "bundled": true
+                },
+                "tunnel-agent": {
+                  "version": "0.4.2",
+                  "bundled": true
+                }
+              }
+            },
+            "rimraf": {
+              "version": "2.5.2",
+              "bundled": true,
+              "requires": {
+                "glob": "7.0.0"
+              },
+              "dependencies": {
+                "glob": {
+                  "version": "7.0.0",
+                  "bundled": true,
+                  "requires": {
+                    "inflight": "1.0.4",
+                    "inherits": "2.0.1",
+                    "minimatch": "3.0.0",
+                    "once": "1.3.3",
+                    "path-is-absolute": "1.0.0"
+                  },
+                  "dependencies": {
+                    "inflight": {
+                      "version": "1.0.4",
+                      "bundled": true,
+                      "requires": {
+                        "once": "1.3.3",
+                        "wrappy": "1.0.1"
+                      },
+                      "dependencies": {
+                        "wrappy": {
+                          "version": "1.0.1",
+                          "bundled": true
+                        }
+                      }
+                    },
+                    "inherits": {
+                      "version": "2.0.1",
+                      "bundled": true
+                    },
+                    "minimatch": {
+                      "version": "3.0.0",
+                      "bundled": true,
+                      "requires": {
+                        "brace-expansion": "1.1.3"
+                      },
+                      "dependencies": {
+                        "brace-expansion": {
+                          "version": "1.1.3",
+                          "bundled": true,
+                          "requires": {
+                            "balanced-match": "0.3.0",
+                            "concat-map": "0.0.1"
+                          },
+                          "dependencies": {
+                            "balanced-match": {
+                              "version": "0.3.0",
+                              "bundled": true
+                            },
+                            "concat-map": {
+                              "version": "0.0.1",
+                              "bundled": true
+                            }
+                          }
+                        }
+                      }
+                    },
+                    "once": {
+                      "version": "1.3.3",
+                      "bundled": true,
+                      "requires": {
+                        "wrappy": "1.0.1"
+                      },
+                      "dependencies": {
+                        "wrappy": {
+                          "version": "1.0.1",
+                          "bundled": true
+                        }
+                      }
+                    },
+                    "path-is-absolute": {
+                      "version": "1.0.0",
+                      "bundled": true
+                    }
+                  }
+                }
+              }
+            },
+            "semver": {
+              "version": "5.1.0",
+              "bundled": true
+            },
+            "tar": {
+              "version": "2.2.1",
+              "bundled": true,
+              "requires": {
+                "block-stream": "0.0.8",
+                "fstream": "1.0.8",
+                "inherits": "2.0.1"
+              },
+              "dependencies": {
+                "block-stream": {
+                  "version": "0.0.8",
+                  "bundled": true,
+                  "requires": {
+                    "inherits": "2.0.1"
+                  }
+                },
+                "fstream": {
+                  "version": "1.0.8",
+                  "bundled": true,
+                  "requires": {
+                    "graceful-fs": "4.1.3",
+                    "inherits": "2.0.1",
+                    "mkdirp": "0.5.1",
+                    "rimraf": "2.5.2"
+                  },
+                  "dependencies": {
+                    "graceful-fs": {
+                      "version": "4.1.3",
+                      "bundled": true
+                    }
+                  }
+                },
+                "inherits": {
+                  "version": "2.0.1",
+                  "bundled": true
+                }
+              }
+            },
+            "tar-pack": {
+              "version": "3.1.3",
+              "bundled": true,
+              "requires": {
+                "debug": "2.2.0",
+                "fstream": "1.0.8",
+                "fstream-ignore": "1.0.3",
+                "once": "1.3.3",
+                "readable-stream": "2.0.5",
+                "rimraf": "2.5.2",
+                "tar": "2.2.1",
+                "uid-number": "0.0.6"
+              },
+              "dependencies": {
+                "debug": {
+                  "version": "2.2.0",
+                  "bundled": true,
+                  "requires": {
+                    "ms": "0.7.1"
+                  },
+                  "dependencies": {
+                    "ms": {
+                      "version": "0.7.1",
+                      "bundled": true
+                    }
+                  }
+                },
+                "fstream": {
+                  "version": "1.0.8",
+                  "bundled": true,
+                  "requires": {
+                    "graceful-fs": "4.1.3",
+                    "inherits": "2.0.1",
+                    "mkdirp": "0.5.1",
+                    "rimraf": "2.5.2"
+                  },
+                  "dependencies": {
+                    "graceful-fs": {
+                      "version": "4.1.3",
+                      "bundled": true
+                    },
+                    "inherits": {
+                      "version": "2.0.1",
+                      "bundled": true
+                    }
+                  }
+                },
+                "fstream-ignore": {
+                  "version": "1.0.3",
+                  "bundled": true,
+                  "requires": {
+                    "fstream": "1.0.8",
+                    "inherits": "2.0.1",
+                    "minimatch": "3.0.0"
+                  },
+                  "dependencies": {
+                    "inherits": {
+                      "version": "2.0.1",
+                      "bundled": true
+                    },
+                    "minimatch": {
+                      "version": "3.0.0",
+                      "bundled": true,
+                      "requires": {
+                        "brace-expansion": "1.1.3"
+                      },
+                      "dependencies": {
+                        "brace-expansion": {
+                          "version": "1.1.3",
+                          "bundled": true,
+                          "requires": {
+                            "balanced-match": "0.3.0",
+                            "concat-map": "0.0.1"
+                          },
+                          "dependencies": {
+                            "balanced-match": {
+                              "version": "0.3.0",
+                              "bundled": true
+                            },
+                            "concat-map": {
+                              "version": "0.0.1",
+                              "bundled": true
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                },
+                "once": {
+                  "version": "1.3.3",
+                  "bundled": true,
+                  "requires": {
+                    "wrappy": "1.0.1"
+                  },
+                  "dependencies": {
+                    "wrappy": {
+                      "version": "1.0.1",
+                      "bundled": true
+                    }
+                  }
+                },
+                "readable-stream": {
+                  "version": "2.0.5",
+                  "bundled": true,
+                  "requires": {
+                    "core-util-is": "1.0.2",
+                    "inherits": "2.0.1",
+                    "isarray": "0.0.1",
+                    "process-nextick-args": "1.0.6",
+                    "string_decoder": "0.10.31",
+                    "util-deprecate": "1.0.2"
+                  },
+                  "dependencies": {
+                    "core-util-is": {
+                      "version": "1.0.2",
+                      "bundled": true
+                    },
+                    "inherits": {
+                      "version": "2.0.1",
+                      "bundled": true
+                    },
+                    "isarray": {
+                      "version": "0.0.1",
+                      "bundled": true
+                    },
+                    "process-nextick-args": {
+                      "version": "1.0.6",
+                      "bundled": true
+                    },
+                    "string_decoder": {
+                      "version": "0.10.31",
+                      "bundled": true
+                    },
+                    "util-deprecate": {
+                      "version": "1.0.2",
+                      "bundled": true
+                    }
+                  }
+                },
+                "uid-number": {
+                  "version": "0.0.6",
+                  "bundled": true
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    "seedrandom": {
+      "version": "2.4.3",
+      "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-2.4.3.tgz",
+      "integrity": "sha1-JDhQTa0zkXMUv/GKxNeU8W1qrsw="
+    },
+    "semver": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
+      "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA=="
+    },
+    "send": {
+      "version": "0.15.1",
+      "resolved": "https://registry.npmjs.org/send/-/send-0.15.1.tgz",
+      "integrity": "sha1-igI1TCbm9cynAAZfXwzeupDse18=",
+      "requires": {
+        "debug": "2.6.1",
+        "depd": "1.1.2",
+        "destroy": "1.0.4",
+        "encodeurl": "1.0.2",
+        "escape-html": "1.0.3",
+        "etag": "1.8.1",
+        "fresh": "0.5.0",
+        "http-errors": "1.6.3",
+        "mime": "1.3.4",
+        "ms": "0.7.2",
+        "on-finished": "2.3.0",
+        "range-parser": "1.2.0",
+        "statuses": "1.3.1"
+      },
+      "dependencies": {
+        "mime": {
+          "version": "1.3.4",
+          "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz",
+          "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM="
+        },
+        "statuses": {
+          "version": "1.3.1",
+          "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz",
+          "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4="
+        }
+      }
+    },
+    "serve-static": {
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.12.1.tgz",
+      "integrity": "sha1-dEOpZePO1kes61Y5+ga/TRu+ADk=",
+      "requires": {
+        "encodeurl": "1.0.2",
+        "escape-html": "1.0.3",
+        "parseurl": "1.3.2",
+        "send": "0.15.1"
+      }
+    },
+    "set-blocking": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+      "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
+    },
+    "setimmediate": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+      "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
+    },
+    "setprototypeof": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
+      "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
+    },
+    "sha1": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz",
+      "integrity": "sha1-rdqnqTFo85PxnrKxUJFhjicA+Eg=",
+      "requires": {
+        "charenc": "0.0.2",
+        "crypt": "0.0.2"
+      }
+    },
+    "shelljs": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.2.tgz",
+      "integrity": "sha512-pRXeNrCA2Wd9itwhvLp5LZQvPJ0wU6bcjaTMywHHGX5XWhVN2nzSu7WV0q+oUY7mGK3mgSkDDzP3MgjqdyIgbQ==",
+      "requires": {
+        "glob": "7.1.2",
+        "interpret": "1.1.0",
+        "rechoir": "0.6.2"
+      }
+    },
+    "should": {
+      "version": "13.2.1",
+      "resolved": "https://registry.npmjs.org/should/-/should-13.2.1.tgz",
+      "integrity": "sha512-l+/NwEMO+DcstsHEwPHRHzC9j4UOE3VQwJGcMWSsD/vqpqHbnQ+1iSHy64Ihmmjx1uiRPD9pFadTSc3MJtXAgw==",
+      "dev": true,
+      "requires": {
+        "should-equal": "2.0.0",
+        "should-format": "3.0.3",
+        "should-type": "1.4.0",
+        "should-type-adaptors": "1.1.0",
+        "should-util": "1.0.0"
+      }
+    },
+    "should-equal": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz",
+      "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==",
+      "dev": true,
+      "requires": {
+        "should-type": "1.4.0"
+      }
+    },
+    "should-format": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz",
+      "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=",
+      "dev": true,
+      "requires": {
+        "should-type": "1.4.0",
+        "should-type-adaptors": "1.1.0"
+      }
+    },
+    "should-type": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz",
+      "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=",
+      "dev": true
+    },
+    "should-type-adaptors": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz",
+      "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==",
+      "dev": true,
+      "requires": {
+        "should-type": "1.4.0",
+        "should-util": "1.0.0"
+      }
+    },
+    "should-util": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.0.tgz",
+      "integrity": "sha1-yYzaN0qmsZDfi6h8mInCtNtiAGM=",
+      "dev": true
+    },
+    "signal-exit": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+      "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
+    },
+    "slice-ansi": {
+      "version": "0.0.4",
+      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz",
+      "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=",
+      "dev": true
+    },
+    "slice-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/slice-stream/-/slice-stream-1.0.0.tgz",
+      "integrity": "sha1-WzO9ZvATsaf4ZGCwPUY97DmtPqA=",
+      "requires": {
+        "readable-stream": "1.0.34"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "0.0.1",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+          "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+        },
+        "readable-stream": {
+          "version": "1.0.34",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
+          "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
+          "requires": {
+            "core-util-is": "1.0.2",
+            "inherits": "2.0.3",
+            "isarray": "0.0.1",
+            "string_decoder": "0.10.31"
+          }
+        },
+        "string_decoder": {
+          "version": "0.10.31",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+          "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+        }
+      }
+    },
+    "smart-buffer": {
+      "version": "1.1.15",
+      "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-1.1.15.tgz",
+      "integrity": "sha1-fxFLW2X6s+KjWqd1uxLw0cZJvxY="
+    },
+    "sntp": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz",
+      "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=",
+      "requires": {
+        "hoek": "2.16.3"
+      }
+    },
+    "socks": {
+      "version": "1.1.10",
+      "resolved": "https://registry.npmjs.org/socks/-/socks-1.1.10.tgz",
+      "integrity": "sha1-W4t/x8jzQcU+0FbpKbe/Tei6e1o=",
+      "requires": {
+        "ip": "1.1.5",
+        "smart-buffer": "1.1.15"
+      }
+    },
+    "socks-proxy-agent": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-3.0.1.tgz",
+      "integrity": "sha512-ZwEDymm204mTzvdqyUqOdovVr2YRd2NYskrYrF2LXyZ9qDiMAoFESGK8CRphiO7rtbo2Y757k2Nia3x2hGtalA==",
+      "requires": {
+        "agent-base": "4.2.0",
+        "socks": "1.1.10"
+      }
+    },
+    "source-map": {
+      "version": "0.1.43",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz",
+      "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=",
+      "optional": true,
+      "requires": {
+        "amdefine": "1.0.1"
+      }
+    },
+    "source-map-support": {
+      "version": "0.4.18",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
+      "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==",
+      "dev": true,
+      "requires": {
+        "source-map": "0.5.7"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        }
+      }
+    },
+    "split": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz",
+      "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=",
+      "requires": {
+        "through": "2.3.8"
+      }
+    },
+    "sprintf-js": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
+    },
+    "sqlite3": {
+      "version": "3.1.13",
+      "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-3.1.13.tgz",
+      "integrity": "sha512-JxXKPJnkZ6NuHRojq+g2WXWBt3M1G9sjZaYiHEWSTGijDM3cwju/0T2XbWqMXFmPqDgw+iB7zKQvnns4bvzXlw==",
+      "requires": {
+        "nan": "2.7.0",
+        "node-pre-gyp": "0.6.38"
+      },
+      "dependencies": {
+        "abbrev": {
+          "version": "1.1.1",
+          "bundled": true
+        },
+        "ajv": {
+          "version": "4.11.8",
+          "bundled": true,
+          "requires": {
+            "co": "4.6.0",
+            "json-stable-stringify": "1.0.1"
+          }
+        },
+        "ansi-regex": {
+          "version": "2.1.1",
+          "bundled": true
+        },
+        "aproba": {
+          "version": "1.2.0",
+          "bundled": true
+        },
+        "are-we-there-yet": {
+          "version": "1.1.4",
+          "bundled": true,
+          "requires": {
+            "delegates": "1.0.0",
+            "readable-stream": "2.3.3"
+          }
+        },
+        "asn1": {
+          "version": "0.2.3",
+          "bundled": true
+        },
+        "assert-plus": {
+          "version": "0.2.0",
+          "bundled": true
+        },
+        "asynckit": {
+          "version": "0.4.0",
+          "bundled": true
+        },
+        "aws-sign2": {
+          "version": "0.6.0",
+          "bundled": true
+        },
+        "aws4": {
+          "version": "1.6.0",
+          "bundled": true
+        },
+        "balanced-match": {
+          "version": "1.0.0",
+          "bundled": true
+        },
+        "bcrypt-pbkdf": {
+          "version": "1.0.1",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "tweetnacl": "0.14.5"
+          }
+        },
+        "block-stream": {
+          "version": "0.0.9",
+          "bundled": true,
+          "requires": {
+            "inherits": "2.0.3"
+          }
+        },
+        "boom": {
+          "version": "2.10.1",
+          "bundled": true,
+          "requires": {
+            "hoek": "2.16.3"
+          }
+        },
+        "brace-expansion": {
+          "version": "1.1.8",
+          "bundled": true,
+          "requires": {
+            "balanced-match": "1.0.0",
+            "concat-map": "0.0.1"
+          }
+        },
+        "caseless": {
+          "version": "0.12.0",
+          "bundled": true
+        },
+        "co": {
+          "version": "4.6.0",
+          "bundled": true
+        },
+        "code-point-at": {
+          "version": "1.1.0",
+          "bundled": true
+        },
+        "combined-stream": {
+          "version": "1.0.5",
+          "bundled": true,
+          "requires": {
+            "delayed-stream": "1.0.0"
+          }
+        },
+        "concat-map": {
+          "version": "0.0.1",
+          "bundled": true
+        },
+        "console-control-strings": {
+          "version": "1.1.0",
+          "bundled": true
+        },
+        "core-util-is": {
+          "version": "1.0.2",
+          "bundled": true
+        },
+        "cryptiles": {
+          "version": "2.0.5",
+          "bundled": true,
+          "requires": {
+            "boom": "2.10.1"
+          }
+        },
+        "dashdash": {
+          "version": "1.14.1",
+          "bundled": true,
+          "requires": {
+            "assert-plus": "1.0.0"
+          },
+          "dependencies": {
+            "assert-plus": {
+              "version": "1.0.0",
+              "bundled": true
+            }
+          }
+        },
+        "debug": {
+          "version": "2.6.9",
+          "bundled": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "deep-extend": {
+          "version": "0.4.2",
+          "bundled": true
+        },
+        "delayed-stream": {
+          "version": "1.0.0",
+          "bundled": true
+        },
+        "delegates": {
+          "version": "1.0.0",
+          "bundled": true
+        },
+        "ecc-jsbn": {
+          "version": "0.1.1",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "jsbn": "0.1.1"
+          }
+        },
+        "extend": {
+          "version": "3.0.1",
+          "bundled": true
+        },
+        "extsprintf": {
+          "version": "1.3.0",
+          "bundled": true
+        },
+        "forever-agent": {
+          "version": "0.6.1",
+          "bundled": true
+        },
+        "form-data": {
+          "version": "2.1.4",
+          "bundled": true,
+          "requires": {
+            "asynckit": "0.4.0",
+            "combined-stream": "1.0.5",
+            "mime-types": "2.1.17"
+          }
+        },
+        "fs.realpath": {
+          "version": "1.0.0",
+          "bundled": true
+        },
+        "fstream": {
+          "version": "1.0.11",
+          "bundled": true,
+          "requires": {
+            "graceful-fs": "4.1.11",
+            "inherits": "2.0.3",
+            "mkdirp": "0.5.1",
+            "rimraf": "2.6.2"
+          }
+        },
+        "fstream-ignore": {
+          "version": "1.0.5",
+          "bundled": true,
+          "requires": {
+            "fstream": "1.0.11",
+            "inherits": "2.0.3",
+            "minimatch": "3.0.4"
+          }
+        },
+        "gauge": {
+          "version": "2.7.4",
+          "bundled": true,
+          "requires": {
+            "aproba": "1.2.0",
+            "console-control-strings": "1.1.0",
+            "has-unicode": "2.0.1",
+            "object-assign": "4.1.1",
+            "signal-exit": "3.0.2",
+            "string-width": "1.0.2",
+            "strip-ansi": "3.0.1",
+            "wide-align": "1.1.2"
+          }
+        },
+        "getpass": {
+          "version": "0.1.7",
+          "bundled": true,
+          "requires": {
+            "assert-plus": "1.0.0"
+          },
+          "dependencies": {
+            "assert-plus": {
+              "version": "1.0.0",
+              "bundled": true
+            }
+          }
+        },
+        "glob": {
+          "version": "7.1.2",
+          "bundled": true,
+          "requires": {
+            "fs.realpath": "1.0.0",
+            "inflight": "1.0.6",
+            "inherits": "2.0.3",
+            "minimatch": "3.0.4",
+            "once": "1.4.0",
+            "path-is-absolute": "1.0.1"
+          }
+        },
+        "graceful-fs": {
+          "version": "4.1.11",
+          "bundled": true
+        },
+        "har-schema": {
+          "version": "1.0.5",
+          "bundled": true
+        },
+        "har-validator": {
+          "version": "4.2.1",
+          "bundled": true,
+          "requires": {
+            "ajv": "4.11.8",
+            "har-schema": "1.0.5"
+          }
+        },
+        "has-unicode": {
+          "version": "2.0.1",
+          "bundled": true
+        },
+        "hawk": {
+          "version": "3.1.3",
+          "bundled": true,
+          "requires": {
+            "boom": "2.10.1",
+            "cryptiles": "2.0.5",
+            "hoek": "2.16.3",
+            "sntp": "1.0.9"
+          }
+        },
+        "hoek": {
+          "version": "2.16.3",
+          "bundled": true
+        },
+        "http-signature": {
+          "version": "1.1.1",
+          "bundled": true,
+          "requires": {
+            "assert-plus": "0.2.0",
+            "jsprim": "1.4.1",
+            "sshpk": "1.13.1"
+          }
+        },
+        "inflight": {
+          "version": "1.0.6",
+          "bundled": true,
+          "requires": {
+            "once": "1.4.0",
+            "wrappy": "1.0.2"
+          }
+        },
+        "inherits": {
+          "version": "2.0.3",
+          "bundled": true
+        },
+        "ini": {
+          "version": "1.3.4",
+          "bundled": true
+        },
+        "is-fullwidth-code-point": {
+          "version": "1.0.0",
+          "bundled": true,
+          "requires": {
+            "number-is-nan": "1.0.1"
+          }
+        },
+        "is-typedarray": {
+          "version": "1.0.0",
+          "bundled": true
+        },
+        "isarray": {
+          "version": "1.0.0",
+          "bundled": true
+        },
+        "isstream": {
+          "version": "0.1.2",
+          "bundled": true
+        },
+        "jsbn": {
+          "version": "0.1.1",
+          "bundled": true,
+          "optional": true
+        },
+        "json-schema": {
+          "version": "0.2.3",
+          "bundled": true
+        },
+        "json-stable-stringify": {
+          "version": "1.0.1",
+          "bundled": true,
+          "requires": {
+            "jsonify": "0.0.0"
+          }
+        },
+        "json-stringify-safe": {
+          "version": "5.0.1",
+          "bundled": true
+        },
+        "jsonify": {
+          "version": "0.0.0",
+          "bundled": true
+        },
+        "jsprim": {
+          "version": "1.4.1",
+          "bundled": true,
+          "requires": {
+            "assert-plus": "1.0.0",
+            "extsprintf": "1.3.0",
+            "json-schema": "0.2.3",
+            "verror": "1.10.0"
+          },
+          "dependencies": {
+            "assert-plus": {
+              "version": "1.0.0",
+              "bundled": true
+            }
+          }
+        },
+        "mime-db": {
+          "version": "1.30.0",
+          "bundled": true
+        },
+        "mime-types": {
+          "version": "2.1.17",
+          "bundled": true,
+          "requires": {
+            "mime-db": "1.30.0"
+          }
+        },
+        "minimatch": {
+          "version": "3.0.4",
+          "bundled": true,
+          "requires": {
+            "brace-expansion": "1.1.8"
+          }
+        },
+        "minimist": {
+          "version": "0.0.8",
+          "bundled": true
+        },
+        "mkdirp": {
+          "version": "0.5.1",
+          "bundled": true,
+          "requires": {
+            "minimist": "0.0.8"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "bundled": true
+        },
+        "nan": {
+          "version": "2.7.0",
+          "resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz",
+          "integrity": "sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY="
+        },
+        "node-pre-gyp": {
+          "version": "0.6.38",
+          "bundled": true,
+          "requires": {
+            "hawk": "3.1.3",
+            "mkdirp": "0.5.1",
+            "nopt": "4.0.1",
+            "npmlog": "4.1.2",
+            "rc": "1.2.1",
+            "request": "2.81.0",
+            "rimraf": "2.6.2",
+            "semver": "5.4.1",
+            "tar": "2.2.1",
+            "tar-pack": "3.4.0"
+          }
+        },
+        "nopt": {
+          "version": "4.0.1",
+          "bundled": true,
+          "requires": {
+            "abbrev": "1.1.1",
+            "osenv": "0.1.4"
+          }
+        },
+        "npmlog": {
+          "version": "4.1.2",
+          "bundled": true,
+          "requires": {
+            "are-we-there-yet": "1.1.4",
+            "console-control-strings": "1.1.0",
+            "gauge": "2.7.4",
+            "set-blocking": "2.0.0"
+          }
+        },
+        "number-is-nan": {
+          "version": "1.0.1",
+          "bundled": true
+        },
+        "oauth-sign": {
+          "version": "0.8.2",
+          "bundled": true
+        },
+        "object-assign": {
+          "version": "4.1.1",
+          "bundled": true
+        },
+        "once": {
+          "version": "1.4.0",
+          "bundled": true,
+          "requires": {
+            "wrappy": "1.0.2"
+          }
+        },
+        "os-homedir": {
+          "version": "1.0.2",
+          "bundled": true
+        },
+        "os-tmpdir": {
+          "version": "1.0.2",
+          "bundled": true
+        },
+        "osenv": {
+          "version": "0.1.4",
+          "bundled": true,
+          "requires": {
+            "os-homedir": "1.0.2",
+            "os-tmpdir": "1.0.2"
+          }
+        },
+        "path-is-absolute": {
+          "version": "1.0.1",
+          "bundled": true
+        },
+        "performance-now": {
+          "version": "0.2.0",
+          "bundled": true
+        },
+        "process-nextick-args": {
+          "version": "1.0.7",
+          "bundled": true
+        },
+        "punycode": {
+          "version": "1.4.1",
+          "bundled": true
+        },
+        "qs": {
+          "version": "6.4.0",
+          "bundled": true
+        },
+        "rc": {
+          "version": "1.2.1",
+          "bundled": true,
+          "requires": {
+            "deep-extend": "0.4.2",
+            "ini": "1.3.4",
+            "minimist": "1.2.0",
+            "strip-json-comments": "2.0.1"
+          },
+          "dependencies": {
+            "minimist": {
+              "version": "1.2.0",
+              "bundled": true
+            }
+          }
+        },
+        "readable-stream": {
+          "version": "2.3.3",
+          "bundled": true,
+          "requires": {
+            "core-util-is": "1.0.2",
+            "inherits": "2.0.3",
+            "isarray": "1.0.0",
+            "process-nextick-args": "1.0.7",
+            "safe-buffer": "5.1.1",
+            "string_decoder": "1.0.3",
+            "util-deprecate": "1.0.2"
+          }
+        },
+        "request": {
+          "version": "2.81.0",
+          "bundled": true,
+          "requires": {
+            "aws-sign2": "0.6.0",
+            "aws4": "1.6.0",
+            "caseless": "0.12.0",
+            "combined-stream": "1.0.5",
+            "extend": "3.0.1",
+            "forever-agent": "0.6.1",
+            "form-data": "2.1.4",
+            "har-validator": "4.2.1",
+            "hawk": "3.1.3",
+            "http-signature": "1.1.1",
+            "is-typedarray": "1.0.0",
+            "isstream": "0.1.2",
+            "json-stringify-safe": "5.0.1",
+            "mime-types": "2.1.17",
+            "oauth-sign": "0.8.2",
+            "performance-now": "0.2.0",
+            "qs": "6.4.0",
+            "safe-buffer": "5.1.1",
+            "stringstream": "0.0.5",
+            "tough-cookie": "2.3.3",
+            "tunnel-agent": "0.6.0",
+            "uuid": "3.1.0"
+          }
+        },
+        "rimraf": {
+          "version": "2.6.2",
+          "bundled": true,
+          "requires": {
+            "glob": "7.1.2"
+          }
+        },
+        "safe-buffer": {
+          "version": "5.1.1",
+          "bundled": true
+        },
+        "semver": {
+          "version": "5.4.1",
+          "bundled": true
+        },
+        "set-blocking": {
+          "version": "2.0.0",
+          "bundled": true
+        },
+        "signal-exit": {
+          "version": "3.0.2",
+          "bundled": true
+        },
+        "sntp": {
+          "version": "1.0.9",
+          "bundled": true,
+          "requires": {
+            "hoek": "2.16.3"
+          }
+        },
+        "sshpk": {
+          "version": "1.13.1",
+          "bundled": true,
+          "requires": {
+            "asn1": "0.2.3",
+            "assert-plus": "1.0.0",
+            "bcrypt-pbkdf": "1.0.1",
+            "dashdash": "1.14.1",
+            "ecc-jsbn": "0.1.1",
+            "getpass": "0.1.7",
+            "jsbn": "0.1.1",
+            "tweetnacl": "0.14.5"
+          },
+          "dependencies": {
+            "assert-plus": {
+              "version": "1.0.0",
+              "bundled": true
+            }
+          }
+        },
+        "string-width": {
+          "version": "1.0.2",
+          "bundled": true,
+          "requires": {
+            "code-point-at": "1.1.0",
+            "is-fullwidth-code-point": "1.0.0",
+            "strip-ansi": "3.0.1"
+          }
+        },
+        "string_decoder": {
+          "version": "1.0.3",
+          "bundled": true,
+          "requires": {
+            "safe-buffer": "5.1.1"
+          }
+        },
+        "stringstream": {
+          "version": "0.0.5",
+          "bundled": true
+        },
+        "strip-ansi": {
+          "version": "3.0.1",
+          "bundled": true,
+          "requires": {
+            "ansi-regex": "2.1.1"
+          }
+        },
+        "strip-json-comments": {
+          "version": "2.0.1",
+          "bundled": true
+        },
+        "tar": {
+          "version": "2.2.1",
+          "bundled": true,
+          "requires": {
+            "block-stream": "0.0.9",
+            "fstream": "1.0.11",
+            "inherits": "2.0.3"
+          }
+        },
+        "tar-pack": {
+          "version": "3.4.0",
+          "bundled": true,
+          "requires": {
+            "debug": "2.6.9",
+            "fstream": "1.0.11",
+            "fstream-ignore": "1.0.5",
+            "once": "1.4.0",
+            "readable-stream": "2.3.3",
+            "rimraf": "2.6.2",
+            "tar": "2.2.1",
+            "uid-number": "0.0.6"
+          }
+        },
+        "tough-cookie": {
+          "version": "2.3.3",
+          "bundled": true,
+          "requires": {
+            "punycode": "1.4.1"
+          }
+        },
+        "tunnel-agent": {
+          "version": "0.6.0",
+          "bundled": true,
+          "requires": {
+            "safe-buffer": "5.1.1"
+          }
+        },
+        "tweetnacl": {
+          "version": "0.14.5",
+          "bundled": true,
+          "optional": true
+        },
+        "uid-number": {
+          "version": "0.0.6",
+          "bundled": true
+        },
+        "util-deprecate": {
+          "version": "1.0.2",
+          "bundled": true
+        },
+        "uuid": {
+          "version": "3.1.0",
+          "bundled": true
+        },
+        "verror": {
+          "version": "1.10.0",
+          "bundled": true,
+          "requires": {
+            "assert-plus": "1.0.0",
+            "core-util-is": "1.0.2",
+            "extsprintf": "1.3.0"
+          },
+          "dependencies": {
+            "assert-plus": {
+              "version": "1.0.0",
+              "bundled": true
+            }
+          }
+        },
+        "wide-align": {
+          "version": "1.1.2",
+          "bundled": true,
+          "requires": {
+            "string-width": "1.0.2"
+          }
+        },
+        "wrappy": {
+          "version": "1.0.2",
+          "bundled": true
+        }
+      }
+    },
+    "sshpk": {
+      "version": "1.14.2",
+      "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz",
+      "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=",
+      "requires": {
+        "asn1": "0.2.3",
+        "assert-plus": "1.0.0",
+        "bcrypt-pbkdf": "1.0.2",
+        "dashdash": "1.14.1",
+        "ecc-jsbn": "0.1.1",
+        "getpass": "0.1.7",
+        "jsbn": "0.1.1",
+        "safer-buffer": "2.1.2",
+        "tweetnacl": "0.14.3"
+      },
+      "dependencies": {
+        "assert-plus": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+          "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+        }
+      }
+    },
+    "stack-trace": {
+      "version": "0.0.10",
+      "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
+      "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA="
+    },
+    "statuses": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+      "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
+    },
+    "stealthy-require": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
+      "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
+    },
+    "stream-combiner": {
+      "version": "0.0.4",
+      "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz",
+      "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=",
+      "requires": {
+        "duplexer": "0.1.1"
+      }
+    },
+    "streamifier": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/streamifier/-/streamifier-0.1.1.tgz",
+      "integrity": "sha1-l+mNj6TRBdYqJpHR3AfoINuN/E8="
+    },
+    "streamsearch": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
+      "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
+    },
+    "string-width": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+      "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+      "requires": {
+        "is-fullwidth-code-point": "2.0.0",
+        "strip-ansi": "4.0.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
+        },
+        "strip-ansi": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+          "requires": {
+            "ansi-regex": "3.0.0"
+          }
+        }
+      }
+    },
+    "string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "requires": {
+        "safe-buffer": "5.1.2"
+      }
+    },
+    "stringstream": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz",
+      "integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA=="
+    },
+    "strip-ansi": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+      "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+      "requires": {
+        "ansi-regex": "2.1.1"
+      }
+    },
+    "strip-bom": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+      "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
+      "dev": true
+    },
+    "strip-json-comments": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+      "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
+    },
+    "superagent": {
+      "version": "3.8.2",
+      "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.2.tgz",
+      "integrity": "sha512-gVH4QfYHcY3P0f/BZzavLreHW3T1v7hG9B+hpMQotGQqurOvhv87GcMCd6LWySmBuf+BDR44TQd0aISjVHLeNQ==",
+      "requires": {
+        "component-emitter": "1.2.1",
+        "cookiejar": "2.1.2",
+        "debug": "3.1.0",
+        "extend": "3.0.1",
+        "form-data": "2.3.2",
+        "formidable": "1.2.1",
+        "methods": "1.1.2",
+        "mime": "1.6.0",
+        "qs": "6.5.2",
+        "readable-stream": "2.3.6"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+          "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "form-data": {
+          "version": "2.3.2",
+          "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz",
+          "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
+          "requires": {
+            "asynckit": "0.4.0",
+            "combined-stream": "1.0.6",
+            "mime-types": "2.1.18"
+          }
+        },
+        "mime": {
+          "version": "1.6.0",
+          "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+          "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+        },
+        "qs": {
+          "version": "6.5.2",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+          "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
+        }
+      }
+    },
+    "supertest": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/supertest/-/supertest-3.1.0.tgz",
+      "integrity": "sha512-O44AMnmJqx294uJQjfUmEyYOg7d9mylNFsMw/Wkz4evKd1njyPrtCN+U6ZIC7sKtfEVQhfTqFFijlXx8KP/Czw==",
+      "requires": {
+        "methods": "1.1.2",
+        "superagent": "3.8.2"
+      }
+    },
+    "supports-color": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+      "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
+    },
+    "table": {
+      "version": "3.8.3",
+      "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz",
+      "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=",
+      "dev": true,
+      "requires": {
+        "ajv": "4.11.8",
+        "ajv-keywords": "1.5.1",
+        "chalk": "1.1.3",
+        "lodash": "4.17.10",
+        "slice-ansi": "0.0.4",
+        "string-width": "2.1.1"
+      }
+    },
+    "tail": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/tail/-/tail-1.2.4.tgz",
+      "integrity": "sha512-IAAm998XX0A1yuQgYzfyfWyDYb1tFI6Q548g71xLwqRn4MvnB+fstbmBoexxRI3i+n04rtetDBqmE0jrYSTvkA=="
+    },
+    "tar": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz",
+      "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=",
+      "requires": {
+        "block-stream": "0.0.9",
+        "fstream": "1.0.11",
+        "inherits": "2.0.3"
+      }
+    },
+    "tar-pack": {
+      "version": "3.4.1",
+      "resolved": "https://registry.npmjs.org/tar-pack/-/tar-pack-3.4.1.tgz",
+      "integrity": "sha512-PPRybI9+jM5tjtCbN2cxmmRU7YmqT3Zv/UDy48tAh2XRkLa9bAORtSWLkVc13+GJF+cdTh1yEnHEk3cpTaL5Kg==",
+      "requires": {
+        "debug": "2.6.1",
+        "fstream": "1.0.11",
+        "fstream-ignore": "1.0.5",
+        "once": "1.4.0",
+        "readable-stream": "2.3.6",
+        "rimraf": "2.6.2",
+        "tar": "2.2.1",
+        "uid-number": "0.0.6"
+      }
+    },
+    "tar-stream": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.1.tgz",
+      "integrity": "sha512-IFLM5wp3QrJODQFPm6/to3LJZrONdBY/otxcvDIQzu217zKye6yVR3hhi9lAjrC2Z+m/j5oDxMPb1qcd8cIvpA==",
+      "requires": {
+        "bl": "1.2.2",
+        "buffer-alloc": "1.2.0",
+        "end-of-stream": "1.4.1",
+        "fs-constants": "1.0.0",
+        "readable-stream": "2.3.6",
+        "to-buffer": "1.1.1",
+        "xtend": "4.0.1"
+      }
+    },
+    "text-table": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+      "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+      "dev": true
+    },
+    "through": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+      "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
+    },
+    "tmp": {
+      "version": "0.0.29",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz",
+      "integrity": "sha1-8lEl/w3Z2jzLDC3Tce4SiLuRKMA=",
+      "dev": true,
+      "requires": {
+        "os-tmpdir": "1.0.2"
+      }
+    },
+    "to-buffer": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz",
+      "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg=="
+    },
+    "tough-cookie": {
+      "version": "2.3.4",
+      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz",
+      "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==",
+      "requires": {
+        "punycode": "1.4.1"
+      }
+    },
+    "traverse": {
+      "version": "0.6.6",
+      "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz",
+      "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc="
+    },
+    "ts-node": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-3.3.0.tgz",
+      "integrity": "sha1-wTxqMCTjC+EYDdUwOPwgkonUv2k=",
+      "dev": true,
+      "requires": {
+        "arrify": "1.0.1",
+        "chalk": "2.4.1",
+        "diff": "3.2.0",
+        "make-error": "1.3.4",
+        "minimist": "1.2.0",
+        "mkdirp": "0.5.1",
+        "source-map-support": "0.4.18",
+        "tsconfig": "6.0.0",
+        "v8flags": "3.1.1",
+        "yn": "2.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+          "dev": true,
+          "requires": {
+            "color-convert": "1.9.2"
+          }
+        },
+        "chalk": {
+          "version": "2.4.1",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
+          "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "3.2.1",
+            "escape-string-regexp": "1.0.5",
+            "supports-color": "5.4.0"
+          }
+        },
+        "has-flag": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "dev": true
+        },
+        "minimist": {
+          "version": "1.2.0",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "5.4.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
+          "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
+          "dev": true,
+          "requires": {
+            "has-flag": "3.0.0"
+          }
+        }
+      }
+    },
+    "tsconfig": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-6.0.0.tgz",
+      "integrity": "sha1-aw6DdgA9evGGT434+J3QBZ/80DI=",
+      "dev": true,
+      "requires": {
+        "strip-bom": "3.0.0",
+        "strip-json-comments": "2.0.1"
+      }
+    },
+    "tunnel-agent": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+      "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+      "requires": {
+        "safe-buffer": "5.1.2"
+      }
+    },
+    "tweetnacl": {
+      "version": "0.14.3",
+      "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.3.tgz",
+      "integrity": "sha1-PaOC9nDyXe1417PReSEZvKC3Ey0="
+    },
+    "type-check": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+      "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+      "dev": true,
+      "requires": {
+        "prelude-ls": "1.1.2"
+      }
+    },
+    "type-is": {
+      "version": "1.6.16",
+      "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz",
+      "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==",
+      "requires": {
+        "media-typer": "0.3.0",
+        "mime-types": "2.1.18"
+      }
+    },
+    "typedarray": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+      "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
+      "dev": true
+    },
+    "typedoc": {
+      "version": "0.11.1",
+      "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.11.1.tgz",
+      "integrity": "sha512-jdNIoHm5wkZqxQTe/g9AQ3LKnZyrzHXqu6A/c9GUOeJyBWLxNr7/Dm3rwFvLksuxRNwTvY/0HRDU9sJTa9WQSg==",
+      "requires": {
+        "@types/fs-extra": "5.0.1",
+        "@types/handlebars": "4.0.36",
+        "@types/highlight.js": "9.12.2",
+        "@types/lodash": "4.14.104",
+        "@types/marked": "0.3.0",
+        "@types/minimatch": "3.0.3",
+        "@types/shelljs": "0.7.8",
+        "fs-extra": "5.0.0",
+        "handlebars": "4.0.11",
+        "highlight.js": "9.12.0",
+        "lodash": "4.17.10",
+        "marked": "0.3.19",
+        "minimatch": "3.0.4",
+        "progress": "2.0.0",
+        "shelljs": "0.8.2",
+        "typedoc-default-themes": "0.5.0",
+        "typescript": "2.7.2"
+      },
+      "dependencies": {
+        "fs-extra": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz",
+          "integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==",
+          "requires": {
+            "graceful-fs": "4.1.11",
+            "jsonfile": "4.0.0",
+            "universalify": "0.1.2"
+          }
+        },
+        "jsonfile": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+          "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
+          "requires": {
+            "graceful-fs": "4.1.11"
+          }
+        },
+        "typescript": {
+          "version": "2.7.2",
+          "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.7.2.tgz",
+          "integrity": "sha512-p5TCYZDAO0m4G344hD+wx/LATebLWZNkkh2asWUFqSsD2OrDNhbAHuSjobrmsUmdzjJjEeZVU9g1h3O6vpstnw=="
+        }
+      }
+    },
+    "typedoc-default-themes": {
+      "version": "0.5.0",
+      "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.5.0.tgz",
+      "integrity": "sha1-bcJDPnjti+qOiHo6zeLzF4W9Yic="
+    },
+    "typedoc-plugin-sourcefile-url": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/typedoc-plugin-sourcefile-url/-/typedoc-plugin-sourcefile-url-1.0.3.tgz",
+      "integrity": "sha1-+7zEtxvZLS95TRwWmkgAQilrH+Y=",
+      "dev": true
+    },
+    "typescript": {
+      "version": "2.8.4",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.8.4.tgz",
+      "integrity": "sha512-IIU5cN1mR5J3z9jjdESJbnxikTrEz3lzAw/D0Tf45jHpBp55nY31UkUvmVHoffCfKHTqJs3fCLPDxknQTTFegQ==",
+      "dev": true
+    },
+    "uglify-js": {
+      "version": "2.8.29",
+      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
+      "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=",
+      "optional": true,
+      "requires": {
+        "source-map": "0.5.7",
+        "uglify-to-browserify": "1.0.2",
+        "yargs": "3.10.0"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "optional": true
+        }
+      }
+    },
+    "uglify-to-browserify": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
+      "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=",
+      "optional": true
+    },
+    "uid-number": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz",
+      "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE="
+    },
+    "ultron": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz",
+      "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po="
+    },
+    "underscore": {
+      "version": "1.8.3",
+      "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
+      "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI="
+    },
+    "underscore.string": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz",
+      "integrity": "sha1-jN2PusTi0uoefi6Al8QvRCKA+Fs=",
+      "dev": true
+    },
+    "universalify": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+      "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
+    },
+    "unpipe": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+      "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
+    },
+    "unzip": {
+      "version": "0.1.11",
+      "resolved": "https://registry.npmjs.org/unzip/-/unzip-0.1.11.tgz",
+      "integrity": "sha1-iXScY7BY19kNYZ+GuYqhU107l/A=",
+      "requires": {
+        "binary": "0.3.0",
+        "fstream": "0.1.31",
+        "match-stream": "0.0.2",
+        "pullstream": "0.4.1",
+        "readable-stream": "1.0.34",
+        "setimmediate": "1.0.5"
+      },
+      "dependencies": {
+        "fstream": {
+          "version": "0.1.31",
+          "resolved": "https://registry.npmjs.org/fstream/-/fstream-0.1.31.tgz",
+          "integrity": "sha1-czfwWPu7vvqMn1YaKMqwhJICyYg=",
+          "requires": {
+            "graceful-fs": "3.0.11",
+            "inherits": "2.0.3",
+            "mkdirp": "0.5.1",
+            "rimraf": "2.6.2"
+          }
+        },
+        "graceful-fs": {
+          "version": "3.0.11",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz",
+          "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=",
+          "requires": {
+            "natives": "1.1.4"
+          }
+        },
+        "isarray": {
+          "version": "0.0.1",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+          "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+        },
+        "readable-stream": {
+          "version": "1.0.34",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
+          "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
+          "requires": {
+            "core-util-is": "1.0.2",
+            "inherits": "2.0.3",
+            "isarray": "0.0.1",
+            "string_decoder": "0.10.31"
+          }
+        },
+        "string_decoder": {
+          "version": "0.10.31",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+          "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+        }
+      }
+    },
+    "unzip2": {
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/unzip2/-/unzip2-0.2.5.tgz",
+      "integrity": "sha1-TveleaeMFcUfVQ9qBT2xlBSciZI=",
+      "requires": {
+        "binary": "0.3.0",
+        "fstream": "0.1.31",
+        "match-stream": "0.0.2",
+        "pullstream": "0.4.1",
+        "readable-stream": "1.0.34",
+        "setimmediate": "1.0.5"
+      },
+      "dependencies": {
+        "fstream": {
+          "version": "0.1.31",
+          "resolved": "https://registry.npmjs.org/fstream/-/fstream-0.1.31.tgz",
+          "integrity": "sha1-czfwWPu7vvqMn1YaKMqwhJICyYg=",
+          "requires": {
+            "graceful-fs": "3.0.11",
+            "inherits": "2.0.3",
+            "mkdirp": "0.5.1",
+            "rimraf": "2.6.2"
+          }
+        },
+        "graceful-fs": {
+          "version": "3.0.11",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz",
+          "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=",
+          "requires": {
+            "natives": "1.1.4"
+          }
+        },
+        "isarray": {
+          "version": "0.0.1",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+          "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+        },
+        "readable-stream": {
+          "version": "1.0.34",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
+          "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
+          "requires": {
+            "core-util-is": "1.0.2",
+            "inherits": "2.0.3",
+            "isarray": "0.0.1",
+            "string_decoder": "0.10.31"
+          }
+        },
+        "string_decoder": {
+          "version": "0.10.31",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+          "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+        }
+      }
+    },
+    "url2": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/url2/-/url2-0.0.0.tgz",
+      "integrity": "sha1-Tqq9HVw6yQ1iq0SFyZhCKGWgSxo="
+    },
+    "user-home": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz",
+      "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=",
+      "dev": true,
+      "requires": {
+        "os-homedir": "1.0.2"
+      }
+    },
+    "util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+    },
+    "utils-merge": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz",
+      "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg="
+    },
+    "v8flags": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.1.tgz",
+      "integrity": "sha512-iw/1ViSEaff8NJ3HLyEjawk/8hjJib3E7pvG4pddVXfUg1983s3VGsiClDjhK64MQVDGqc1Q8r18S4VKQZS9EQ==",
+      "dev": true,
+      "requires": {
+        "homedir-polyfill": "1.0.1"
+      }
+    },
+    "vary": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+      "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
+    },
+    "verror": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+      "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+      "requires": {
+        "assert-plus": "1.0.0",
+        "core-util-is": "1.0.2",
+        "extsprintf": "1.3.0"
+      },
+      "dependencies": {
+        "assert-plus": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+          "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+        }
+      }
+    },
+    "walkdir": {
+      "version": "0.0.11",
+      "resolved": "https://registry.npmjs.org/walkdir/-/walkdir-0.0.11.tgz",
+      "integrity": "sha1-oW0CXrkxvQO1LzCMrtD0D86+lTI="
+    },
+    "weak-map": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/weak-map/-/weak-map-1.0.0.tgz",
+      "integrity": "sha1-tm5Wqd8L0lp2u/G1FNsSkIBhSjc="
+    },
+    "wide-align": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
+      "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
+      "requires": {
+        "string-width": "2.1.1"
+      }
+    },
+    "window-size": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
+      "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=",
+      "optional": true
+    },
+    "winston": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/winston/-/winston-2.3.1.tgz",
+      "integrity": "sha1-C0hCDZeMAYBM8CMLZIhhWYIloRk=",
+      "requires": {
+        "async": "1.0.0",
+        "colors": "1.0.3",
+        "cycle": "1.0.3",
+        "eyes": "0.1.8",
+        "isstream": "0.1.2",
+        "stack-trace": "0.0.10"
+      },
+      "dependencies": {
+        "async": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz",
+          "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k="
+        },
+        "colors": {
+          "version": "1.0.3",
+          "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
+          "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs="
+        }
+      }
+    },
+    "wordwrap": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
+      "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
+    },
+    "wotb": {
+      "version": "0.6.4",
+      "resolved": "https://registry.npmjs.org/wotb/-/wotb-0.6.4.tgz",
+      "integrity": "sha1-L/cCADEZjr6dbhFaiYtVSUCuw+k=",
+      "requires": {
+        "bindings": "1.2.1",
+        "nan": "2.2.0",
+        "node-pre-gyp": "0.6.23"
+      },
+      "dependencies": {
+        "node-pre-gyp": {
+          "version": "0.6.23",
+          "bundled": true,
+          "requires": {
+            "mkdirp": "0.5.1",
+            "nopt": "3.0.6",
+            "npmlog": "2.0.2",
+            "rc": "1.1.6",
+            "request": "2.69.0",
+            "rimraf": "2.5.2",
+            "semver": "5.1.0",
+            "tar": "2.2.1",
+            "tar-pack": "3.1.3"
+          },
+          "dependencies": {
+            "mkdirp": {
+              "version": "0.5.1",
+              "bundled": true,
+              "requires": {
+                "minimist": "0.0.8"
+              },
+              "dependencies": {
+                "minimist": {
+                  "version": "0.0.8",
+                  "bundled": true
+                }
+              }
+            },
+            "nopt": {
+              "version": "3.0.6",
+              "bundled": true,
+              "requires": {
+                "abbrev": "1.0.7"
+              },
+              "dependencies": {
+                "abbrev": {
+                  "version": "1.0.7",
+                  "bundled": true
+                }
+              }
+            },
+            "npmlog": {
+              "version": "2.0.2",
+              "bundled": true,
+              "requires": {
+                "ansi": "0.3.1",
+                "are-we-there-yet": "1.0.6",
+                "gauge": "1.2.7"
+              },
+              "dependencies": {
+                "ansi": {
+                  "version": "0.3.1",
+                  "bundled": true
+                },
+                "are-we-there-yet": {
+                  "version": "1.0.6",
+                  "bundled": true,
+                  "requires": {
+                    "delegates": "1.0.0",
+                    "readable-stream": "2.0.5"
+                  },
+                  "dependencies": {
+                    "delegates": {
+                      "version": "1.0.0",
+                      "bundled": true
+                    },
+                    "readable-stream": {
+                      "version": "2.0.5",
+                      "bundled": true,
+                      "requires": {
+                        "core-util-is": "1.0.2",
+                        "inherits": "2.0.1",
+                        "isarray": "0.0.1",
+                        "process-nextick-args": "1.0.6",
+                        "string_decoder": "0.10.31",
+                        "util-deprecate": "1.0.2"
+                      },
+                      "dependencies": {
+                        "core-util-is": {
+                          "version": "1.0.2",
+                          "bundled": true
+                        },
+                        "inherits": {
+                          "version": "2.0.1",
+                          "bundled": true
+                        },
+                        "isarray": {
+                          "version": "0.0.1",
+                          "bundled": true
+                        },
+                        "process-nextick-args": {
+                          "version": "1.0.6",
+                          "bundled": true
+                        },
+                        "string_decoder": {
+                          "version": "0.10.31",
+                          "bundled": true
+                        },
+                        "util-deprecate": {
+                          "version": "1.0.2",
+                          "bundled": true
+                        }
+                      }
+                    }
+                  }
+                },
+                "gauge": {
+                  "version": "1.2.7",
+                  "bundled": true,
+                  "requires": {
+                    "ansi": "0.3.1",
+                    "has-unicode": "2.0.0",
+                    "lodash.pad": "4.1.0",
+                    "lodash.padend": "4.2.0",
+                    "lodash.padstart": "4.2.0"
+                  },
+                  "dependencies": {
+                    "has-unicode": {
+                      "version": "2.0.0",
+                      "bundled": true
+                    },
+                    "lodash.pad": {
+                      "version": "4.1.0",
+                      "bundled": true,
+                      "requires": {
+                        "lodash.repeat": "4.0.0",
+                        "lodash.tostring": "4.1.2"
+                      },
+                      "dependencies": {
+                        "lodash.repeat": {
+                          "version": "4.0.0",
+                          "bundled": true,
+                          "requires": {
+                            "lodash.tostring": "4.1.2"
+                          }
+                        },
+                        "lodash.tostring": {
+                          "version": "4.1.2",
+                          "bundled": true
+                        }
+                      }
+                    },
+                    "lodash.padend": {
+                      "version": "4.2.0",
+                      "bundled": true,
+                      "requires": {
+                        "lodash.repeat": "4.0.0",
+                        "lodash.tostring": "4.1.2"
+                      },
+                      "dependencies": {
+                        "lodash.repeat": {
+                          "version": "4.0.0",
+                          "bundled": true,
+                          "requires": {
+                            "lodash.tostring": "4.1.2"
+                          }
+                        },
+                        "lodash.tostring": {
+                          "version": "4.1.2",
+                          "bundled": true
+                        }
+                      }
+                    },
+                    "lodash.padstart": {
+                      "version": "4.2.0",
+                      "bundled": true,
+                      "requires": {
+                        "lodash.repeat": "4.0.0",
+                        "lodash.tostring": "4.1.2"
+                      },
+                      "dependencies": {
+                        "lodash.repeat": {
+                          "version": "4.0.0",
+                          "bundled": true,
+                          "requires": {
+                            "lodash.tostring": "4.1.2"
+                          }
+                        },
+                        "lodash.tostring": {
+                          "version": "4.1.2",
+                          "bundled": true
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            },
+            "rc": {
+              "version": "1.1.6",
+              "bundled": true,
+              "requires": {
+                "deep-extend": "0.4.1",
+                "ini": "1.3.4",
+                "minimist": "1.2.0",
+                "strip-json-comments": "1.0.4"
+              },
+              "dependencies": {
+                "deep-extend": {
+                  "version": "0.4.1",
+                  "bundled": true
+                },
+                "ini": {
+                  "version": "1.3.4",
+                  "bundled": true
+                },
+                "minimist": {
+                  "version": "1.2.0",
+                  "bundled": true
+                },
+                "strip-json-comments": {
+                  "version": "1.0.4",
+                  "bundled": true
+                }
+              }
+            },
+            "request": {
+              "version": "2.69.0",
+              "bundled": true,
+              "requires": {
+                "aws-sign2": "0.6.0",
+                "aws4": "1.3.2",
+                "bl": "1.0.3",
+                "caseless": "0.11.0",
+                "combined-stream": "1.0.5",
+                "extend": "3.0.0",
+                "forever-agent": "0.6.1",
+                "form-data": "1.0.0-rc3",
+                "har-validator": "2.0.6",
+                "hawk": "3.1.3",
+                "http-signature": "1.1.1",
+                "is-typedarray": "1.0.0",
+                "isstream": "0.1.2",
+                "json-stringify-safe": "5.0.1",
+                "mime-types": "2.1.10",
+                "node-uuid": "1.4.7",
+                "oauth-sign": "0.8.1",
+                "qs": "6.0.2",
+                "stringstream": "0.0.5",
+                "tough-cookie": "2.2.1",
+                "tunnel-agent": "0.4.2"
+              },
+              "dependencies": {
+                "aws-sign2": {
+                  "version": "0.6.0",
+                  "bundled": true
+                },
+                "aws4": {
+                  "version": "1.3.2",
+                  "bundled": true,
+                  "requires": {
+                    "lru-cache": "4.0.0"
+                  },
+                  "dependencies": {
+                    "lru-cache": {
+                      "version": "4.0.0",
+                      "bundled": true,
+                      "requires": {
+                        "pseudomap": "1.0.2",
+                        "yallist": "2.0.0"
+                      },
+                      "dependencies": {
+                        "pseudomap": {
+                          "version": "1.0.2",
+                          "bundled": true
+                        },
+                        "yallist": {
+                          "version": "2.0.0",
+                          "bundled": true
+                        }
+                      }
+                    }
+                  }
+                },
+                "bl": {
+                  "version": "1.0.3",
+                  "bundled": true,
+                  "requires": {
+                    "readable-stream": "2.0.5"
+                  },
+                  "dependencies": {
+                    "readable-stream": {
+                      "version": "2.0.5",
+                      "bundled": true,
+                      "requires": {
+                        "core-util-is": "1.0.2",
+                        "inherits": "2.0.1",
+                        "isarray": "0.0.1",
+                        "process-nextick-args": "1.0.6",
+                        "string_decoder": "0.10.31",
+                        "util-deprecate": "1.0.2"
+                      },
+                      "dependencies": {
+                        "core-util-is": {
+                          "version": "1.0.2",
+                          "bundled": true
+                        },
+                        "inherits": {
+                          "version": "2.0.1",
+                          "bundled": true
+                        },
+                        "isarray": {
+                          "version": "0.0.1",
+                          "bundled": true
+                        },
+                        "process-nextick-args": {
+                          "version": "1.0.6",
+                          "bundled": true
+                        },
+                        "string_decoder": {
+                          "version": "0.10.31",
+                          "bundled": true
+                        },
+                        "util-deprecate": {
+                          "version": "1.0.2",
+                          "bundled": true
+                        }
+                      }
+                    }
+                  }
+                },
+                "caseless": {
+                  "version": "0.11.0",
+                  "bundled": true
+                },
+                "combined-stream": {
+                  "version": "1.0.5",
+                  "bundled": true,
+                  "requires": {
+                    "delayed-stream": "1.0.0"
+                  },
+                  "dependencies": {
+                    "delayed-stream": {
+                      "version": "1.0.0",
+                      "bundled": true
+                    }
+                  }
+                },
+                "extend": {
+                  "version": "3.0.0",
+                  "bundled": true
+                },
+                "forever-agent": {
+                  "version": "0.6.1",
+                  "bundled": true
+                },
+                "form-data": {
+                  "version": "1.0.0-rc3",
+                  "bundled": true,
+                  "requires": {
+                    "async": "1.5.2",
+                    "combined-stream": "1.0.5",
+                    "mime-types": "2.1.10"
+                  },
+                  "dependencies": {
+                    "async": {
+                      "version": "1.5.2",
+                      "bundled": true
+                    }
+                  }
+                },
+                "har-validator": {
+                  "version": "2.0.6",
+                  "bundled": true,
+                  "requires": {
+                    "chalk": "1.1.1",
+                    "commander": "2.9.0",
+                    "is-my-json-valid": "2.13.1",
+                    "pinkie-promise": "2.0.0"
+                  },
+                  "dependencies": {
+                    "chalk": {
+                      "version": "1.1.1",
+                      "bundled": true,
+                      "requires": {
+                        "ansi-styles": "2.2.0",
+                        "escape-string-regexp": "1.0.5",
+                        "has-ansi": "2.0.0",
+                        "strip-ansi": "3.0.1",
+                        "supports-color": "2.0.0"
+                      },
+                      "dependencies": {
+                        "ansi-styles": {
+                          "version": "2.2.0",
+                          "bundled": true,
+                          "requires": {
+                            "color-convert": "1.0.0"
+                          },
+                          "dependencies": {
+                            "color-convert": {
+                              "version": "1.0.0",
+                              "bundled": true
+                            }
+                          }
+                        },
+                        "escape-string-regexp": {
+                          "version": "1.0.5",
+                          "bundled": true
+                        },
+                        "has-ansi": {
+                          "version": "2.0.0",
+                          "bundled": true,
+                          "requires": {
+                            "ansi-regex": "2.0.0"
+                          },
+                          "dependencies": {
+                            "ansi-regex": {
+                              "version": "2.0.0",
+                              "bundled": true
+                            }
+                          }
+                        },
+                        "strip-ansi": {
+                          "version": "3.0.1",
+                          "bundled": true,
+                          "requires": {
+                            "ansi-regex": "2.0.0"
+                          },
+                          "dependencies": {
+                            "ansi-regex": {
+                              "version": "2.0.0",
+                              "bundled": true
+                            }
+                          }
+                        },
+                        "supports-color": {
+                          "version": "2.0.0",
+                          "bundled": true
+                        }
+                      }
+                    },
+                    "commander": {
+                      "version": "2.9.0",
+                      "bundled": true,
+                      "requires": {
+                        "graceful-readlink": "1.0.1"
+                      },
+                      "dependencies": {
+                        "graceful-readlink": {
+                          "version": "1.0.1",
+                          "bundled": true
+                        }
+                      }
+                    },
+                    "is-my-json-valid": {
+                      "version": "2.13.1",
+                      "bundled": true,
+                      "requires": {
+                        "generate-function": "2.0.0",
+                        "generate-object-property": "1.2.0",
+                        "jsonpointer": "2.0.0",
+                        "xtend": "4.0.1"
+                      },
+                      "dependencies": {
+                        "generate-function": {
+                          "version": "2.0.0",
+                          "bundled": true
+                        },
+                        "generate-object-property": {
+                          "version": "1.2.0",
+                          "bundled": true,
+                          "requires": {
+                            "is-property": "1.0.2"
+                          },
+                          "dependencies": {
+                            "is-property": {
+                              "version": "1.0.2",
+                              "bundled": true
+                            }
+                          }
+                        },
+                        "jsonpointer": {
+                          "version": "2.0.0",
+                          "bundled": true
+                        },
+                        "xtend": {
+                          "version": "4.0.1",
+                          "bundled": true
+                        }
+                      }
+                    },
+                    "pinkie-promise": {
+                      "version": "2.0.0",
+                      "bundled": true,
+                      "requires": {
+                        "pinkie": "2.0.4"
+                      },
+                      "dependencies": {
+                        "pinkie": {
+                          "version": "2.0.4",
+                          "bundled": true
+                        }
+                      }
+                    }
+                  }
+                },
+                "hawk": {
+                  "version": "3.1.3",
+                  "bundled": true,
+                  "requires": {
+                    "boom": "2.10.1",
+                    "cryptiles": "2.0.5",
+                    "hoek": "2.16.3",
+                    "sntp": "1.0.9"
+                  },
+                  "dependencies": {
+                    "boom": {
+                      "version": "2.10.1",
+                      "bundled": true,
+                      "requires": {
+                        "hoek": "2.16.3"
+                      }
+                    },
+                    "cryptiles": {
+                      "version": "2.0.5",
+                      "bundled": true,
+                      "requires": {
+                        "boom": "2.10.1"
+                      }
+                    },
+                    "hoek": {
+                      "version": "2.16.3",
+                      "bundled": true
+                    },
+                    "sntp": {
+                      "version": "1.0.9",
+                      "bundled": true,
+                      "requires": {
+                        "hoek": "2.16.3"
+                      }
+                    }
+                  }
+                },
+                "http-signature": {
+                  "version": "1.1.1",
+                  "bundled": true,
+                  "requires": {
+                    "assert-plus": "0.2.0",
+                    "jsprim": "1.2.2",
+                    "sshpk": "1.7.4"
+                  },
+                  "dependencies": {
+                    "assert-plus": {
+                      "version": "0.2.0",
+                      "bundled": true
+                    },
+                    "jsprim": {
+                      "version": "1.2.2",
+                      "bundled": true,
+                      "requires": {
+                        "extsprintf": "1.0.2",
+                        "json-schema": "0.2.2",
+                        "verror": "1.3.6"
+                      },
+                      "dependencies": {
+                        "extsprintf": {
+                          "version": "1.0.2",
+                          "bundled": true
+                        },
+                        "json-schema": {
+                          "version": "0.2.2",
+                          "bundled": true
+                        },
+                        "verror": {
+                          "version": "1.3.6",
+                          "bundled": true,
+                          "requires": {
+                            "extsprintf": "1.0.2"
+                          }
+                        }
+                      }
+                    },
+                    "sshpk": {
+                      "version": "1.7.4",
+                      "bundled": true,
+                      "requires": {
+                        "asn1": "0.2.3",
+                        "assert-plus": "0.2.0",
+                        "dashdash": "1.13.0",
+                        "ecc-jsbn": "0.1.1",
+                        "jodid25519": "1.0.2",
+                        "jsbn": "0.1.0",
+                        "tweetnacl": "0.14.1"
+                      },
+                      "dependencies": {
+                        "asn1": {
+                          "version": "0.2.3",
+                          "bundled": true
+                        },
+                        "dashdash": {
+                          "version": "1.13.0",
+                          "bundled": true,
+                          "requires": {
+                            "assert-plus": "1.0.0"
+                          },
+                          "dependencies": {
+                            "assert-plus": {
+                              "version": "1.0.0",
+                              "bundled": true
+                            }
+                          }
+                        },
+                        "ecc-jsbn": {
+                          "version": "0.1.1",
+                          "bundled": true,
+                          "optional": true,
+                          "requires": {
+                            "jsbn": "0.1.0"
+                          }
+                        },
+                        "jodid25519": {
+                          "version": "1.0.2",
+                          "bundled": true,
+                          "optional": true,
+                          "requires": {
+                            "jsbn": "0.1.0"
+                          }
+                        },
+                        "jsbn": {
+                          "version": "0.1.0",
+                          "bundled": true,
+                          "optional": true
+                        },
+                        "tweetnacl": {
+                          "version": "0.14.1",
+                          "bundled": true,
+                          "optional": true
+                        }
+                      }
+                    }
+                  }
+                },
+                "is-typedarray": {
+                  "version": "1.0.0",
+                  "bundled": true
+                },
+                "isstream": {
+                  "version": "0.1.2",
+                  "bundled": true
+                },
+                "json-stringify-safe": {
+                  "version": "5.0.1",
+                  "bundled": true
+                },
+                "mime-types": {
+                  "version": "2.1.10",
+                  "bundled": true,
+                  "requires": {
+                    "mime-db": "1.22.0"
+                  },
+                  "dependencies": {
+                    "mime-db": {
+                      "version": "1.22.0",
+                      "bundled": true
+                    }
+                  }
+                },
+                "node-uuid": {
+                  "version": "1.4.7",
+                  "bundled": true
+                },
+                "oauth-sign": {
+                  "version": "0.8.1",
+                  "bundled": true
+                },
+                "qs": {
+                  "version": "6.0.2",
+                  "bundled": true
+                },
+                "stringstream": {
+                  "version": "0.0.5",
+                  "bundled": true
+                },
+                "tough-cookie": {
+                  "version": "2.2.1",
+                  "bundled": true
+                },
+                "tunnel-agent": {
+                  "version": "0.4.2",
+                  "bundled": true
+                }
+              }
+            },
+            "rimraf": {
+              "version": "2.5.2",
+              "bundled": true,
+              "requires": {
+                "glob": "7.0.0"
+              },
+              "dependencies": {
+                "glob": {
+                  "version": "7.0.0",
+                  "bundled": true,
+                  "requires": {
+                    "inflight": "1.0.4",
+                    "inherits": "2.0.1",
+                    "minimatch": "3.0.0",
+                    "once": "1.3.3",
+                    "path-is-absolute": "1.0.0"
+                  },
+                  "dependencies": {
+                    "inflight": {
+                      "version": "1.0.4",
+                      "bundled": true,
+                      "requires": {
+                        "once": "1.3.3",
+                        "wrappy": "1.0.1"
+                      },
+                      "dependencies": {
+                        "wrappy": {
+                          "version": "1.0.1",
+                          "bundled": true
+                        }
+                      }
+                    },
+                    "inherits": {
+                      "version": "2.0.1",
+                      "bundled": true
+                    },
+                    "minimatch": {
+                      "version": "3.0.0",
+                      "bundled": true,
+                      "requires": {
+                        "brace-expansion": "1.1.3"
+                      },
+                      "dependencies": {
+                        "brace-expansion": {
+                          "version": "1.1.3",
+                          "bundled": true,
+                          "requires": {
+                            "balanced-match": "0.3.0",
+                            "concat-map": "0.0.1"
+                          },
+                          "dependencies": {
+                            "balanced-match": {
+                              "version": "0.3.0",
+                              "bundled": true
+                            },
+                            "concat-map": {
+                              "version": "0.0.1",
+                              "bundled": true
+                            }
+                          }
+                        }
+                      }
+                    },
+                    "once": {
+                      "version": "1.3.3",
+                      "bundled": true,
+                      "requires": {
+                        "wrappy": "1.0.1"
+                      },
+                      "dependencies": {
+                        "wrappy": {
+                          "version": "1.0.1",
+                          "bundled": true
+                        }
+                      }
+                    },
+                    "path-is-absolute": {
+                      "version": "1.0.0",
+                      "bundled": true
+                    }
+                  }
+                }
+              }
+            },
+            "semver": {
+              "version": "5.1.0",
+              "bundled": true
+            },
+            "tar": {
+              "version": "2.2.1",
+              "bundled": true,
+              "requires": {
+                "block-stream": "0.0.8",
+                "fstream": "1.0.8",
+                "inherits": "2.0.1"
+              },
+              "dependencies": {
+                "block-stream": {
+                  "version": "0.0.8",
+                  "bundled": true,
+                  "requires": {
+                    "inherits": "2.0.1"
+                  }
+                },
+                "fstream": {
+                  "version": "1.0.8",
+                  "bundled": true,
+                  "requires": {
+                    "graceful-fs": "4.1.3",
+                    "inherits": "2.0.1",
+                    "mkdirp": "0.5.1",
+                    "rimraf": "2.5.2"
+                  },
+                  "dependencies": {
+                    "graceful-fs": {
+                      "version": "4.1.3",
+                      "bundled": true
+                    }
+                  }
+                },
+                "inherits": {
+                  "version": "2.0.1",
+                  "bundled": true
+                }
+              }
+            },
+            "tar-pack": {
+              "version": "3.1.3",
+              "bundled": true,
+              "requires": {
+                "debug": "2.2.0",
+                "fstream": "1.0.8",
+                "fstream-ignore": "1.0.3",
+                "once": "1.3.3",
+                "readable-stream": "2.0.5",
+                "rimraf": "2.5.2",
+                "tar": "2.2.1",
+                "uid-number": "0.0.6"
+              },
+              "dependencies": {
+                "debug": {
+                  "version": "2.2.0",
+                  "bundled": true,
+                  "requires": {
+                    "ms": "0.7.1"
+                  },
+                  "dependencies": {
+                    "ms": {
+                      "version": "0.7.1",
+                      "bundled": true
+                    }
+                  }
+                },
+                "fstream": {
+                  "version": "1.0.8",
+                  "bundled": true,
+                  "requires": {
+                    "graceful-fs": "4.1.3",
+                    "inherits": "2.0.1",
+                    "mkdirp": "0.5.1",
+                    "rimraf": "2.5.2"
+                  },
+                  "dependencies": {
+                    "graceful-fs": {
+                      "version": "4.1.3",
+                      "bundled": true
+                    },
+                    "inherits": {
+                      "version": "2.0.1",
+                      "bundled": true
+                    }
+                  }
+                },
+                "fstream-ignore": {
+                  "version": "1.0.3",
+                  "bundled": true,
+                  "requires": {
+                    "fstream": "1.0.8",
+                    "inherits": "2.0.1",
+                    "minimatch": "3.0.0"
+                  },
+                  "dependencies": {
+                    "inherits": {
+                      "version": "2.0.1",
+                      "bundled": true
+                    },
+                    "minimatch": {
+                      "version": "3.0.0",
+                      "bundled": true,
+                      "requires": {
+                        "brace-expansion": "1.1.3"
+                      },
+                      "dependencies": {
+                        "brace-expansion": {
+                          "version": "1.1.3",
+                          "bundled": true,
+                          "requires": {
+                            "balanced-match": "0.3.0",
+                            "concat-map": "0.0.1"
+                          },
+                          "dependencies": {
+                            "balanced-match": {
+                              "version": "0.3.0",
+                              "bundled": true
+                            },
+                            "concat-map": {
+                              "version": "0.0.1",
+                              "bundled": true
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                },
+                "once": {
+                  "version": "1.3.3",
+                  "bundled": true,
+                  "requires": {
+                    "wrappy": "1.0.1"
+                  },
+                  "dependencies": {
+                    "wrappy": {
+                      "version": "1.0.1",
+                      "bundled": true
+                    }
+                  }
+                },
+                "readable-stream": {
+                  "version": "2.0.5",
+                  "bundled": true,
+                  "requires": {
+                    "core-util-is": "1.0.2",
+                    "inherits": "2.0.1",
+                    "isarray": "0.0.1",
+                    "process-nextick-args": "1.0.6",
+                    "string_decoder": "0.10.31",
+                    "util-deprecate": "1.0.2"
+                  },
+                  "dependencies": {
+                    "core-util-is": {
+                      "version": "1.0.2",
+                      "bundled": true
+                    },
+                    "inherits": {
+                      "version": "2.0.1",
+                      "bundled": true
+                    },
+                    "isarray": {
+                      "version": "0.0.1",
+                      "bundled": true
+                    },
+                    "process-nextick-args": {
+                      "version": "1.0.6",
+                      "bundled": true
+                    },
+                    "string_decoder": {
+                      "version": "0.10.31",
+                      "bundled": true
+                    },
+                    "util-deprecate": {
+                      "version": "1.0.2",
+                      "bundled": true
+                    }
+                  }
+                },
+                "uid-number": {
+                  "version": "0.0.6",
+                  "bundled": true
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    "wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+    },
+    "write": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz",
+      "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=",
+      "dev": true,
+      "requires": {
+        "mkdirp": "0.5.1"
+      }
+    },
+    "ws": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz",
+      "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==",
+      "requires": {
+        "options": "0.0.6",
+        "ultron": "1.0.2"
+      }
+    },
+    "xml-escape": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/xml-escape/-/xml-escape-1.0.0.tgz",
+      "integrity": "sha1-AJY9aXsq3wwYXE4E5zF0upsojrI=",
+      "dev": true
+    },
+    "xml2js": {
+      "version": "0.1.14",
+      "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.1.14.tgz",
+      "integrity": "sha1-UnTmf1pkxfkpdM2FE54DMq3GuQw=",
+      "requires": {
+        "sax": "1.2.4"
+      }
+    },
+    "xtend": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+      "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
+    },
+    "yargs": {
+      "version": "3.10.0",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
+      "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
+      "optional": true,
+      "requires": {
+        "camelcase": "1.2.1",
+        "cliui": "2.1.0",
+        "decamelize": "1.2.0",
+        "window-size": "0.1.0"
+      }
+    },
+    "yn": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz",
+      "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=",
+      "dev": true
+    },
+    "zip-stream": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-1.2.0.tgz",
+      "integrity": "sha1-qLxF9MG0lpnGuQGYuqyqzbzUugQ=",
+      "requires": {
+        "archiver-utils": "1.3.0",
+        "compress-commons": "1.2.2",
+        "lodash": "4.17.10",
+        "readable-stream": "2.3.6"
+      }
+    }
+  }
+}
diff --git a/package.json b/package.json
index a1eea7dc21f280b4ac0ec26127d6a877e626c5fb..b722a32a9d35af7ad12991d1d913e35fbaad55d3 100644
--- a/package.json
+++ b/package.json
@@ -25,6 +25,7 @@
     "prepublish": "tsc",
     "tsc": "tsc",
     "tscw": "tsc -w",
+    "doc": "typedoc --out typedoc/ index.ts app/ --mode file --readme README.md --includeDeclarations --sourcefile-url-prefix \"https://git.duniter.org/nodes/typescript/duniter/blob/loki/\"",
     "test": "nyc --reporter html mocha",
     "start": "node bin/duniter start",
     "build": "tsc && cd \"node_modules/duniter-ui\" && npm install && npm run build",
@@ -57,12 +58,13 @@
     "url": "https://github.com/duniter/duniter/issues"
   },
   "dependencies": {
+    "@types/ws": "^5.1.2",
     "archiver": "1.3.0",
     "async": "2.2.0",
     "bindings": "1.2.1",
     "body-parser": "1.17.1",
     "bs58": "^4.0.1",
-    "co": "4.6.0",
+    "cli-table": "^0.3.1",
     "colors": "1.1.2",
     "commander": "2.9.0",
     "cors": "2.8.2",
@@ -75,6 +77,7 @@
     "inquirer": "3.0.6",
     "jison": "0.4.17",
     "js-yaml": "3.8.2",
+    "lokijs": "^1.5.3",
     "merkle": "0.5.1",
     "moment": "2.19.3",
     "morgan": "1.8.1",
@@ -84,7 +87,7 @@
     "node-pre-gyp": "0.6.34",
     "node-uuid": "1.4.8",
     "optimist": "0.6.1",
-    "q-io": "1.13.2",
+    "q-io": "^1.13.5",
     "querablep": "^0.1.0",
     "request": "2.81.0",
     "request-promise": "4.2.0",
@@ -95,6 +98,7 @@
     "sqlite3": "3.1.13",
     "tail": "^1.2.1",
     "tweetnacl": "0.14.3",
+    "typedoc": "^0.11.1",
     "underscore": "1.8.3",
     "unzip": "0.1.11",
     "unzip2": "0.2.5",
@@ -103,6 +107,7 @@
     "ws": "1.1.5"
   },
   "devDependencies": {
+    "@types/lokijs": "^1.5.2",
     "@types/mocha": "^2.2.41",
     "@types/node": "^8.0.9",
     "@types/should": "^8.3.0",
@@ -118,7 +123,8 @@
     "supertest": "",
     "tmp": "0.0.29",
     "ts-node": "^3.3.0",
-    "typescript": "^2.4.1"
+    "typedoc-plugin-sourcefile-url": "^1.0.3",
+    "typescript": "~2.8.1"
   },
   "peerDependencies": {},
   "bin": {
diff --git a/release/arch/arm/build-arm.sh b/release/arch/arm/build-arm.sh
index ea7c25c0c5b60d5bd1e6329e37d3a53c50434874..9fbc767db8463f56dc0f9d363055fc332c5f325d 100755
--- a/release/arch/arm/build-arm.sh
+++ b/release/arch/arm/build-arm.sh
@@ -68,7 +68,7 @@ cp -R "$DOWNLOADS/node-${NVER}-linux-${ARCH}" node
 
 npm install
 
-npm install duniter-ui@1.6.x --save --production
+npm install duniter-ui@1.7.x --save --production
 SRC=`pwd`
 echo $SRC
 
diff --git a/release/arch/linux/build-lin.sh b/release/arch/linux/build-lin.sh
index 0ca5c2db5fbeb07093a4cacfb808cac5df0a7fe2..6c1f66a7675c56066dcb6a1472ac9c939ce7c619 100644
--- a/release/arch/linux/build-lin.sh
+++ b/release/arch/linux/build-lin.sh
@@ -123,7 +123,7 @@ NW_VERSION=0.28.0
 NW_RELEASE="v${NW_VERSION}"
 NW="nwjs-${NW_RELEASE}-linux-x64"
 NW_GZ="${NW}.tar.gz"
-DUNITER_UI_VER="1.6.x"
+DUNITER_UI_VER="1.7.x"
 
 nvm install ${NVER} || exit 1
 nvm use ${NVER} || exit 1
@@ -168,11 +168,11 @@ rm -Rf .gitignore .git || exit 1 # Remove git files
 
 # Build
 echo ">> VM: building modules..."
-npm install || exit 1
+yarn || exit 1
 
 # Duniter UI
-npm install "duniter-ui@${DUNITER_UI_VER}" || exit 1
-npm prune --production || exit 1
+yarn add "duniter-ui@${DUNITER_UI_VER}" || exit 1
+yarn --production || exit 1
 
 rm -rf release coverage test # Non production folders
 cp -r "${RELEASES}/duniter" "${RELEASES}/desktop_" || exit 1
diff --git a/release/arch/windows/build.bat b/release/arch/windows/build.bat
index 4ee27f5a7de6d0af5f4421a92c2fe6bcdfaa6332..57447a19304df74832407478cb24253eed76f321 100644
--- a/release/arch/windows/build.bat
+++ b/release/arch/windows/build.bat
@@ -66,7 +66,7 @@ call npm cache clean
 call npm install
 REM call npm test
 echo "Ajout du module 1/1 (duniter-ui)..."
-call npm install duniter-ui@1.6.x --save --production
+call npm install duniter-ui@1.7.x --save --production
 echo "Retrait des modules 'dev'..."
 call npm prune --production
 
diff --git a/release/scripts/create-release.js b/release/scripts/create-release.js
index badc4b1dfc80d086169e2a11c8ffbad75cc3c083..a64b17f98c1fb7c61866ecee2457291e47985c29 100644
--- a/release/scripts/create-release.js
+++ b/release/scripts/create-release.js
@@ -13,9 +13,6 @@
 
 "use strict";
 
-const co = require('co');
-const fs = require('fs');
-const path = require('path');
 const rp = require('request-promise');
 
 const GITHUB_TOKEN = process.argv[2]
@@ -23,12 +20,12 @@ const tagName      = process.argv[3]
 const command      = process.argv[4]
 const value        = process.argv[5]
 
-co(function*() {
+(async () => {
   try {
     // Get release URL
     let release
     try {
-      release = yield github('/repos/duniter/duniter/releases/tags/' + tagName)
+      release = await github('/repos/duniter/duniter/releases/tags/' + tagName)
     } catch (e) {
       if (!(e && e.statusCode == 404)) {
         throw e
@@ -38,7 +35,7 @@ co(function*() {
     // Creation
     if (command === "create") {
       if (!release) {
-        release = yield github('/repos/duniter/duniter/releases', 'POST', {
+        release = await github('/repos/duniter/duniter/releases', 'POST', {
           tag_name: tagName,
           draft: false,
           prerelease: true
@@ -59,7 +56,7 @@ co(function*() {
       if (!release) {
         console.error('Release ' + tagName + ' does not exist.')
       } else {
-        release = yield github('/repos/duniter/duniter/releases/' + release.id, 'PATCH', {
+        release = await github('/repos/duniter/duniter/releases/' + release.id, 'PATCH', {
           tag_name: tagName,
           draft: false,
           prerelease: isPreRelease
@@ -77,21 +74,19 @@ co(function*() {
     console.error(e);
   }
   process.exit(0);
-});
+})()
 
-function github(url, method = 'GET', body = undefined) {
-  return co(function*() {
-    yield new Promise((resolve) => setTimeout(resolve, 1));
-    return yield rp({
-      uri: 'https://api.github.com' + url,
-      method,
-      body,
-      json: true,
-      headers: {
-        'User-Agent': 'Request-Promise',
-        'Authorization': 'token ' + GITHUB_TOKEN,
-        'Accept': 'application/vnd.github.v3+json'
-      }
-    });
+async function github(url, method = 'GET', body = undefined) {
+  await new Promise((resolve) => setTimeout(resolve, 1));
+  return await rp({
+    uri: 'https://api.github.com' + url,
+    method,
+    body,
+    json: true,
+    headers: {
+      'User-Agent': 'Request-Promise',
+      'Authorization': 'token ' + GITHUB_TOKEN,
+      'Accept': 'application/vnd.github.v3+json'
+    }
   });
 }
diff --git a/release/scripts/upload-release.js b/release/scripts/upload-release.js
index 3d64eafabf4765124590193a31334cff7243e95b..a62e37b1c12436af3a8f30f74647e590557f1981 100644
--- a/release/scripts/upload-release.js
+++ b/release/scripts/upload-release.js
@@ -13,7 +13,6 @@
 
 "use strict";
 
-const co = require('co');
 const fs = require('fs');
 const path = require('path');
 const rp = require('request-promise');
@@ -23,51 +22,47 @@ const tagName      = process.argv[3]
 const filePath     = process.argv[4]
 const fileType     = getFileType(filePath)
 
-co(function*() {
+(async () => {
   try {
     // Get release URL
-    const release = yield github('/repos/duniter/duniter/releases/tags/' + tagName); // May be a draft
+    const release = await github('/repos/duniter/duniter/releases/tags/' + tagName); // May be a draft
     console.log('Release: ' + release.tag_name);
     const filename = path.basename(filePath)
     console.log('Uploading asset %s...', filename);
     const upload_url = release.upload_url.replace('{?name,label}', '?' + ['name=' + filename].join('&'));
-    yield githubUpload(upload_url, filePath, fileType)
+    await githubUpload(upload_url, filePath, fileType)
   } catch (e) {
     console.error(e);
   }
   process.exit(0);
-});
+})()
 
-function github(url) {
-  return co(function*() {
-    yield new Promise((resolve) => setTimeout(resolve, 1));
-    return yield rp({
-      uri: 'https://api.github.com' + url,
-      json: true,
-      headers: {
-        'User-Agent': 'Request-Promise',
-        'Authorization': 'token ' + GITHUB_TOKEN,
-        'Accept': 'application/vnd.github.v3+json'
-      }
-    });
+async function github(url) {
+  await new Promise((resolve) => setTimeout(resolve, 1));
+  return await rp({
+    uri: 'https://api.github.com' + url,
+    json: true,
+    headers: {
+      'User-Agent': 'Request-Promise',
+      'Authorization': 'token ' + GITHUB_TOKEN,
+      'Accept': 'application/vnd.github.v3+json'
+    }
   });
 }
 
-function githubUpload(upload_url, filePath, type) {
-  return co(function*() {
-    const stats = fs.statSync(filePath);
-    return yield rp({
-      method: 'POST',
-      body: fs.createReadStream(filePath),
-      uri: upload_url,
-      headers: {
-        'User-Agent': 'Request-Promise',
-        'Authorization': 'token ' + GITHUB_TOKEN,
-        'Content-type': type,
-        'Accept': 'application/json',
-        'Content-Length': stats.size
-      }
-    });
+async function githubUpload(upload_url, filePath, type) {
+  const stats = fs.statSync(filePath);
+  return await rp({
+    method: 'POST',
+    body: fs.createReadStream(filePath),
+    uri: upload_url,
+    headers: {
+      'User-Agent': 'Request-Promise',
+      'Authorization': 'token ' + GITHUB_TOKEN,
+      'Content-type': type,
+      'Accept': 'application/json',
+      'Content-Length': stats.size
+    }
   });
 }
 
diff --git a/server.ts b/server.ts
index 026ddf671f33b9ca98489bb4005e2257c2aad78b..1ddb6257a6f64b456858bc576b2739d241627661 100644
--- a/server.ts
+++ b/server.ts
@@ -17,9 +17,7 @@ import {PeeringService} from "./app/service/PeeringService"
 import {BlockchainService} from "./app/service/BlockchainService"
 import {TransactionService} from "./app/service/TransactionsService"
 import {ConfDTO} from "./app/lib/dto/ConfDTO"
-import {FileDAL} from "./app/lib/dal/fileDAL"
-import {DuniterBlockchain} from "./app/lib/blockchain/DuniterBlockchain"
-import {SQLBlockchain} from "./app/lib/blockchain/SqlBlockchain"
+import {FileDAL, FileDALParams} from "./app/lib/dal/fileDAL"
 import * as stream from "stream"
 import {KeyGen, randomKey} from "./app/lib/common-libs/crypto/keyring"
 import {parsers} from "./app/lib/common-libs/parsers/index"
@@ -37,7 +35,11 @@ import {PeerDTO} from "./app/lib/dto/PeerDTO"
 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 {ProxiesConf} from './app/lib/proxy';
+import {Directory, FileSystem} from "./app/lib/system/directory"
+import {DataErrors} from "./app/lib/common-libs/errors"
+import {DBPeer} from "./app/lib/db/DBPeer"
+import {Underscore} from "./app/lib/common-libs/underscore"
 
 export interface HookableServer {
   generatorGetJoinData: (...args:any[]) => Promise<any>
@@ -56,12 +58,11 @@ const es          = require('event-stream');
 const daemonize   = require("daemonize2")
 const constants   = require('./app/lib/constants');
 const jsonpckg    = require('./package.json');
-const directory   = require('./app/lib/system/directory');
 const logger      = require('./app/lib/logger').NewLogger('server');
 
 export class Server extends stream.Duplex implements HookableServer {
 
-  private paramsP:Promise<any>|null
+  private paramsP:Promise<FileDALParams>
   private endpointsDefinitions:(()=>Promise<string>)[] = []
   private wrongEndpointsFilters:((endpoints:string[])=>Promise<string[]>)[] = []
   startService:()=>Promise<void>
@@ -94,7 +95,7 @@ export class Server extends stream.Duplex implements HookableServer {
     this.version = jsonpckg.version;
     this.logger = logger;
 
-    this.paramsP = directory.getHomeParams(memoryOnly, home)
+    this.paramsP = Directory.getHomeParams(memoryOnly, home)
 
     this.documentFIFO = new GlobalFifoPromise()
 
@@ -158,9 +159,18 @@ export class Server extends stream.Duplex implements HookableServer {
     await this.dal.close()
   }
 
-  async loadConf(useDefaultConf:any = false) {
+  async reloadConf() {
+    await this.loadConf(false, true)
+  }
+
+  async loadConf(useDefaultConf:any = false, reuseExisting = false) {
     logger.debug('Loading conf...');
-    this.conf = await this.dal.loadConf(this.overrideConf, useDefaultConf)
+    const loaded = await this.dal.loadConf(this.overrideConf, useDefaultConf)
+    if (!reuseExisting || !this.conf) {
+      this.conf = loaded
+    } else {
+      Underscore.extend(this.conf, loaded) // Overwrite the current conf
+    }
     // Default values
     this.conf.proxiesConf      = this.conf.proxiesConf === undefined ?       new ProxiesConf()                            : this.conf.proxiesConf
     this.conf.remoteipv6       = this.conf.remoteipv6 === undefined ?        this.conf.ipv6                               : this.conf.remoteipv6
@@ -196,8 +206,6 @@ export class Server extends stream.Duplex implements HookableServer {
     // Extract key pair
     this.keyPair = KeyGen(this.conf.pair.pub, this.conf.pair.sec);
     this.sign = (msg:string) => this.keyPair.sign(msg)
-    // Blockchain object
-    this.blockchain = new DuniterBlockchain(new SQLBlockchain(this.dal), this.dal);
     // Update services
     this.IdentityService.setConfDAL(this.conf, this.dal)
     this.MembershipService.setConfDAL(this.conf, this.dal)
@@ -327,21 +335,23 @@ export class Server extends stream.Duplex implements HookableServer {
     let head_1 = await this.dal.bindexDAL.head(1);
     if (head_1) {
       // Case 1: b_index < block
-      await this.dal.blockDAL.exec('DELETE FROM block WHERE NOT fork AND number > ' + head_1.number);
+      await this.dal.blockDAL.dropNonForkBlocksAbove(head_1.number)
       // Case 2: b_index > block
       const current = await this.dal.blockDAL.getCurrent();
-      const nbBlocksToRevert = (head_1.number - current.number);
+      const nbBlocksToRevert = (head_1.number - (current as DBBlock).number);
       for (let i = 0; i < nbBlocksToRevert; i++) {
-        await this.revert();
+        await this.revertHead();
       }
     }
+    // Database trimming
+    await this.dal.loki.flushAndTrimData()
     // Eventual block resolution
     await this.BlockchainService.blockResolution()
     // Eventual fork resolution
     await this.BlockchainService.forkResolution()
   }
 
-  recomputeSelfPeer() {
+  recomputeSelfPeer(): Promise<DBPeer | null> {
     return this.PeeringService.generateSelfPeer(this.conf)
   }
 
@@ -364,24 +374,24 @@ export class Server extends stream.Duplex implements HookableServer {
     const params = await this.paramsP;
     const myFS = params.fs;
     const rootPath = params.home;
-    const existsDir = await myFS.exists(rootPath);
+    const existsDir = await myFS.fsExists(rootPath);
     if (existsDir) {
-      await myFS.removeTree(rootPath);
+      await myFS.fsRemoveTree(rootPath);
     }
   }
 
   async resetAll(done:any = null) {
     await this.resetDataHook()
     await this.resetConfigHook()
-    const files = ['stats', 'cores', 'current', directory.DUNITER_DB_NAME, directory.DUNITER_DB_NAME + '.db', directory.DUNITER_DB_NAME + '.log', directory.WOTB_FILE, 'export.zip', 'import.zip', 'conf'];
-    const dirs  = ['blocks', 'blockchain', 'ud_history', 'branches', 'certs', 'txs', 'cores', 'sources', 'links', 'ms', 'identities', 'peers', 'indicators', 'leveldb'];
+    const files = ['stats', 'cores', 'current', Directory.DUNITER_DB_NAME, Directory.DUNITER_DB_NAME + '.db', Directory.DUNITER_DB_NAME + '.log', Directory.WOTB_FILE, 'export.zip', 'import.zip', 'conf'];
+    const dirs  = ['archives', 'loki', 'blocks', 'blockchain', 'ud_history', 'branches', 'certs', 'txs', 'cores', 'sources', 'links', 'ms', 'identities', 'peers', 'indicators', 'leveldb'];
     return this.resetFiles(files, dirs, done);
   }
 
   async resetData(done:any = null) {
     await this.resetDataHook()
-    const files = ['stats', 'cores', 'current', directory.DUNITER_DB_NAME, directory.DUNITER_DB_NAME + '.db', directory.DUNITER_DB_NAME + '.log', directory.WOTB_FILE];
-    const dirs  = ['blocks', 'ud_history', 'branches', 'certs', 'txs', 'cores', 'sources', 'links', 'ms', 'identities', 'peers', 'indicators', 'leveldb'];
+    const files = ['stats', 'cores', 'current', Directory.DUNITER_DB_NAME, Directory.DUNITER_DB_NAME + '.db', Directory.DUNITER_DB_NAME + '.log', Directory.WOTB_FILE];
+    const dirs  = ['archives', 'loki', 'blocks', 'ud_history', 'branches', 'certs', 'txs', 'cores', 'sources', 'links', 'ms', 'identities', 'peers', 'indicators', 'leveldb'];
     await this.resetFiles(files, dirs, done);
   }
 
@@ -407,12 +417,12 @@ export class Server extends stream.Duplex implements HookableServer {
     const rootPath = params.home;
     const myFS = params.fs;
     const archive = archiver('zip');
-    if (await myFS.exists(path.join(rootPath, 'indicators'))) {
+    if (await myFS.fsExists(path.join(rootPath, 'indicators'))) {
       archive.directory(path.join(rootPath, 'indicators'), '/indicators', undefined, { name: 'indicators'});
     }
     const files = ['duniter.db', 'stats.json', 'wotb.bin'];
     for (const file of files) {
-      if (await myFS.exists(path.join(rootPath, file))) {
+      if (await myFS.fsExists(path.join(rootPath, file))) {
         archive.file(path.join(rootPath, file), { name: file });
       }
     }
@@ -434,42 +444,42 @@ export class Server extends stream.Duplex implements HookableServer {
   async cleanDBData() {
     await this.dal.cleanCaches();
     this.dal.wotb.resetWoT();
-    const files = ['stats', 'cores', 'current', directory.DUNITER_DB_NAME, directory.DUNITER_DB_NAME + '.db', directory.DUNITER_DB_NAME + '.log'];
-    const dirs  = ['blocks', 'ud_history', 'branches', 'certs', 'txs', 'cores', 'sources', 'links', 'ms', 'identities', 'peers', 'indicators', 'leveldb'];
+    const files = ['stats', 'cores', 'current', Directory.DUNITER_DB_NAME, Directory.DUNITER_DB_NAME + '.db', Directory.DUNITER_DB_NAME + '.log'];
+    const dirs  = ['loki', 'blocks', 'ud_history', 'branches', 'certs', 'txs', 'cores', 'sources', 'links', 'ms', 'identities', 'peers', 'indicators', 'leveldb'];
     return this.resetFiles(files, dirs);
   }
 
   private async resetFiles(files:string[], dirs:string[], done:any = null) {
     try {
       const params = await this.paramsP;
-      const myFS = params.fs;
+      const myFS:FileSystem = params.fs;
       const rootPath = params.home;
       for (const fName of files) {
         // JSON file?
-        const existsJSON = await myFS.exists(rootPath + '/' + fName + '.json');
+        const existsJSON = await myFS.fsExists(rootPath + '/' + fName + '.json');
         if (existsJSON) {
           const theFilePath = rootPath + '/' + fName + '.json';
-          await myFS.remove(theFilePath);
-          if (await myFS.exists(theFilePath)) {
+          await myFS.fsUnlink(theFilePath);
+          if (await myFS.fsExists(theFilePath)) {
             throw Error('Failed to delete file "' + theFilePath + '"');
           }
         } else {
           // Normal file?
           const normalFile = path.join(rootPath, fName);
-          const existsFile = await myFS.exists(normalFile);
+          const existsFile = await myFS.fsExists(normalFile);
           if (existsFile) {
-            await myFS.remove(normalFile);
-            if (await myFS.exists(normalFile)) {
+            await myFS.fsUnlink(normalFile);
+            if (await myFS.fsExists(normalFile)) {
               throw Error('Failed to delete file "' + normalFile + '"');
             }
           }
         }
       }
       for (const dirName of dirs) {
-        const existsDir = await myFS.exists(rootPath + '/' + dirName);
+        const existsDir = await myFS.fsExists(rootPath + '/' + dirName);
         if (existsDir) {
-          await myFS.removeTree(rootPath + '/' + dirName);
-          if (await myFS.exists(rootPath + '/' + dirName)) {
+          await myFS.fsRemoveTree(rootPath + '/' + dirName);
+          if (await myFS.fsExists(rootPath + '/' + dirName)) {
             throw Error('Failed to delete folder "' + rootPath + '/' + dirName + '"');
           }
         }
@@ -492,8 +502,15 @@ export class Server extends stream.Duplex implements HookableServer {
     return this.BlockchainService.revertCurrentBlock()
   }
 
+  revertHead() {
+    return this.BlockchainService.revertCurrentHead()
+  }
+
   async revertTo(number:number) {
     const current = await this.BlockchainService.current();
+    if (!current) {
+      throw Error(DataErrors[DataErrors.CANNOT_REVERT_NO_CURRENT_BLOCK])
+    }
     for (let i = 0, count = current.number - number; i < count; i++) {
       await this.BlockchainService.revertCurrentBlock()
     }
@@ -518,6 +535,9 @@ export class Server extends stream.Duplex implements HookableServer {
 
   async reapplyTo(number:number) {
     const current = await this.BlockchainService.current();
+    if (!current) {
+      throw Error(DataErrors[DataErrors.CANNOT_REAPPLY_NO_CURRENT_BLOCK])
+    }
     if (current.number == number) {
       logger.warn('Already reached');
     } else {
@@ -543,8 +563,8 @@ export class Server extends stream.Duplex implements HookableServer {
     const argv = this.getCommand(overrideCommand, insteadOfCmd)
     return daemonize.setup({
       main: mainModule,
-      name: directory.INSTANCE_NAME,
-      pidfile: path.join(directory.INSTANCE_HOME, "app.pid"),
+      name: Directory.INSTANCE_NAME,
+      pidfile: path.join(Directory.INSTANCE_HOME, "app.pid"),
       argv,
       cwd
     });
@@ -631,7 +651,7 @@ export class Server extends stream.Duplex implements HookableServer {
   /**
    * Default WoT incoming data for new block. To be overriden by a module.
    */
-  generatorGetJoinData(current:DBBlock, idtyHash:string , char:string): Promise<any> {
+  generatorGetJoinData(current:DBBlock|null, idtyHash:string , char:string): Promise<any> {
     return Promise.resolve({})
   }
 
diff --git a/test/blockchain/basic-blockchain.ts b/test/blockchain/basic-blockchain.ts
deleted file mode 100644
index f052c4dace531f85734b0b33ec64ab6ddb0d488d..0000000000000000000000000000000000000000
--- a/test/blockchain/basic-blockchain.ts
+++ /dev/null
@@ -1,174 +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 {BasicBlockchain} from "../../app/lib/blockchain/BasicBlockchain"
-import {ArrayBlockchain} from "./lib/ArrayBlockchain"
-import {SQLBlockchain} from "../../app/lib/blockchain/SqlBlockchain"
-import {SQLiteDriver} from "../../app/lib/dal/drivers/SQLiteDriver"
-import {BIndexDAL} from "../../app/lib/dal/sqliteDAL/index/BIndexDAL";
-import {MetaDAL} from "../../app/lib/dal/sqliteDAL/MetaDAL";
-import {ConfDTO} from "../../app/lib/dto/ConfDTO";
-
-const assert = require('assert')
-
-let blockchain:BasicBlockchain,
-  emptyBlockchain:BasicBlockchain
-
-describe('Basic Memory Blockchain', () => {
-
-  before(() => {
-    blockchain = new BasicBlockchain(new ArrayBlockchain())
-    emptyBlockchain = new BasicBlockchain(new ArrayBlockchain())
-  })
-
-  it('should be able to push 3 blocks and read them', async () => {
-    await blockchain.pushBlock({ name: 'A' })
-    await blockchain.pushBlock({ name: 'B' })
-    await blockchain.pushBlock({ name: 'C' })
-    const HEAD0 = await blockchain.head()
-    const HEAD1 = await blockchain.head(1)
-    const HEAD2 = await blockchain.head(2)
-    const BLOCK0 = await blockchain.getBlock(0)
-    const BLOCK1 = await blockchain.getBlock(1)
-    const BLOCK2 = await blockchain.getBlock(2)
-    assert.equal(HEAD0.name, 'C')
-    assert.equal(HEAD1.name, 'B')
-    assert.equal(HEAD2.name, 'A')
-    assert.deepEqual(HEAD2, BLOCK0)
-    assert.deepEqual(HEAD1, BLOCK1)
-    assert.deepEqual(HEAD0, BLOCK2)
-  })
-
-  it('should be able to read a range', async () => {
-    const range1 = await blockchain.headRange(2)
-    assert.equal(range1.length, 2)
-    assert.equal(range1[0].name, 'C')
-    assert.equal(range1[1].name, 'B')
-    const range2 = await blockchain.headRange(6)
-    assert.equal(range2.length, 3)
-    assert.equal(range2[0].name, 'C')
-    assert.equal(range2[1].name, 'B')
-    assert.equal(range2[2].name, 'A')
-  })
-
-  it('should have a good height', async () => {
-    const height1 = await blockchain.height()
-    await blockchain.pushBlock({ name: 'D' })
-    const height2 = await blockchain.height()
-    const height3 = await emptyBlockchain.height()
-    assert.equal(height1, 3)
-    assert.equal(height2, 4)
-    assert.equal(height3, 0)
-  })
-
-  it('should be able to revert blocks', async () => {
-    const reverted = await blockchain.revertHead()
-    const height2 = await blockchain.height()
-    assert.equal(height2, 3)
-    assert.equal(reverted.name, 'D')
-  })
-
-})
-
-describe('Basic SQL Blockchain', () => {
-
-  before(async () => {
-
-    {
-      const db = new SQLiteDriver(':memory:')
-
-      const bindexDAL = new BIndexDAL(db)
-      const metaDAL = new MetaDAL(db)
-
-      await bindexDAL.init()
-      await metaDAL.init()
-      await metaDAL.exec('CREATE TABLE txs (id INTEGER null);')
-      await metaDAL.exec('CREATE TABLE idty (id INTEGER null);')
-      await metaDAL.exec('CREATE TABLE cert (id INTEGER null);')
-      await metaDAL.exec('CREATE TABLE membership (id INTEGER null);')
-      await metaDAL.exec('CREATE TABLE block (fork INTEGER null);')
-      await metaDAL.upgradeDatabase(ConfDTO.mock());
-
-      const dal = { bindexDAL }
-
-      blockchain = new BasicBlockchain(new SQLBlockchain(dal))
-    }
-    {
-      const db = new SQLiteDriver(':memory:')
-
-      const bindexDAL = new BIndexDAL(db)
-      const metaDAL = new MetaDAL(db)
-
-      await bindexDAL.init()
-      await metaDAL.init()
-      await metaDAL.exec('CREATE TABLE txs (id INTEGER null);')
-      await metaDAL.exec('CREATE TABLE idty (id INTEGER null);')
-      await metaDAL.exec('CREATE TABLE cert (id INTEGER null);')
-      await metaDAL.exec('CREATE TABLE membership (id INTEGER null);')
-      await metaDAL.exec('CREATE TABLE block (fork INTEGER null);')
-      await metaDAL.upgradeDatabase(ConfDTO.mock());
-
-      const dal = { bindexDAL }
-
-      emptyBlockchain = new BasicBlockchain(new SQLBlockchain(dal))
-    }
-  })
-
-  it('should be able to push 3 blocks and read them', async () => {
-    await blockchain.pushBlock({ number: 0, version: 1, bsize: 0, hash: 'H', issuer: 'I', time: 1, membersCount: 1, issuersCount: 1, issuersFrame: 1, issuersFrameVar: 1, avgBlockSize: 0, medianTime: 1, dividend: 10, mass: 100, unitBase: 0, powMin: 0, udTime: 0, udReevalTime: 0, diffNumber: 1, speed: 1, massReeval: 1 })
-    await blockchain.pushBlock({ number: 1, version: 1, bsize: 0, hash: 'H', issuer: 'I', time: 1, membersCount: 1, issuersCount: 1, issuersFrame: 1, issuersFrameVar: 1, avgBlockSize: 0, medianTime: 1, dividend: 10, mass: 100, unitBase: 0, powMin: 0, udTime: 0, udReevalTime: 0, diffNumber: 1, speed: 1, massReeval: 1 })
-    await blockchain.pushBlock({ number: 2, version: 1, bsize: 0, hash: 'H', issuer: 'I', time: 1, membersCount: 1, issuersCount: 1, issuersFrame: 1, issuersFrameVar: 1, avgBlockSize: 0, medianTime: 1, dividend: 10, mass: 100, unitBase: 0, powMin: 0, udTime: 0, udReevalTime: 0, diffNumber: 1, speed: 1, massReeval: 1 })
-    const HEAD0 = await blockchain.head()
-    const HEAD1 = await blockchain.head(1)
-    const HEAD2 = await blockchain.head(2)
-    const BLOCK0 = await blockchain.getBlock(0)
-    const BLOCK1 = await blockchain.getBlock(1)
-    const BLOCK2 = await blockchain.getBlock(2)
-    assert.equal(HEAD0.number, 2)
-    assert.equal(HEAD1.number, 1)
-    assert.equal(HEAD2.number, 0)
-    assert.deepEqual(HEAD2, BLOCK0)
-    assert.deepEqual(HEAD1, BLOCK1)
-    assert.deepEqual(HEAD0, BLOCK2)
-  })
-
-  it('should be able to read a range', async () => {
-    const range1 = await blockchain.headRange(2)
-    assert.equal(range1.length, 2)
-    assert.equal(range1[0].number, 2)
-    assert.equal(range1[1].number, 1)
-    const range2 = await blockchain.headRange(6)
-    assert.equal(range2.length, 3)
-    assert.equal(range2[0].number, 2)
-    assert.equal(range2[1].number, 1)
-    assert.equal(range2[2].number, 0)
-  })
-
-  it('should have a good height', async () => {
-    const height1 = await blockchain.height()
-    await blockchain.pushBlock({ number: 3, version: 1, bsize: 0, hash: 'H', issuer: 'I', time: 1, membersCount: 1, issuersCount: 1, issuersFrame: 1, issuersFrameVar: 1, avgBlockSize: 0, medianTime: 1, dividend: 10, mass: 100, unitBase: 0, powMin: 0, udTime: 0, udReevalTime: 0, diffNumber: 1, speed: 1, massReeval: 1 })
-    const height2 = await blockchain.height()
-    const height3 = await emptyBlockchain.height()
-    assert.equal(height1, 3)
-    assert.equal(height2, 4)
-    assert.equal(height3, 0)
-  })
-
-  it('should be able to revert blocks', async () => {
-    const reverted = await blockchain.revertHead()
-    const height2 = await blockchain.height()
-    assert.equal(height2, 3)
-    assert.equal(reverted.number, 3)
-  })
-
-})
diff --git a/test/blockchain/indexed-blockchain.ts b/test/blockchain/indexed-blockchain.ts
deleted file mode 100644
index 8304e1c32e5c05d653980ac21d52d633b550777b..0000000000000000000000000000000000000000
--- a/test/blockchain/indexed-blockchain.ts
+++ /dev/null
@@ -1,467 +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";
-import {ArrayBlockchain} from "./lib/ArrayBlockchain"
-import {IndexedBlockchain} from "../../app/lib/blockchain/IndexedBlockchain"
-import {MemoryIndex} from "./lib/MemoryIndex"
-import {SQLIndex} from "../../app/lib/blockchain/SqlIndex"
-import {SQLiteDriver} from "../../app/lib/dal/drivers/SQLiteDriver"
-
-const assert = require('assert')
-
-describe('Indexed Blockchain', () => {
-
-  describe('MemoryIndex', () => {
-
-    let blockchain:any
-
-    describe('PK on one field', () => {
-
-      before(() => {
-        blockchain = new IndexedBlockchain(new ArrayBlockchain(), new MemoryIndex(), 'writtenOn', {
-          iindex: {
-            pk: 'name',
-            remove: 'expired'
-          },
-          zindex: {
-            pk: 'name'
-          }
-        })
-      })
-
-      it('should be able to index data', async () => {
-        await blockchain.recordIndex({
-          iindex: [
-            { name: 'A', status: 'OK', writtenOn: 23000, events: 0, member: false },
-            { name: 'A', status: 'OK', writtenOn: 23000, events: 4 },
-            { name: 'A', status: 'OK', writtenOn: 23000, events: 5, member: true },
-            { name: 'A', status: 'OK', writtenOn: 23601 },
-            { name: 'A', status: 'OK', writtenOn: 23888 },
-            { name: 'A', status: 'OK', writtenOn: 23889 },
-            { name: 'B', status: 'OK', writtenOn: 23000, events: 1, member: false },
-            { name: 'B', status: 'KO', writtenOn: 23000, events: null },
-            { name: 'C', status: 'KO', writtenOn: 23500 },
-            { name: 'D', status: 'KO', writtenOn: 23500 },
-            { name: 'D', status: 'KO', writtenOn: 23521, expired: true }
-          ]
-        })
-      })
-
-      it('should be able to reduce data', async () => {
-        const reducedA = await blockchain.indexReduce('iindex', { name: 'A' })
-        const reducedB = await blockchain.indexReduce('iindex', { name: 'B' })
-        assert.deepEqual(reducedA, { name: 'A', status: 'OK', writtenOn: 23889, events: 5, member: true })
-        assert.deepEqual(reducedB, { name: 'B', status: 'KO', writtenOn: 23000, events: 1, member: false })
-      })
-
-      it('should be able to count data', async () => {
-        const countAi = await blockchain.indexCount('iindex', { name: 'A' })
-        const countBi = await blockchain.indexCount('iindex', { name: 'B' })
-        const countCi = await blockchain.indexCount('iindex', { name: 'C' })
-        const countDi = await blockchain.indexCount('iindex', { name: 'D' })
-        const countBz = await blockchain.indexCount('zindex', { name: 'B' })
-        assert.equal(countAi, 6)
-        assert.equal(countBi, 2)
-        assert.equal(countCi, 1)
-        assert.equal(countDi, 2)
-        assert.equal(countBz, 0)
-      })
-
-      it('should be able to reduce grouped data', async () => {
-        const reducedBy = await blockchain.indexReduceGroupBy('iindex', { writtenOn: 23000 }, ['name'])
-        assert.deepEqual(reducedBy, [
-          { name: 'A', status: 'OK', writtenOn: 23000, events: 5, member: true },
-          { name: 'B', status: 'KO', writtenOn: 23000, events: 1, member: false }
-        ])
-      })
-
-      it('should be able to trim data', async () => {
-        // The number of records should decrease
-        await blockchain.indexTrim(23601)
-        const countAi = await blockchain.indexCount('iindex', { name: 'A' })
-        const countBi = await blockchain.indexCount('iindex', { name: 'B' })
-        const countCi = await blockchain.indexCount('iindex', { name: 'C' })
-        const countDi = await blockchain.indexCount('iindex', { name: 'D' })
-        const countBz = await blockchain.indexCount('zindex', { name: 'B' })
-        assert.equal(countAi, 4)
-        assert.equal(countBi, 1)
-        assert.equal(countCi, 1)
-        assert.equal(countDi, 0) // Expired = remove rows on trim
-        assert.equal(countBz, 0)
-        const reducedAi = await blockchain.indexReduce('iindex', { name: 'A' })
-        const reducedBi = await blockchain.indexReduce('iindex', { name: 'B' })
-        const reducedCi = await blockchain.indexReduce('iindex', { name: 'C' })
-        const reducedDi = await blockchain.indexReduce('iindex', { name: 'D' })
-        const reducedBz = await blockchain.indexReduce('zindex', { name: 'B' })
-        assert.deepEqual(reducedAi, { name: 'A', status: 'OK', writtenOn: 23889, events: 5, member: true })
-        assert.deepEqual(reducedBi, { name: 'B', status: 'KO', writtenOn: 23000, events: 1, member: false })
-        assert.deepEqual(reducedCi, { name: 'C', status: 'KO', writtenOn: 23500 })
-        assert.deepEqual(reducedDi, {})
-        assert.deepEqual(reducedBz, {})
-      })
-    })
-
-    describe('PK on two fields', () => {
-
-      before(() => {
-        blockchain = new IndexedBlockchain(new ArrayBlockchain(), new MemoryIndex(), 'writtenOn', {
-          iindex: {
-            pk: ['id', 'pos'],
-            remove: 'expired'
-          },
-          zindex: {
-            pk: 'name'
-          }
-        })
-      })
-
-      it('should be able to index data', async () => {
-        await blockchain.recordIndex({
-          iindex: [
-            { id: 'A', pos: 0, status: 'OK', writtenOn: 23000, events: 0, member: false },
-            { id: 'A', pos: 0, status: 'OK', writtenOn: 23000, events: 4 },
-            { id: 'A', pos: 0, status: 'OK', writtenOn: 23000, events: 5, member: true },
-            { id: 'A', pos: 0, status: 'OK', writtenOn: 23601 },
-            { id: 'A', pos: 1, status: 'OK', writtenOn: 23888 },
-            { id: 'A', pos: 2, status: 'OK', writtenOn: 23889 },
-            { id: 'B', pos: 0, status: 'OK', writtenOn: 23000, events: 1, member: false },
-            { id: 'B', pos: 0, status: 'KO', writtenOn: 23000, events: null },
-            { id: 'C', pos: 0, status: 'KO', writtenOn: 23500 },
-            { id: 'D', pos: 0, status: 'KO', writtenOn: 23500 },
-            { id: 'D', pos: 1, status: 'KO', writtenOn: 23521, expired: true }
-          ]
-        })
-      })
-
-      it('should be able to reduce data', async () => {
-        const reducedA = await blockchain.indexReduce('iindex', { id: 'A', pos: 0 })
-        const reducedB = await blockchain.indexReduce('iindex', { id: 'B', pos: 0 })
-        assert.deepEqual(reducedA, { id: 'A', pos: 0, status: 'OK', writtenOn: 23601, events: 5, member: true })
-        assert.deepEqual(reducedB, { id: 'B', pos: 0, status: 'KO', writtenOn: 23000, events: 1, member: false })
-      })
-
-      it('should be able to count data', async () => {
-        const countAi = await blockchain.indexCount('iindex', { id: 'A', pos: 0 })
-        const countBi = await blockchain.indexCount('iindex', { id: 'B', pos: 0 })
-        const countCi = await blockchain.indexCount('iindex', { id: 'C', pos: 0 })
-        const countDi = await blockchain.indexCount('iindex', { id: 'D', pos: 0 })
-        const countBz = await blockchain.indexCount('zindex', { id: 'B', pos: 0 })
-        assert.equal(countAi, 4)
-        assert.equal(countBi, 2)
-        assert.equal(countCi, 1)
-        assert.equal(countDi, 1)
-        assert.equal(countBz, 0)
-      })
-
-      it('should be able to reduce grouped data', async () => {
-        const reducedBy = await blockchain.indexReduceGroupBy('iindex', { writtenOn: 23000 }, ['id', 'pos'])
-        assert.deepEqual(reducedBy, [
-          { id: 'A', pos: 0, status: 'OK', writtenOn: 23000, events: 5, member: true },
-          { id: 'B', pos: 0, status: 'KO', writtenOn: 23000, events: 1, member: false }
-        ])
-      })
-
-      it('should be able to trim data', async () => {
-        // The number of records should decrease
-        await blockchain.indexTrim(23601)
-        const countAi = await blockchain.indexCount('iindex', { id: 'A', pos: 0 })
-        const countBi = await blockchain.indexCount('iindex', { id: 'B', pos: 0 })
-        const countCi = await blockchain.indexCount('iindex', { id: 'C', pos: 0 })
-        const countDi = await blockchain.indexCount('iindex', { id: 'D', pos: 0 })
-        const countBz = await blockchain.indexCount('zindex', { id: 'B', pos: 0 })
-        assert.equal(countAi, 2)
-        assert.equal(countBi, 1)
-        assert.equal(countCi, 1)
-        assert.equal(countDi, 1) // Not expired!
-        assert.equal(countBz, 0)
-        const reducedAi = await blockchain.indexReduce('iindex', { id: 'A', pos: 0 })
-        const reducedBi = await blockchain.indexReduce('iindex', { id: 'B', pos: 0 })
-        const reducedCi = await blockchain.indexReduce('iindex', { id: 'C', pos: 0 })
-        const reducedDi = await blockchain.indexReduce('iindex', { id: 'D', pos: 0 })
-        const reducedBz = await blockchain.indexReduce('zindex', { id: 'B', pos: 0 })
-        assert.deepEqual(reducedAi, { id: 'A', pos: 0, status: 'OK', writtenOn: 23601, events: 5, member: true })
-        assert.deepEqual(reducedBi, { id: 'B', pos: 0, status: 'KO', writtenOn: 23000, events: 1, member: false })
-        assert.deepEqual(reducedCi, { id: 'C', pos: 0, status: 'KO', writtenOn: 23500 })
-        assert.deepEqual(reducedDi, { id: 'D', pos: 0, status: 'KO', writtenOn: 23500 })
-        assert.deepEqual(reducedBz, {})
-      })
-    })
-  })
-
-  describe('SqlIndex', () => {
-
-    let blockchain:any
-
-    describe('PK on one field', () => {
-
-      before(() => {
-        const db = new SQLiteDriver(':memory:')
-        blockchain = new IndexedBlockchain(new ArrayBlockchain(), new SQLIndex(db, {
-          iindex: {
-            sqlFields: [
-              'name CHAR(1) NULL',
-              'status CHAR(2) NULL',
-              'writtenOn INTEGER NULL',
-              'events INTEGER NULL',
-              'member INTEGER NULL',
-              'expired INTEGER NULL'
-            ],
-            fields: [
-              'name',
-              'status',
-              'writtenOn',
-              'events',
-              'member',
-              'expired'
-            ],
-            booleans: ['member', 'expired']
-          },
-          zindex: {
-            sqlFields: [
-              'name CHAR(1) NULL',
-              'status CHAR(2) NULL',
-              'writtenOn INTEGER NULL',
-              'events INTEGER NULL',
-              'member INTEGER NULL',
-              'expired INTEGER NULL'
-            ],
-            fields: [
-              'name',
-              'status',
-              'writtenOn',
-              'events',
-              'member',
-              'expired'
-            ],
-            booleans: ['member', 'expired']
-          }
-        }), 'writtenOn', {
-          iindex: {
-            pk: 'name',
-            remove: 'expired'
-          },
-          zindex: {
-            pk: 'name'
-          }
-        })
-      })
-
-      it('should be able to index data', async () => {
-        await blockchain.recordIndex({
-          iindex: [
-            { name: 'A', status: 'OK', writtenOn: 23000, events: 0, member: false },
-            { name: 'A', status: 'OK', writtenOn: 23000, events: 4 },
-            { name: 'A', status: 'OK', writtenOn: 23000, events: 5, member: true },
-            { name: 'A', status: 'OK', writtenOn: 23601 },
-            { name: 'A', status: 'OK', writtenOn: 23888 },
-            { name: 'A', status: 'OK', writtenOn: 23889 },
-            { name: 'B', status: 'OK', writtenOn: 23000, events: 1, member: false },
-            { name: 'B', status: 'KO', writtenOn: 23000, events: null },
-            { name: 'C', status: 'KO', writtenOn: 23500 },
-            { name: 'D', status: 'KO', writtenOn: 23500 },
-            { name: 'D', status: 'KO', writtenOn: 23521, expired: true }
-          ]
-        })
-      })
-
-      it('should be able to reduce data', async () => {
-        const reducedA = await blockchain.indexReduce('iindex', { name: 'A' })
-        const reducedB = await blockchain.indexReduce('iindex', { name: 'B' })
-        assert.deepEqual(reducedA, { name: 'A', status: 'OK', writtenOn: 23889, events: 5, member: true })
-        assert.deepEqual(reducedB, { name: 'B', status: 'KO', writtenOn: 23000, events: 1, member: false })
-      })
-
-      it('should be able to count data', async () => {
-        const countAi = await blockchain.indexCount('iindex', { name: 'A' })
-        const countBi = await blockchain.indexCount('iindex', { name: 'B' })
-        const countCi = await blockchain.indexCount('iindex', { name: 'C' })
-        const countDi = await blockchain.indexCount('iindex', { name: 'D' })
-        const countBz = await blockchain.indexCount('zindex', { name: 'B' })
-        assert.equal(countAi, 6)
-        assert.equal(countBi, 2)
-        assert.equal(countCi, 1)
-        assert.equal(countDi, 2)
-        assert.equal(countBz, 0)
-      })
-
-      it('should be able to reduce grouped data', async () => {
-        const reducedBy = await blockchain.indexReduceGroupBy('iindex', { writtenOn: 23000 }, ['name'])
-        assert.deepEqual(reducedBy, [
-          { name: 'A', status: 'OK', writtenOn: 23000, events: 5, member: true },
-          { name: 'B', status: 'KO', writtenOn: 23000, events: 1, member: false }
-        ])
-      })
-
-      it('should be able to trim data', async () => {
-        // The number of records should decrease
-        await blockchain.indexTrim(23601)
-        const countAi = await blockchain.indexCount('iindex', { name: 'A' })
-        const countBi = await blockchain.indexCount('iindex', { name: 'B' })
-        const countCi = await blockchain.indexCount('iindex', { name: 'C' })
-        const countDi = await blockchain.indexCount('iindex', { name: 'D' })
-        const countBz = await blockchain.indexCount('zindex', { name: 'B' })
-        assert.equal(countAi, 4)
-        assert.equal(countBi, 1)
-        assert.equal(countCi, 1)
-        assert.equal(countDi, 0) // Expired = remove rows on trim
-        assert.equal(countBz, 0)
-        const reducedAi = await blockchain.indexReduce('iindex', { name: 'A' })
-        const reducedBi = await blockchain.indexReduce('iindex', { name: 'B' })
-        const reducedCi = await blockchain.indexReduce('iindex', { name: 'C' })
-        const reducedDi = await blockchain.indexReduce('iindex', { name: 'D' })
-        const reducedBz = await blockchain.indexReduce('zindex', { name: 'B' })
-        assert.deepEqual(reducedAi, { name: 'A', status: 'OK', writtenOn: 23889, events: 5, member: true })
-        assert.deepEqual(reducedBi, { name: 'B', status: 'KO', writtenOn: 23000, events: 1, member: false })
-        assert.deepEqual(reducedCi, { name: 'C', status: 'KO', writtenOn: 23500 })
-        assert.deepEqual(reducedDi, {})
-        assert.deepEqual(reducedBz, {})
-      })
-    })
-
-    describe('PK on two fields', () => {
-
-      before(() => {
-        const db = new SQLiteDriver(':memory:')
-        blockchain = new IndexedBlockchain(new ArrayBlockchain(), new SQLIndex(db, {
-          iindex: {
-            sqlFields: [
-              'id INTEGER NULL',
-              'pos INTEGER NULL',
-              'name CHAR(1) NULL',
-              'status CHAR(2) NULL',
-              'writtenOn INTEGER NULL',
-              'events INTEGER NULL',
-              'member INTEGER NULL',
-              'expired INTEGER NULL'
-            ],
-            fields: [
-              'id',
-              'pos',
-              'name',
-              'status',
-              'writtenOn',
-              'events',
-              'member',
-              'expired'
-            ],
-            booleans: ['member', 'expired']
-          },
-          zindex: {
-            sqlFields: [
-              'id INTEGER NULL',
-              'pos INTEGER NULL',
-              'name CHAR(1) NULL',
-              'status CHAR(2) NULL',
-              'writtenOn INTEGER NULL',
-              'events INTEGER NULL',
-              'member INTEGER NULL',
-              'expired INTEGER NULL'
-            ],
-            fields: [
-              'id',
-              'pos',
-              'name',
-              'status',
-              'writtenOn',
-              'events',
-              'member',
-              'expired'
-            ],
-            booleans: ['member', 'expired']
-          }
-        }), 'writtenOn', {
-          iindex: {
-            pk: ['id', 'pos'],
-            remove: 'expired'
-          },
-          zindex: {
-            pk: 'name'
-          }
-        })
-      })
-
-      it('should be able to index data', async () => {
-        await blockchain.recordIndex({
-          iindex: [
-            { id: 'A', pos: 0, status: 'OK', writtenOn: 23000, events: 0, member: false },
-            { id: 'A', pos: 0, status: 'OK', writtenOn: 23000, events: 4 },
-            { id: 'A', pos: 0, status: 'OK', writtenOn: 23000, events: 5, member: true },
-            { id: 'A', pos: 0, status: 'OK', writtenOn: 23601 },
-            { id: 'A', pos: 1, status: 'OK', writtenOn: 23888 },
-            { id: 'A', pos: 2, status: 'OK', writtenOn: 23889 },
-            { id: 'B', pos: 0, status: 'OK', writtenOn: 23000, events: 1, member: false },
-            { id: 'B', pos: 0, status: 'KO', writtenOn: 23000, events: null },
-            { id: 'C', pos: 0, status: 'KO', writtenOn: 23500 },
-            { id: 'D', pos: 0, status: 'KO', writtenOn: 23500 },
-            { id: 'D', pos: 1, status: 'KO', writtenOn: 23521, expired: true }
-          ]
-        })
-      })
-
-      it('should be able to reduce data', async () => {
-        const reducedA = await blockchain.indexReduce('iindex', { id: 'A', pos: 0 })
-        const reducedB = await blockchain.indexReduce('iindex', { id: 'B', pos: 0 })
-        assert.deepEqual(reducedA, { id: 'A', pos: 0, status: 'OK', writtenOn: 23601, events: 5, member: true })
-        assert.deepEqual(reducedB, { id: 'B', pos: 0, status: 'KO', writtenOn: 23000, events: 1, member: false })
-      })
-
-      it('should be able to count data', async () => {
-        const countAi = await blockchain.indexCount('iindex', { id: 'A', pos: 0 })
-        const countBi = await blockchain.indexCount('iindex', { id: 'B', pos: 0 })
-        const countCi = await blockchain.indexCount('iindex', { id: 'C', pos: 0 })
-        const countDi = await blockchain.indexCount('iindex', { id: 'D', pos: 0 })
-        const countBz = await blockchain.indexCount('zindex', { id: 'B', pos: 0 })
-        assert.equal(countAi, 4)
-        assert.equal(countBi, 2)
-        assert.equal(countCi, 1)
-        assert.equal(countDi, 1)
-        assert.equal(countBz, 0)
-      })
-
-      it('should be able to reduce grouped data', async () => {
-        const reducedBy = await blockchain.indexReduceGroupBy('iindex', { writtenOn: 23000 }, ['id', 'pos'])
-        assert.deepEqual(reducedBy, [
-          { id: 'A', pos: 0, status: 'OK', writtenOn: 23000, events: 5, member: true },
-          { id: 'B', pos: 0, status: 'KO', writtenOn: 23000, events: 1, member: false }
-        ])
-      })
-
-      it('should be able to trim data', async () => {
-        // The number of records should decrease
-        await blockchain.indexTrim(23601)
-        const countAi = await blockchain.indexCount('iindex', { id: 'A', pos: 0 })
-        const countBi = await blockchain.indexCount('iindex', { id: 'B', pos: 0 })
-        const countCi = await blockchain.indexCount('iindex', { id: 'C', pos: 0 })
-        const countDi = await blockchain.indexCount('iindex', { id: 'D', pos: 0 })
-        const countBz = await blockchain.indexCount('zindex', { id: 'B', pos: 0 })
-        assert.equal(countAi, 2)
-        assert.equal(countBi, 1)
-        assert.equal(countCi, 1)
-        assert.equal(countDi, 1) // Not expired!
-        assert.equal(countBz, 0)
-        const reducedAi = await blockchain.indexReduce('iindex', { id: 'A', pos: 0 })
-        const reducedBi = await blockchain.indexReduce('iindex', { id: 'B', pos: 0 })
-        const reducedCi = await blockchain.indexReduce('iindex', { id: 'C', pos: 0 })
-        const reducedDi = await blockchain.indexReduce('iindex', { id: 'D', pos: 0 })
-        const reducedBz = await blockchain.indexReduce('zindex', { id: 'B', pos: 0 })
-        assert.deepEqual(reducedAi, { id: 'A', pos: 0, status: 'OK', writtenOn: 23601, events: 5, member: true })
-        assert.deepEqual(reducedBi, { id: 'B', pos: 0, status: 'KO', writtenOn: 23000, events: 1, member: false })
-        assert.deepEqual(reducedCi, { id: 'C', pos: 0, status: 'KO', writtenOn: 23500 })
-        assert.deepEqual(reducedDi, { id: 'D', pos: 0, status: 'KO', writtenOn: 23500 })
-        assert.deepEqual(reducedBz, {})
-      })
-    })
-  })
-
-})
diff --git a/test/blockchain/lib/ArrayBlockchain.ts b/test/blockchain/lib/ArrayBlockchain.ts
deleted file mode 100644
index 25c0fc576e48d3ee7c7e8dde2d64e6bcf895defd..0000000000000000000000000000000000000000
--- a/test/blockchain/lib/ArrayBlockchain.ts
+++ /dev/null
@@ -1,48 +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 {BlockchainOperator} from "../../../app/lib/blockchain/interfaces/BlockchainOperator"
-
-export class ArrayBlockchain implements BlockchainOperator {
-
-  // The blockchain storage
-  private bcArray: any[] = []
-
-  store(b:any): Promise<any> {
-    this.bcArray.push(b)
-    return Promise.resolve(b)
-  }
-
-  read(i: number): Promise<any> {
-    return Promise.resolve(this.bcArray[i])
-  }
-
-  head(n: number): Promise<any> {
-    const index = Math.max(0, this.bcArray.length - 1 - (n || 0))
-    return Promise.resolve(this.bcArray[index])
-  }
-
-  height(): Promise<number> {
-    return Promise.resolve(this.bcArray.length)
-  }
-
-  headRange(m: number): Promise<any[]> {
-    const index = Math.max(0, this.bcArray.length - (m || 0))
-    return Promise.resolve(this.bcArray.slice(index, this.bcArray.length).reverse())
-  }
-
-  revertHead(): Promise<any> {
-    const reverted = this.bcArray.pop()
-    return Promise.resolve(reverted)
-  }
-}
diff --git a/test/blockchain/lib/MemoryIndex.ts b/test/blockchain/lib/MemoryIndex.ts
deleted file mode 100644
index cfd6471f43c67253554388223971f3c08d1b081f..0000000000000000000000000000000000000000
--- a/test/blockchain/lib/MemoryIndex.ts
+++ /dev/null
@@ -1,108 +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"
-import {IndexOperator} from "../../../app/lib/blockchain/interfaces/IndexOperator"
-
-const _  = require('underscore')
-
-export class MemoryIndex implements IndexOperator {
-
-  // The blockchain storage
-  private indexStorage: { [index: string]: any[] } = { }
-
-  initIndexer(pkFields: any): Promise<void> {
-    return Promise.resolve()
-  }
-
-  getSubIndexes(): Promise<string[]> {
-    return Promise.resolve(_.keys(this.indexStorage))
-  }
-
-  findTrimable(subIndex: string, numberField: string, maxNumber: number): Promise<any[]> {
-    const criterias:any = {}
-    criterias[numberField] = { $lt: maxNumber }
-    return this.findWhere(subIndex, criterias)
-  }
-
-  removeWhere(subIndex: string, criterias: {}): Promise<void> {
-    let i = 0
-    let rows = this.indexStorage[subIndex]
-    while (i < rows.length) {
-      if (MemoryIndex.matchComplexCriterias(criterias, rows[i])) {
-        rows.splice(i, 1)
-      } else {
-        i++
-      }
-    }
-    return Promise.resolve()
-  }
-
-  recordIndex(index: any): Promise<void> {
-    const subIndexes = _.keys(index)
-    // Create subIndexes if they do not exist
-    for (const subIndex of subIndexes) {
-      this.indexStorage[subIndex] = this.indexStorage[subIndex] || []
-    }
-    // Feed the subIndexes
-    for (const subIndex of subIndexes) {
-      this.indexStorage[subIndex] = this.indexStorage[subIndex].concat(index[subIndex])
-    }
-    return Promise.resolve()
-  }
-
-  private static matchComplexCriterias(criterias:any, row:any): boolean {
-    const criteriaKeys = _.keys(criterias)
-    let matches = true
-    let i = 0
-    while (matches && i < criteriaKeys.length) {
-      const k = criteriaKeys[i]
-      if (typeof criterias[k] === 'function') {
-        matches = criterias[k](row[k])
-      } else if (typeof criterias[k] === 'object') {
-        if (criterias[k].$lt) {
-          matches = row[k] < criterias[k].$lt
-        } else if (criterias[k].$gt) {
-          matches = row[k] > criterias[k].$gt
-        } else if (criterias[k].$lte) {
-          matches = row[k] <= criterias[k].$lte
-        } else if (criterias[k].$gte) {
-          matches = row[k] >= criterias[k].$gte
-        } else {
-          // Unknown predicate
-          matches = false
-        }
-      } else {
-        matches = row[k] === criterias[k]
-      }
-      i++
-    }
-    return matches
-  }
-
-  findWhere(subIndex: string, criterias: {}): Promise<any[]> {
-    let res: any[] = []
-    const areBasicCriterias = _.values(criterias).reduce((are:boolean, criteria:any) => are && typeof criteria !== 'function' && typeof criteria !== 'object', true)
-    if (areBasicCriterias) {
-      res = _.where(this.indexStorage[subIndex], criterias)
-    } else {
-      // Slower test, with specific criterias
-      for (const row of this.indexStorage[subIndex]) {
-        if (MemoryIndex.matchComplexCriterias(criterias, row)) {
-          res.push(row)
-        }
-      }
-    }
-    return Promise.resolve(res)
-  }
-}
diff --git a/test/blockchain/misc-sql-blockchain.ts b/test/blockchain/misc-sql-blockchain.ts
deleted file mode 100644
index 2caa2d975f41d39acc731161e11dcec72cdd122d..0000000000000000000000000000000000000000
--- a/test/blockchain/misc-sql-blockchain.ts
+++ /dev/null
@@ -1,233 +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";
-import {MiscIndexedBlockchain} from "../../app/lib/blockchain/MiscIndexedBlockchain"
-import {ArrayBlockchain} from "./lib/ArrayBlockchain"
-import {SQLiteDriver} from "../../app/lib/dal/drivers/SQLiteDriver"
-import {MIndexDAL} from "../../app/lib/dal/sqliteDAL/index/MIndexDAL";
-import {IIndexDAL} from "../../app/lib/dal/sqliteDAL/index/IIndexDAL";
-import {SIndexDAL} from "../../app/lib/dal/sqliteDAL/index/SIndexDAL";
-import {CIndexDAL} from "../../app/lib/dal/sqliteDAL/index/CIndexDAL";
-import {MetaDAL} from "../../app/lib/dal/sqliteDAL/MetaDAL";
-import {ConfDTO} from "../../app/lib/dto/ConfDTO";
-
-const assert = require('assert')
-
-describe('MISC SQL Blockchain', () => {
-
-  let blockchain:any
-
-  before(async () => {
-
-    const db = new SQLiteDriver(':memory:')
-
-    const mindexDAL = new MIndexDAL(db)
-    const iindexDAL = new IIndexDAL(db)
-    const sindexDAL = new SIndexDAL(db)
-    const cindexDAL = new CIndexDAL(db)
-    const metaDAL = new MetaDAL(db)
-
-    await iindexDAL.init()
-    await mindexDAL.init()
-    await sindexDAL.init()
-    await cindexDAL.init()
-    await metaDAL.init()
-    // Ghost tables required for DB upgrade
-    await metaDAL.exec('CREATE TABLE txs (id INTEGER null);')
-    await metaDAL.exec('CREATE TABLE idty (id INTEGER null);')
-    await metaDAL.exec('CREATE TABLE cert (id INTEGER null);')
-    await metaDAL.exec('CREATE TABLE membership (id INTEGER null);')
-    await metaDAL.exec('CREATE TABLE block (fork INTEGER null);')
-    await metaDAL.exec('CREATE TABLE b_index (id INTEGER null);')
-    await metaDAL.upgradeDatabase(ConfDTO.mock());
-
-    blockchain = new MiscIndexedBlockchain(new ArrayBlockchain(), mindexDAL, iindexDAL, sindexDAL, cindexDAL)
-  })
-
-  describe('MINDEX', () => {
-
-    it('should be able to index data', async () => {
-      await blockchain.recordIndex({
-        m_index: [
-          { op: 'CREATE', pub: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', created_on: '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855', written_on: '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855', writtenOn: 0, expires_on: 1520544727, expired_on: null, revokes_on: 1552102327, revoked_on: null, leaving: false, revocation: null, chainable_on: null },
-          { op: 'UPDATE', pub: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', created_on: '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855', written_on: '3-0000611A1018A322624853A8AE10D0EBFF3C6AEE37BF4DE5354C720049C22BD1', writtenOn: 3, expires_on: 1520544728, expired_on: null, revokes_on: 1520544728, revoked_on: null, leaving: false, revocation: null, chainable_on: null },
-          { op: 'UPDATE', pub: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', created_on: '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855', written_on: '4-0000090B7059E7BF5DD2CCA5E4F0330C1DA42C5DCBD2D1364B99B3FF89DE6744', writtenOn: 4, expires_on: 1520544729, expired_on: null, revokes_on: 1520544729, revoked_on: null, leaving: false, revocation: null, chainable_on: null }
-        ]
-      })
-    })
-
-    it('should be able to reduce data', async () => {
-      const reducedG5 = await blockchain.indexReduce('m_index', { pub: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT' })
-      assert.deepEqual(reducedG5, { op: 'UPDATE', pub: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', created_on: '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855', written_on: '4-0000090B7059E7BF5DD2CCA5E4F0330C1DA42C5DCBD2D1364B99B3FF89DE6744', writtenOn: 4, expires_on: 1520544729, revokes_on: 1520544729, leaving: false })
-    })
-
-    it('should be able to count data', async () => {
-      const countG5 = await blockchain.indexCount('m_index', { pub: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT' })
-      assert.equal(countG5, 3)
-    })
-
-    it('should be able to reduce grouped data', async () => {
-      const reducedBy = await blockchain.indexReduceGroupBy('m_index', { created_on: '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855' }, ['op', 'pub'])
-      assert.deepEqual(reducedBy, [
-        { op: 'CREATE', pub: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', created_on: '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855', written_on: '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855', writtenOn: 0, expires_on: 1520544727, revokes_on: 1552102327, leaving: false },
-        { op: 'UPDATE', pub: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', created_on: '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855', written_on: '4-0000090B7059E7BF5DD2CCA5E4F0330C1DA42C5DCBD2D1364B99B3FF89DE6744', writtenOn: 4, expires_on: 1520544729, revokes_on: 1520544729, leaving: false }
-      ])
-    })
-
-    it('should be able to trim data', async () => {
-      // The number of records should decrease
-      await blockchain.indexTrim(4)
-      const countG5 = await blockchain.indexCount('m_index', { pub: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT' })
-      assert.equal(countG5, 2)
-      const reducedG5 = await blockchain.indexReduce('m_index', { pub: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT' })
-      assert.deepEqual(reducedG5, { op: 'UPDATE', pub: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', created_on: '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855', written_on: '4-0000090B7059E7BF5DD2CCA5E4F0330C1DA42C5DCBD2D1364B99B3FF89DE6744', writtenOn: 4, expires_on: 1520544729, revokes_on: 1520544729, leaving: false })
-    })
-  })
-
-  describe('IINDEX', () => {
-
-    it('should be able to index data', async () => {
-      await blockchain.recordIndex({
-        i_index: [
-          { op: 'CREATE', uid: 'pseudo', pub: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', hash: '1505A45A5EEBFC3AFAD1475A4739C8447A79420A83340559CE5A49F9891167BB', sig: '2vfmih7xhW/QLJ85PZH1Tc6j5fooIXca+yr/esnt0yvdk5LhEKrOB32JFqCctAoRNwpRjBdZ2Q8l15+In1rrDg==', created_on: '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855', written_on: '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855',     writtenOn: 0,     member: true,  wasMember: true, kick: false, wotb_id: 164 },
-          { op: 'UPDATE', uid: 'pseudo', pub: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', hash: '1505A45A5EEBFC3AFAD1475A4739C8447A79420A83340559CE5A49F9891167BB', sig: '2vfmih7xhW/QLJ85PZH1Tc6j5fooIXca+yr/esnt0yvdk5LhEKrOB32JFqCctAoRNwpRjBdZ2Q8l15+In1rrDg==', created_on: '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855', written_on: '33396-000009C936CD6F7C5672C1E6D36159E0BEA2B394F386CA0EBA7E73662A09BB43', writtenOn: 33396, member: false, wasMember: true, kick: false, wotb_id: 164 },
-          { op: 'UPDATE', uid: 'pseudo', pub: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', hash: '1505A45A5EEBFC3AFAD1475A4739C8447A79420A83340559CE5A49F9891167BB', sig: '2vfmih7xhW/QLJ85PZH1Tc6j5fooIXca+yr/esnt0yvdk5LhEKrOB32JFqCctAoRNwpRjBdZ2Q8l15+In1rrDg==', created_on: '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855', written_on: '40000-000006C311D2677D101116287718395A2CBB7B94389004D19B0E4AC6DCE2DE5F', writtenOn: 40000, member: true,  wasMember: true, kick: false, wotb_id: 164 }
-        ]
-      })
-    })
-
-    it('should be able to reduce data', async () => {
-      const reducedG5 = await blockchain.indexReduce('i_index', { pub: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT' })
-      assert.deepEqual(reducedG5, { op: 'UPDATE', uid: 'pseudo', pub: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', hash: '1505A45A5EEBFC3AFAD1475A4739C8447A79420A83340559CE5A49F9891167BB', sig: '2vfmih7xhW/QLJ85PZH1Tc6j5fooIXca+yr/esnt0yvdk5LhEKrOB32JFqCctAoRNwpRjBdZ2Q8l15+In1rrDg==', created_on: '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855', written_on: '40000-000006C311D2677D101116287718395A2CBB7B94389004D19B0E4AC6DCE2DE5F', writtenOn: 40000, member: true,  wasMember: true, kick: false, wotb_id: 164 })
-    })
-
-    it('should be able to count data', async () => {
-      const countG5 = await blockchain.indexCount('i_index', { pub: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT' })
-      assert.equal(countG5, 3)
-    })
-
-    it('should be able to reduce grouped data', async () => {
-      const reducedBy = await blockchain.indexReduceGroupBy('i_index', { created_on: '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855' }, ['op', 'pub'])
-      assert.deepEqual(reducedBy, [
-        { op: 'CREATE', uid: 'pseudo', pub: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', hash: '1505A45A5EEBFC3AFAD1475A4739C8447A79420A83340559CE5A49F9891167BB', sig: '2vfmih7xhW/QLJ85PZH1Tc6j5fooIXca+yr/esnt0yvdk5LhEKrOB32JFqCctAoRNwpRjBdZ2Q8l15+In1rrDg==', created_on: '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855', written_on: '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855',     writtenOn: 0,     member: true,  wasMember: true, kick: false, wotb_id: 164 },
-        { op: 'UPDATE', uid: 'pseudo', pub: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', hash: '1505A45A5EEBFC3AFAD1475A4739C8447A79420A83340559CE5A49F9891167BB', sig: '2vfmih7xhW/QLJ85PZH1Tc6j5fooIXca+yr/esnt0yvdk5LhEKrOB32JFqCctAoRNwpRjBdZ2Q8l15+In1rrDg==', created_on: '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855', written_on: '40000-000006C311D2677D101116287718395A2CBB7B94389004D19B0E4AC6DCE2DE5F', writtenOn: 40000, member: true,  wasMember: true, kick: false, wotb_id: 164 }
-      ])
-    })
-
-    it('should be able to trim data', async () => {
-      // The number of records should decrease
-      await blockchain.indexTrim(40000)
-      const countG5 = await blockchain.indexCount('i_index', { pub: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT' })
-      assert.equal(countG5, 2)
-      const reducedG5 = await blockchain.indexReduce('i_index', { pub: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT' })
-      assert.deepEqual(reducedG5, { op: 'UPDATE', uid: 'pseudo', pub: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', hash: '1505A45A5EEBFC3AFAD1475A4739C8447A79420A83340559CE5A49F9891167BB', sig: '2vfmih7xhW/QLJ85PZH1Tc6j5fooIXca+yr/esnt0yvdk5LhEKrOB32JFqCctAoRNwpRjBdZ2Q8l15+In1rrDg==', created_on: '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855', written_on: '40000-000006C311D2677D101116287718395A2CBB7B94389004D19B0E4AC6DCE2DE5F', writtenOn: 40000, member: true,  wasMember: true, kick: false, wotb_id: 164 })
-    })
-  })
-
-  describe('SINDEX', () => {
-
-    it('should be able to index data', async () => {
-      await blockchain.recordIndex({
-        s_index: [
-          // Dividend
-          { op: 'CREATE', tx: null, identifier: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', pos: 35820, created_on: null, written_on: '35820-00000B363BC8F761EB5343660592D50B872FE1140B350C9780EF5BC6F9DD000B', writtenOn: 35820, written_time: 1500000000, amount: 500, base: 0, locktime: 0, consumed: false, conditions: 'SIG(CPEaW4BGNaBdx6FbAxjNQ9Po2apnX2bDvBXJT9yaZUMc)' },
-          { op: 'UPDATE', tx: null, identifier: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', pos: 35820, created_on: null, written_on: '35821-0000053C7B54AEFAEC4FCFB2763202ECD8382A635340BD622EDBC0CCC553F763', writtenOn: 35821, written_time: 1500000001, amount: 500, base: 0, locktime: 0, consumed: true,  conditions: 'SIG(CPEaW4BGNaBdx6FbAxjNQ9Po2apnX2bDvBXJT9yaZUMc)' },
-          // Transaction
-          { op: 'CREATE', tx: 'D01432C6D7D078CB566C08886FD92CA5D158433D7A8D971124973625BFAB78D9', identifier: 'D01432C6D7D078CB566C08886FD92CA5D158433D7A8D971124973625BFAB78D9', pos: 1, created_on: '33958-0000009CEC38916882EF46C40069EF227F1D7CB4B34EAD5298D84B6658FBB9FB', written_on: '30196-00000A8ABF13284452CD56C9DEC68124D4A31CE1BDD06819EB22E070EBDE1D2D', writtenOn: 30196, written_time: 1499000000, amount: 301, base: 0, locktime: 0, consumed: false, conditions: 'SIG(CPEaW4BGNaBdx6FbAxjNQ9Po2apnX2bDvBXJT9yaZUMc)' },
-          { op: 'UPDATE', tx: '3926D234037264654D9C4A2D44CDDC18998DC48262F3677F23DA5BA81BD530EA', identifier: 'D01432C6D7D078CB566C08886FD92CA5D158433D7A8D971124973625BFAB78D9', pos: 1, created_on: '33958-0000009CEC38916882EF46C40069EF227F1D7CB4B34EAD5298D84B6658FBB9FB', written_on: '30197-0000009CEC38916882EF46C40069EF227F1D7CB4B34EAD5298D84B6658FBB9FB', writtenOn: 30197, written_time: 1499000001, amount: 301, base: 0, locktime: 0, consumed: true,  conditions: 'SIG(CPEaW4BGNaBdx6FbAxjNQ9Po2apnX2bDvBXJT9yaZUMc)' }
-        ]
-      })
-    })
-
-    it('should be able to reduce data', async () => {
-      const reducedUD = await blockchain.indexReduce('s_index', { identifier: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', pos: 35820 })
-      const reducedTX = await blockchain.indexReduce('s_index', { identifier: 'D01432C6D7D078CB566C08886FD92CA5D158433D7A8D971124973625BFAB78D9', pos: 1 })
-      assert.deepEqual(reducedUD, { op: 'UPDATE', identifier: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', pos: 35820, written_on: '35821-0000053C7B54AEFAEC4FCFB2763202ECD8382A635340BD622EDBC0CCC553F763', writtenOn: 35821, written_time: 1500000001, amount: 500, base: 0, locktime: 0, consumed: true,  conditions: 'SIG(CPEaW4BGNaBdx6FbAxjNQ9Po2apnX2bDvBXJT9yaZUMc)' })
-      assert.deepEqual(reducedTX, { op: 'UPDATE', tx: '3926D234037264654D9C4A2D44CDDC18998DC48262F3677F23DA5BA81BD530EA', identifier: 'D01432C6D7D078CB566C08886FD92CA5D158433D7A8D971124973625BFAB78D9', pos: 1, created_on: '33958-0000009CEC38916882EF46C40069EF227F1D7CB4B34EAD5298D84B6658FBB9FB', written_on: '30197-0000009CEC38916882EF46C40069EF227F1D7CB4B34EAD5298D84B6658FBB9FB', writtenOn: 30197, written_time: 1499000001, amount: 301, base: 0, locktime: 0, consumed: true,  conditions: 'SIG(CPEaW4BGNaBdx6FbAxjNQ9Po2apnX2bDvBXJT9yaZUMc)' })
-    })
-
-    it('should be able to count data', async () => {
-      const countUD = await blockchain.indexCount('s_index', { identifier: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', pos: 35820 })
-      const countTX = await blockchain.indexCount('s_index', { identifier: 'D01432C6D7D078CB566C08886FD92CA5D158433D7A8D971124973625BFAB78D9', pos: 1 })
-      assert.equal(countUD, 2)
-      assert.equal(countTX, 2)
-    })
-
-    it('should be able to reduce grouped data', async () => {
-      const reducedBy = await blockchain.indexReduceGroupBy('s_index', { pos: { $gt: 0 } }, ['identifier', 'pos'])
-      assert.deepEqual(reducedBy, [
-        { op: 'UPDATE', tx: '3926D234037264654D9C4A2D44CDDC18998DC48262F3677F23DA5BA81BD530EA', identifier: 'D01432C6D7D078CB566C08886FD92CA5D158433D7A8D971124973625BFAB78D9', pos: 1, created_on: '33958-0000009CEC38916882EF46C40069EF227F1D7CB4B34EAD5298D84B6658FBB9FB', written_on: '30197-0000009CEC38916882EF46C40069EF227F1D7CB4B34EAD5298D84B6658FBB9FB', writtenOn: 30197, written_time: 1499000001, amount: 301, base: 0, locktime: 0, consumed: true,  conditions: 'SIG(CPEaW4BGNaBdx6FbAxjNQ9Po2apnX2bDvBXJT9yaZUMc)' },
-        { op: 'UPDATE', identifier: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', pos: 35820, written_on: '35821-0000053C7B54AEFAEC4FCFB2763202ECD8382A635340BD622EDBC0CCC553F763', writtenOn: 35821, written_time: 1500000001, amount: 500, base: 0, locktime: 0, consumed: true,  conditions: 'SIG(CPEaW4BGNaBdx6FbAxjNQ9Po2apnX2bDvBXJT9yaZUMc)' }
-      ])
-    })
-
-    it('should be able to trim data', async () => {
-      // The number of records should decrease
-      await blockchain.indexTrim(35000)
-      const countUD = await blockchain.indexCount('s_index', { identifier: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', pos: 35820 })
-      const countTX = await blockchain.indexCount('s_index', { identifier: 'D01432C6D7D078CB566C08886FD92CA5D158433D7A8D971124973625BFAB78D9', pos: 1 })
-      assert.equal(countUD, 2)
-      assert.equal(countTX, 0) // This index removes the lines marked `consumed`
-      const reducedUD = await blockchain.indexReduce('s_index', { identifier: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', pos: 35820 })
-      assert.deepEqual(reducedUD, { op: 'UPDATE', identifier: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', pos: 35820, written_on: '35821-0000053C7B54AEFAEC4FCFB2763202ECD8382A635340BD622EDBC0CCC553F763', writtenOn: 35821, written_time: 1500000001, amount: 500, base: 0, locktime: 0, consumed: true,  conditions: 'SIG(CPEaW4BGNaBdx6FbAxjNQ9Po2apnX2bDvBXJT9yaZUMc)' })
-    })
-  })
-
-  describe('CINDEX', () => {
-
-    it('should be able to index data', async () => {
-      await blockchain.recordIndex({
-        c_index: [
-          { op: 'CREATE', issuer: 'D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx', receiver: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', created_on: 0,  written_on: '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855',  writtenOn: 0,  sig: 'MYWlBd2Hw3T/59BDz9HZECBuZ984C23F5lqUGluIUXsvXjsY4xKNqcN2x75s9rn++u4GEzZov6OznLZiHtbAAQ==', expires_on: 1552102327, expired_on: 0,          chainable_on: 1489419127 },
-          { op: 'UPDATE', issuer: 'D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx', receiver: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', created_on: 0,  written_on: '9-0000092C94D0257C61A2504092440600487B2C8BEE73F9C8763C9F351543887D',  writtenOn: 9,  sig: 'MYWlBd2Hw3T/59BDz9HZECBuZ984C23F5lqUGluIUXsvXjsY4xKNqcN2x75s9rn++u4GEzZov6OznLZiHtbAAQ==', expires_on: 1552102327, expired_on: 1552102400, chainable_on: 1489419127 },
-          { op: 'CREATE', issuer: 'EV4yZXAgmDd9rMsRCSH2MK7RHWty7CDB9tmHku3iRnEB', receiver: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', created_on: 11, written_on: '11-000019EC1161FC9FB1848A58A3137B9CD9A919E86B2394B9682BBC3FADB1AF1F', writtenOn: 11, sig: 'plFuA1vgXJh0CQ9MVCmOgfTfFb5u3qICMfgxVJEsyco+lmZTxaKuruSsRdhw3YZgJgfU6YwC+ta/RcgLF6DvDA==', expires_on: 1556866334, expired_on: 0,          chainable_on: 1494184082}
-        ]
-      })
-    })
-
-    it('should be able to reduce data', async () => {
-      const reducedC1 = await blockchain.indexReduce('c_index', { issuer: 'D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx', receiver: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', created_on: 0 })
-      const reducedC2 = await blockchain.indexReduce('c_index', { issuer: 'EV4yZXAgmDd9rMsRCSH2MK7RHWty7CDB9tmHku3iRnEB', receiver: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', created_on: 11 })
-      assert.deepEqual(reducedC1, { op: 'UPDATE', issuer: 'D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx', receiver: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', created_on: 0,  written_on: '9-0000092C94D0257C61A2504092440600487B2C8BEE73F9C8763C9F351543887D',  writtenOn: 9,  sig: 'MYWlBd2Hw3T/59BDz9HZECBuZ984C23F5lqUGluIUXsvXjsY4xKNqcN2x75s9rn++u4GEzZov6OznLZiHtbAAQ==', expires_on: 1552102327, expired_on: 1552102400, chainable_on: 1489419127 })
-      assert.deepEqual(reducedC2, { op: 'CREATE', issuer: 'EV4yZXAgmDd9rMsRCSH2MK7RHWty7CDB9tmHku3iRnEB', receiver: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', created_on: 11, written_on: '11-000019EC1161FC9FB1848A58A3137B9CD9A919E86B2394B9682BBC3FADB1AF1F', writtenOn: 11, sig: 'plFuA1vgXJh0CQ9MVCmOgfTfFb5u3qICMfgxVJEsyco+lmZTxaKuruSsRdhw3YZgJgfU6YwC+ta/RcgLF6DvDA==', expires_on: 1556866334, expired_on: 0,          chainable_on: 1494184082})
-    })
-
-    it('should be able to count data', async () => {
-      const countC1 = await blockchain.indexCount('c_index', { issuer: 'D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx', receiver: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', created_on: 0 })
-      const countC2 = await blockchain.indexCount('c_index', { issuer: 'EV4yZXAgmDd9rMsRCSH2MK7RHWty7CDB9tmHku3iRnEB', receiver: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', created_on: 11 })
-      assert.equal(countC1, 2)
-      assert.equal(countC2, 1)
-    })
-
-    it('should be able to reduce grouped data', async () => {
-      const reducedBy = await blockchain.indexReduceGroupBy('c_index', { created_on: { $gte: 0 } }, ['issuer', 'receiver', 'created_on'])
-      assert.deepEqual(reducedBy, [
-        { op: 'UPDATE', issuer: 'D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx', receiver: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', created_on: 0,  written_on: '9-0000092C94D0257C61A2504092440600487B2C8BEE73F9C8763C9F351543887D',  writtenOn: 9,  sig: 'MYWlBd2Hw3T/59BDz9HZECBuZ984C23F5lqUGluIUXsvXjsY4xKNqcN2x75s9rn++u4GEzZov6OznLZiHtbAAQ==', expires_on: 1552102327, expired_on: 1552102400, chainable_on: 1489419127 },
-        { op: 'CREATE', issuer: 'EV4yZXAgmDd9rMsRCSH2MK7RHWty7CDB9tmHku3iRnEB', receiver: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', created_on: 11, written_on: '11-000019EC1161FC9FB1848A58A3137B9CD9A919E86B2394B9682BBC3FADB1AF1F', writtenOn: 11, sig: 'plFuA1vgXJh0CQ9MVCmOgfTfFb5u3qICMfgxVJEsyco+lmZTxaKuruSsRdhw3YZgJgfU6YwC+ta/RcgLF6DvDA==', expires_on: 1556866334, expired_on: 0,          chainable_on: 1494184082}
-      ])
-    })
-
-    it('should be able to trim data', async () => {
-      // The number of records should decrease
-      await blockchain.indexTrim(10)
-      const countC1 = await blockchain.indexCount('c_index', { issuer: 'D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx', receiver: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', created_on: 0 })
-      const countC2 = await blockchain.indexCount('c_index', { issuer: 'EV4yZXAgmDd9rMsRCSH2MK7RHWty7CDB9tmHku3iRnEB', receiver: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', created_on: 11 })
-      assert.equal(countC1, 0) // This index removes the lines marked `expired_on`
-      assert.equal(countC2, 1)
-      const reducedC2 = await blockchain.indexReduce('c_index', { issuer: 'EV4yZXAgmDd9rMsRCSH2MK7RHWty7CDB9tmHku3iRnEB', receiver: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', created_on: 11 })
-      assert.deepEqual(reducedC2, { op: 'CREATE', issuer: 'EV4yZXAgmDd9rMsRCSH2MK7RHWty7CDB9tmHku3iRnEB', receiver: 'G5P7k5t764ybGfFGLnEAwwMDz6y2U4afagAmyJXgKFyT', created_on: 11, written_on: '11-000019EC1161FC9FB1848A58A3137B9CD9A919E86B2394B9682BBC3FADB1AF1F', writtenOn: 11, sig: 'plFuA1vgXJh0CQ9MVCmOgfTfFb5u3qICMfgxVJEsyco+lmZTxaKuruSsRdhw3YZgJgfU6YwC+ta/RcgLF6DvDA==', expires_on: 1556866334, expired_on: 0,          chainable_on: 1494184082})
-    })
-  })
-
-})
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 44940fa4ca241274bf624a940c2d3db02ba7687e..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');
 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.getBlock(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/dal/blockchain-archive.ts b/test/dal/blockchain-archive.ts
new file mode 100644
index 0000000000000000000000000000000000000000..54d06feb3f04c2869e6a6e5bd8e2c3c158a4cf9c
--- /dev/null
+++ b/test/dal/blockchain-archive.ts
@@ -0,0 +1,88 @@
+// 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 {getNanosecondsTime} from "../../app/ProcessCpuProfiler"
+import * as os from "os"
+import * as path from "path"
+import * as assert from "assert"
+import {BlockchainArchiveDAO, BlockLike} from "../../app/lib/dal/indexDAL/abstract/BlockchainArchiveDAO"
+import {CFSBlockchainArchive} from "../../app/lib/dal/indexDAL/CFSBlockchainArchive"
+import {CFSCore} from "../../app/lib/dal/fileDALs/CFSCore"
+import {RealFS} from "../../app/lib/system/directory"
+
+describe("Blockchain Archive data layer", () => {
+
+  let archives:BlockchainArchiveDAO<BlockLike>
+  let dbPath = path.join(os.tmpdir(), 'duniter' + getNanosecondsTime())
+
+  before(async () => {
+    archives = new CFSBlockchainArchive(new CFSCore(dbPath, RealFS()), 2)
+    archives.triggerInit()
+    await archives.init()
+  })
+
+  it('should be able to read last saved block when archives are empty', async () => {
+    assert.equal(null, await archives.getLastSavedBlock())
+  })
+
+  it('should be able to archive 4 blocks', async () => {
+    const chunksCreated = await archives.archive([
+      { number: 0, hash: 'H0', previousHash: '' },
+      { number: 1, hash: 'H1', previousHash: 'H0' },
+      { number: 2, hash: 'H2', previousHash: 'H1' },
+      { number: 3, hash: 'H3', previousHash: 'H2' },
+      { number: 4, hash: 'H4', previousHash: 'H3' },
+      { number: 5, hash: 'H5', previousHash: 'H4' },
+    ])
+    assert.equal(chunksCreated, 3)
+  })
+
+  it('should be able to read archived blocks', async () => {
+    assert.notEqual(null, await archives.getBlock(0, 'H0'))
+    assert.notEqual(null, await archives.getBlock(1, 'H1'))
+    assert.notEqual(null, await archives.getBlock(2, 'H2'))
+    assert.notEqual(null, await archives.getBlock(3, 'H3'))
+    assert.notEqual(null, await archives.getBlock(4, 'H4'))
+    assert.notEqual(null, await archives.getBlock(5, 'H5'))
+  })
+
+  it('should be able to read last saved block when archives are full', async () => {
+    assert.notEqual(null, await archives.getLastSavedBlock())
+    assert.equal(5, ((await archives.getLastSavedBlock()) as BlockLike).number)
+  })
+
+  it('should not be able to read non-archived blocks', async () => {
+    assert.equal(null, await archives.getBlock(0, 'H5'))
+    assert.equal(null, await archives.getBlock(8, 'H8'))
+  })
+
+  it('should refuse to store unchained blocks', async () => {
+    const chunksCreated1 = await archives.archive([
+      { number: 6, hash: 'H6', previousHash: 'H5' },
+      { number: 7, hash: 'H7', previousHash: 'H61' },
+    ])
+    assert.equal(chunksCreated1, 0)
+    const chunksCreated2 = await archives.archive([
+      { number: 6, hash: 'H6', previousHash: 'H5' },
+      { number: 8, hash: 'H7', previousHash: 'H6' },
+    ])
+    assert.equal(chunksCreated2, 0)
+  })
+
+  it('should refuse to store blocks that are not chunks', async () => {
+    const chunksCreated = await archives.archive([
+      { number: 6, hash: 'H6', previousHash: 'H5' },
+    ])
+    assert.equal(chunksCreated, 0)
+  })
+})
diff --git a/test/dal/file-dal.ts b/test/dal/file-dal.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1f243579235f86f85eaffa77f847fc1232d2cb62
--- /dev/null
+++ b/test/dal/file-dal.ts
@@ -0,0 +1,88 @@
+// 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 {assertEqual, assertFalse, assertTrue, writeBasicTestWith2Users} from "../integration/tools/test-framework"
+import {TestingServer} from "../integration/tools/toolbox"
+import {CommonConstants} from "../../app/lib/common-libs/constants"
+
+describe('File Data Access Layer', () => writeBasicTestWith2Users((test) => {
+
+  let initialValue = CommonConstants.BLOCKS_COLLECT_THRESHOLD
+
+  before(() => {
+    // Let's trim loki data every 3 blocks
+    CommonConstants.BLOCKS_COLLECT_THRESHOLD = 3
+  })
+
+  after(() => {
+    // Revert
+    CommonConstants.BLOCKS_COLLECT_THRESHOLD = initialValue
+  })
+
+  test('if we disable the changes API', async (s1: TestingServer) => {
+    s1.dal.disableChangesAPI()
+    assertTrue(s1.dal.iindexDAL.lokiCollection.disableChangesApi)
+    assertTrue(s1.dal.iindexDAL.lokiCollection.disableDeltaChangesApi)
+  })
+
+  test('if we enable back the changes API', async (s1: TestingServer) => {
+    s1.dal.enableChangesAPI()
+    assertFalse(s1.dal.iindexDAL.lokiCollection.disableChangesApi)
+    assertFalse(s1.dal.iindexDAL.lokiCollection.disableDeltaChangesApi)
+  })
+
+  test('we should have no changes after commit of b#0', async (s1, cat, tac) => {
+    assertEqual(s1.dal.iindexDAL.lokiCollection.collection.data.length, 0)
+    assertEqual(s1.dal.iindexDAL.lokiCollection.collection.changes.length, 0)
+    await cat.createIdentity()
+    await tac.createIdentity()
+    await cat.cert(tac)
+    await tac.cert(cat)
+    await cat.join()
+    await tac.join()
+    await s1.commit()
+    // No changes after a commit, but new data
+    assertEqual(s1.dal.iindexDAL.lokiCollection.collection.data.length, 2)
+    assertEqual(s1.dal.iindexDAL.lokiCollection.collection.changes.length, 0)
+    // Without changes files (since block#0 triggers the lokijs data commit)
+    assertEqual((await s1.dal.loki.listChangesFilesPending()).length, 0)
+  })
+
+  test('we should have changes files after commit of b#1', async (s1, cat, tac) => {
+    await tac.revoke()
+    await s1.commit()
+    // Some changes, as block#1 does not provoke a lokijs data commit
+    assertEqual(s1.dal.iindexDAL.lokiCollection.collection.data.length, 3)
+    assertEqual(s1.dal.iindexDAL.lokiCollection.collection.changes.length, 0)
+    // With changes files (since block#1 does not trigger the lokijs data commit)
+    assertEqual((await s1.dal.loki.listChangesFilesPending()).length, 1)
+  })
+
+  test('we should have one more changes files after commit of b#2', async (s1) => {
+    await s1.commit()
+    // Some changes, as block#1 does not provoke a lokijs data commit
+    assertEqual(s1.dal.iindexDAL.lokiCollection.collection.data.length, 3)
+    assertEqual(s1.dal.iindexDAL.lokiCollection.collection.changes.length, 0)
+    // With changes files (since block#1 does not trigger the lokijs data commit)
+    assertEqual((await s1.dal.loki.listChangesFilesPending()).length, 2)
+  })
+
+  test('we should have no more changes files after commit of b#3', async (s1) => {
+    await s1.commit()
+    // Some changes, as block#1 does not provoke a lokijs data commit
+    assertEqual(s1.dal.iindexDAL.lokiCollection.collection.data.length, 3)
+    assertEqual(s1.dal.iindexDAL.lokiCollection.collection.changes.length, 0)
+    // With changes files (since block#1 does not trigger the lokijs data commit)
+    assertEqual((await s1.dal.loki.listChangesFilesPending()).length, 0)
+  })
+}))
diff --git a/test/dal/loki.ts b/test/dal/loki.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ebe6b3ccca71ce2cbacb6431ae92f03bbe441386
--- /dev/null
+++ b/test/dal/loki.ts
@@ -0,0 +1,115 @@
+// 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 {LokiJsDriver} from "../../app/lib/dal/drivers/LokiJsDriver"
+import {getNanosecondsTime} from "../../app/ProcessCpuProfiler"
+import * as os from "os"
+import * as path from "path"
+import * as assert from "assert"
+import {RealFS} from "../../app/lib/system/directory"
+import {shouldThrow} from "../unit-tools"
+import {DBCommit} from "../../app/lib/dal/drivers/LokiFsAdapter"
+
+describe("Loki data layer", () => {
+
+  let driver:LokiJsDriver
+  let dbPath = path.join(os.tmpdir(), 'duniter' + getNanosecondsTime())
+
+  it('should be able to create a new instance', async () => {
+    driver = new LokiJsDriver(dbPath)
+    await driver.loadDatabase()
+  })
+
+  it('should be able to commit data', async () => {
+    const coll = driver.getLokiInstance().addCollection('block', { disableChangesApi: false })
+    coll.insert({ a: 1 })
+    coll.insert({ b: 2 })
+    await driver.flushAndTrimData()
+  })
+
+  it('should be able restart the DB and read the data', async () => {
+    const driver2 = new LokiJsDriver(dbPath)
+    await driver2.loadDatabase()
+    const coll = driver2.getLokiInstance().getCollection('block')
+    assert.notEqual(null, coll)
+    assert.equal(coll.find().length, 2)
+  })
+
+  it('should be able to add few changes data', async () => {
+    const driver2 = new LokiJsDriver(dbPath)
+    await driver2.loadDatabase()
+    const coll = driver2.getLokiInstance().getCollection('block')
+    coll.insert({ c: 3 })
+    coll.chain().find({ c: 3 }).update((o:any) => o.c = 4)
+    coll.chain().find({ a: 1 }).remove()
+    const changesCount1 = await driver2.commitData()
+    assert.equal(changesCount1, 3)
+    const changesCount2 = await driver2.commitData()
+    assert.equal(changesCount2, 0)
+  })
+
+  it('should be able restart the DB and read the commited data', async () => {
+    const driver2 = new LokiJsDriver(dbPath)
+    await driver2.loadDatabase()
+    const coll = driver2.getLokiInstance().getCollection('block')
+    assert.equal(coll.find().length, 2)
+    assert.equal(coll.find({ a: 1 }).length, 0)
+    assert.equal(coll.find({ b: 2 }).length, 1)
+    assert.equal(coll.find({ c: 4 }).length, 1)
+  })
+
+  it('should be able to trim then restart the DB and read the commited data', async () => {
+    const driverTrim = new LokiJsDriver(dbPath)
+    await driverTrim.loadDatabase()
+    await driverTrim.flushAndTrimData()
+    const driver2 = new LokiJsDriver(dbPath)
+    await driver2.loadDatabase()
+    const coll = driver2.getLokiInstance().getCollection('block')
+    assert.equal(coll.find().length, 2)
+    assert.equal(coll.find({ a: 1 }).length, 0)
+    assert.equal(coll.find({ b: 2 }).length, 1)
+    assert.equal(coll.find({ c: 4 }).length, 1)
+  })
+
+  it('should not see any data if commit file is absent', async () => {
+    const rfs = RealFS()
+    await rfs.fsUnlink(path.join(dbPath, 'commit.json'))
+    const driver3 = new LokiJsDriver(dbPath)
+    await driver3.loadDatabase()
+    const coll = driver3.getLokiInstance().getCollection('block')
+    assert.equal(null, coll)
+  })
+
+  it('should throw if commit file contains unknown index file', async () => {
+    const rfs = RealFS()
+    await rfs.fsWrite(path.join(dbPath, 'commit.json'), JSON.stringify({
+      indexFile: 'non-existing.index.json'
+    }))
+    const driver4 = new LokiJsDriver(dbPath)
+    await shouldThrow(driver4.loadDatabase())
+  })
+
+  it('should throw if commit file contains unknown data files', async () => {
+    const rfs = RealFS()
+    await rfs.fsRemoveTree(dbPath)
+    const driver4 = new LokiJsDriver(dbPath)
+    const coll = driver4.getLokiInstance().addCollection('block')
+    coll.insert({ a: 1 })
+    coll.insert({ b: 2 })
+    await driver.flushAndTrimData()
+    const oldCommit:DBCommit = JSON.parse(await rfs.fsReadFile(path.join(dbPath, 'commit.json')))
+    oldCommit.collections['block'] = 'wrong-file.json'
+    const driver5 = new LokiJsDriver(dbPath)
+    await shouldThrow(driver5.loadDatabase())
+  })
+})
diff --git a/test/dal/source_dal.js b/test/dal/source_dal.js
deleted file mode 100644
index 08c243bcdefa51c5507ed5e9631aafc69201e957..0000000000000000000000000000000000000000
--- a/test/dal/source_dal.js
+++ /dev/null
@@ -1,51 +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 FileDAL = require('../../app/lib/dal/fileDAL').FileDAL
-const dir = require('../../app/lib/system/directory');
-const indexer    = require('../../app/lib/indexer').Indexer
-
-let dal;
-
-describe("Source DAL", function(){
-
-  before(() => co(function *() {
-    dal = new FileDAL(yield dir.getHomeParams(true, 'db0'));
-    yield dal.init();
-  }));
-
-  it('should be able to feed the sindex with unordered rows', () => co(function *() {
-    yield dal.sindexDAL.insertBatch([
-      { op: 'UPDATE', identifier: 'SOURCE_1', pos: 4, written_on: '139-H', writtenOn: 139, written_time: 4500, consumed: true,  conditions: 'SIG(ABC)' },
-      { op: 'CREATE', identifier: 'SOURCE_1', pos: 4, written_on: '126-H', writtenOn: 126, written_time: 2000, consumed: false, conditions: 'SIG(ABC)' },
-      { op: 'CREATE', identifier: 'SOURCE_2', pos: 4, written_on: '126-H', writtenOn: 126, written_time: 2000, consumed: false, conditions: 'SIG(ABC)' },
-      { op: 'CREATE', identifier: 'SOURCE_3', pos: 4, written_on: '126-H', writtenOn: 126, written_time: 2000, consumed: false, conditions: 'SIG(DEF)' }
-    ]);
-    (yield dal.sindexDAL.sqlFind({ identifier: 'SOURCE_1' })).should.have.length(2);
-    (yield dal.sindexDAL.sqlFind({ pos: 4 })).should.have.length(4);
-    // Source availability
-    const sourcesOfDEF = yield dal.sindexDAL.getAvailableForPubkey('DEF');
-    sourcesOfDEF.should.have.length(1);
-    const sourcesOfABC = yield dal.sindexDAL.getAvailableForPubkey('ABC');
-    sourcesOfABC.should.have.length(1);
-    const source1 = yield dal.sindexDAL.getSource('SOURCE_1', 4);
-    source1.should.have.property('consumed').equal(true);
-    const udSources = yield dal.sindexDAL.getUDSources('ABC');
-    udSources.should.have.length(2);
-    udSources[0].should.have.property('consumed').equal(true);
-    udSources[1].should.have.property('consumed').equal(false);
-  }));
-});
diff --git a/test/dal/sources-dal.ts b/test/dal/sources-dal.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3288f50319c3af1dce84788329a96033a392f89d
--- /dev/null
+++ b/test/dal/sources-dal.ts
@@ -0,0 +1,47 @@
+// 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 {FileDAL} from "../../app/lib/dal/fileDAL"
+import {Directory} from "../../app/lib/system/directory"
+
+const should = require('should');
+
+let dal:FileDAL
+
+describe("Source DAL", function(){
+
+  before(async () => {
+    dal = new FileDAL(await Directory.getHomeParams(true, 'db0'));
+    await dal.init({} as any)
+  })
+
+  it('should be able to feed the sindex with unordered rows', async () => {
+    await dal.sindexDAL.insertBatch([
+      { op: 'UPDATE', tx: null, identifier: 'SOURCE_1', pos: 4, written_on: '139-H', writtenOn: 139, written_time: 4500, consumed: true,  conditions: 'SIG(ABC)' },
+      { op: 'CREATE', tx: null, identifier: 'SOURCE_1', pos: 4, written_on: '126-H', writtenOn: 126, written_time: 2000, consumed: false, conditions: 'SIG(ABC)' },
+      { op: 'CREATE', tx: null, identifier: 'SOURCE_2', pos: 4, written_on: '126-H', writtenOn: 126, written_time: 2000, consumed: false, conditions: 'SIG(ABC)' },
+      { op: 'CREATE', tx: null, identifier: 'SOURCE_3', pos: 4, written_on: '126-H', writtenOn: 126, written_time: 2000, consumed: false, conditions: 'SIG(DEF)' }
+    ] as any);
+    (await dal.sindexDAL.findRaw({ identifier: 'SOURCE_1' })).should.have.length(2);
+    (await dal.sindexDAL.findRaw({ pos: 4 })).should.have.length(4);
+    // Source availability
+    const sourcesOfDEF = await dal.sindexDAL.getAvailableForPubkey('DEF');
+    sourcesOfDEF.should.have.length(1);
+    const sourcesOfABC = await dal.sindexDAL.getAvailableForPubkey('ABC');
+    sourcesOfABC.should.have.length(1);
+    const source1 = await dal.sindexDAL.getTxSource('SOURCE_1', 4) as any
+    source1.should.have.property('consumed').equal(true);
+    const source2 = await dal.sindexDAL.getTxSource('SOURCE_2', 4) as any
+    source2.should.have.property('consumed').equal(false);
+  })
+})
diff --git a/test/dal/triming.js b/test/dal/triming-dal.ts
similarity index 63%
rename from test/dal/triming.js
rename to test/dal/triming-dal.ts
index a684a0c0e0b66106b2b7bc5a1a2ba26daf9b0385..ada1d304f057d8ca18a9e9b2d535e3a32f40e9df 100644
--- a/test/dal/triming.js
+++ b/test/dal/triming-dal.ts
@@ -11,132 +11,131 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
-const co = require('co');
+import {FileDAL} from "../../app/lib/dal/fileDAL"
+import {Directory} from "../../app/lib/system/directory"
+import {Indexer} from "../../app/lib/indexer"
+import {simpleNodeWith2Users} from "../integration/tools/toolbox"
+
 const should = require('should');
-const FileDAL = require('../../app/lib/dal/fileDAL').FileDAL
-const dir = require('../../app/lib/system/directory');
-const indexer    = require('../../app/lib/indexer').Indexer
-const toolbox = require('../integration/tools/toolbox');
 
-let dal;
+let dal:FileDAL
 
 describe("Triming", function(){
 
-  before(() => co(function *() {
-    dal = new FileDAL(yield dir.getHomeParams(true, 'db0'));
-    yield dal.init();
-  }));
+  before(async () => {
+    dal = new FileDAL(await Directory.getHomeParams(true, 'db0'));
+    await dal.init({} as any)
+  })
 
-  it('should be able to feed the bindex', () => co(function *() {
-    yield dal.bindexDAL.insertBatch([
+  it('should be able to feed the bindex', async () => {
+    await dal.bindexDAL.insertBatch([
       { number: 121, version: 6, bsize: 0, hash: "HASH", issuer: "ISSUER", time: 0, membersCount: 3, issuersCount: 2, issuersFrame: 1, issuersFrameVar: 2, avgBlockSize: 0, medianTime: 1482500000, dividend: 100, mass: 300, massReeval: 300, unitBase: 2, powMin: 70, udTime: 0, udReevalTime: 0, diffNumber: 5, speed: 1.0 },
       { number: 122, version: 6, bsize: 0, hash: "HASH", issuer: "ISSUER", time: 0, membersCount: 3, issuersCount: 2, issuersFrame: 1, issuersFrameVar: 2, avgBlockSize: 0, medianTime: 1482500000, dividend: 100, mass: 300, massReeval: 300, unitBase: 2, powMin: 70, udTime: 0, udReevalTime: 0, diffNumber: 5, speed: 1.0 },
       { number: 123, version: 6, bsize: 0, hash: "HASH", issuer: "ISSUER", time: 0, membersCount: 3, issuersCount: 2, issuersFrame: 1, issuersFrameVar: 2, avgBlockSize: 0, medianTime: 1482500000, dividend: 100, mass: 300, massReeval: 300, unitBase: 2, powMin: 70, udTime: 0, udReevalTime: 0, diffNumber: 5, speed: 1.0 },
       { number: 124, version: 6, bsize: 0, hash: "HASH", issuer: "ISSUER", time: 0, membersCount: 3, issuersCount: 2, issuersFrame: 1, issuersFrameVar: 2, avgBlockSize: 0, medianTime: 1482500000, dividend: 100, mass: 300, massReeval: 300, unitBase: 2, powMin: 70, udTime: 0, udReevalTime: 0, diffNumber: 5, speed: 1.0 },
       { number: 125, version: 6, bsize: 0, hash: "HASH", issuer: "ISSUER", time: 0, membersCount: 3, issuersCount: 2, issuersFrame: 1, issuersFrameVar: 2, avgBlockSize: 0, medianTime: 1482500000, dividend: 100, mass: 300, massReeval: 300, unitBase: 2, powMin: 70, udTime: 0, udReevalTime: 0, diffNumber: 5, speed: 1.0 }
-    ]);
-  }));
+    ] as any);
+  })
 
-  it('should have bindex head(1) = 125', () => co(function *() {
-    const head = yield dal.bindexDAL.head(1);
+  it('should have bindex head(1) = 125', async () => {
+    const head = await dal.bindexDAL.head(1);
     head.should.have.property('number').equal(125);
-  }));
+  })
 
-  it('should have bindex range(1, 3) = 125, 124, 123', () => co(function *() {
-    const range = yield dal.bindexDAL.range(1,3);
+  it('should have bindex range(1, 3) = 125, 124, 123', async () => {
+    const range = await dal.bindexDAL.range(1,3);
     range.should.have.length(3);
     range[0].should.have.property('number').equal(125);
     range[1].should.have.property('number').equal(124);
     range[2].should.have.property('number').equal(123);
-  }));
+  })
 
-  it('should be able to feed the iindex', () => co(function *() {
-    yield dal.iindexDAL.insertBatch([
+  it('should be able to feed the iindex', async () => {
+    await dal.iindexDAL.insertBatch([
       { op: 'CREATE', pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', uid: 'cat', created_on: '121-H', written_on: '122-H', writtenOn: 122, member: true,  wasMember: true, kick: false },
       { op: 'UPDATE', pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', uid: null,  created_on: '121-H', written_on: '123-H', writtenOn: 123, member: null,  wasMember: null, kick: true },
       { op: 'UPDATE', pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', uid: null,  created_on: '121-H', written_on: '124-H', writtenOn: 124, member: false, wasMember: null, kick: false }
-    ]);
-    let lignes = yield dal.iindexDAL.reducable('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
+    ] as any);
+    let lignes = await dal.iindexDAL.reducable('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
     lignes.should.have.length(3);
-    indexer.DUP_HELPERS.reduce(lignes).should.have.property('member').equal(false);
-  }));
+    Indexer.DUP_HELPERS.reduce(lignes).should.have.property('member').equal(false);
+  })
 
-  it('should be able to trim the iindex', () => co(function *() {
+  it('should be able to trim the iindex', async () => {
     // Triming
-    yield dal.trimIndexes(124);
-    const lignes = yield dal.iindexDAL.reducable('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
+    await dal.trimIndexes(124);
+    const lignes = await dal.iindexDAL.reducable('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
     lignes.should.have.length(2);
-    indexer.DUP_HELPERS.reduce(lignes).should.have.property('member').equal(false);
-  }));
+    Indexer.DUP_HELPERS.reduce(lignes).should.have.property('member').equal(false);
+  })
 
-  it('triming again the iindex should have no effet', () => co(function *() {
+  it('triming again the iindex should have no effet', async () => {
     // Triming
-    yield dal.trimIndexes(124);
-    const lignes = yield dal.iindexDAL.reducable('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
+    await dal.trimIndexes(124);
+    const lignes = await dal.iindexDAL.reducable('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
     lignes.should.have.length(2);
-    indexer.DUP_HELPERS.reduce(lignes).should.have.property('member').equal(false);
-  }));
+    Indexer.DUP_HELPERS.reduce(lignes).should.have.property('member').equal(false);
+  })
 
-  it('should be able to feed the mindex', () => co(function *() {
-    yield dal.mindexDAL.insertBatch([
+  it('should be able to feed the mindex', async () => {
+    await dal.mindexDAL.insertBatch([
       { op: 'CREATE', pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', created_on: '121-H', written_on: '122-H', writtenOn: 122, expires_on: 1000, expired_on: null },
       { op: 'UPDATE', pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', created_on: '121-H', written_on: '123-H', writtenOn: 123, expires_on: 1200, expired_on: null },
       { op: 'UPDATE', pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', created_on: '121-H', written_on: '124-H', writtenOn: 124, expires_on: null, expired_on: null },
       { op: 'UPDATE', pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', created_on: '121-H', written_on: '125-H', writtenOn: 125, expires_on: 1400, expired_on: null }
-    ]);
-    const lignes = yield dal.mindexDAL.reducable('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
+    ] as any);
+    const lignes = await dal.mindexDAL.reducable('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
     lignes.should.have.length(4);
-    indexer.DUP_HELPERS.reduce(lignes).should.have.property('expires_on').equal(1400);
-  }));
+    Indexer.DUP_HELPERS.reduce(lignes).should.have.property('expires_on').equal(1400);
+  })
 
-  it('should be able to trim the mindex', () => co(function *() {
+  it('should be able to trim the mindex', async () => {
     // Triming
-    yield dal.trimIndexes(124);
-    const lignes = yield dal.mindexDAL.reducable('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
+    await dal.trimIndexes(124);
+    const lignes = await dal.mindexDAL.reducable('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
     lignes.should.have.length(3);
-    indexer.DUP_HELPERS.reduce(lignes).should.have.property('expires_on').equal(1400);
-  }));
+    Indexer.DUP_HELPERS.reduce(lignes).should.have.property('expires_on').equal(1400);
+  })
 
-  it('should be able to feed the cindex', () => co(function *() {
-    yield dal.cindexDAL.insertBatch([
+  it('should be able to feed the cindex', async () => {
+    await dal.cindexDAL.insertBatch([
       { op: 'CREATE', issuer: 'HgTT', receiver: 'DNan', created_on: '121-H', written_on: '126-H', writtenOn: 126, expires_on: 1000, expired_on: null },
       { op: 'UPDATE', issuer: 'HgTT', receiver: 'DNan', created_on: '121-H', written_on: '126-H', writtenOn: 126, expires_on: null, expired_on: 3000 },
       { op: 'CREATE', issuer: 'DNan', receiver: 'HgTT', created_on: '125-H', written_on: '126-H', writtenOn: 126, expires_on: null, expired_on: null }
-    ]);
-    (yield dal.cindexDAL.sqlFind({ issuer: 'HgTT' })).should.have.length(2);
-    (yield dal.cindexDAL.sqlFind({ issuer: 'DNan' })).should.have.length(1);
-  }));
+    ] as any);
+    (await dal.cindexDAL.findRaw({ issuer: 'HgTT' })).should.have.length(2);
+    (await dal.cindexDAL.findRaw({ issuer: 'DNan' })).should.have.length(1);
+  })
 
-  it('should be able to trim the cindex', () => co(function *() {
+  it('should be able to trim the cindex', async () => {
     // Triming
-    yield dal.trimIndexes(127);
-    (yield dal.cindexDAL.sqlFind({ issuer: 'HgTT' })).should.have.length(0);
+    await dal.trimIndexes(127);
+    (await dal.cindexDAL.findRaw({ issuer: 'HgTT' })).should.have.length(0);
     // { op: 'UPDATE', issuer: 'DNan', receiver: 'HgTT', created_on: '125-H', written_on: '126-H', writtenOn: 126, expires_on: 3600, expired_on: null },/**/
-    (yield dal.cindexDAL.sqlFind({ issuer: 'DNan' })).should.have.length(1);
-  }));
+    (await dal.cindexDAL.findRaw({ issuer: 'DNan' })).should.have.length(1);
+  })
 
-  it('should be able to feed the sindex', () => co(function *() {
-    yield dal.sindexDAL.insertBatch([
+  it('should be able to feed the sindex', async () => {
+    await dal.sindexDAL.insertBatch([
       { op: 'CREATE', identifier: 'SOURCE_1', pos: 4, written_on: '126-H', writtenOn: 126, written_time: 2000, consumed: false },
       { op: 'UPDATE', identifier: 'SOURCE_1', pos: 4, written_on: '139-H', writtenOn: 139, written_time: 4500, consumed: true },
       { op: 'CREATE', identifier: 'SOURCE_2', pos: 4, written_on: '126-H', writtenOn: 126, written_time: 2000, consumed: false },
       { op: 'CREATE', identifier: 'SOURCE_3', pos: 4, written_on: '126-H', writtenOn: 126, written_time: 2000, consumed: false }
-    ]);
-    (yield dal.sindexDAL.sqlFind({ identifier: 'SOURCE_1' })).should.have.length(2);
-    (yield dal.sindexDAL.sqlFind({ pos: 4 })).should.have.length(4);
-  }));
+    ] as any);
+    (await dal.sindexDAL.findRaw({ identifier: 'SOURCE_1' })).should.have.length(2);
+    (await dal.sindexDAL.findRaw({ pos: 4 })).should.have.length(4);
+  })
 
-  it('should be able to trim the sindex', () => co(function *() {
+  it('should be able to trim the sindex', async () => {
     // Triming
-    yield dal.trimIndexes(140);
-    (yield dal.sindexDAL.sqlFind({ identifier: 'SOURCE_1' })).should.have.length(0);
-    (yield dal.sindexDAL.sqlFind({ pos: 4 })).should.have.length(2);
-  }));
+    await dal.trimIndexes(140);
+    (await dal.sindexDAL.findRaw({ identifier: 'SOURCE_1' })).should.have.length(0);
+    (await dal.sindexDAL.findRaw({ pos: 4 })).should.have.length(2);
+  })
 
-  it('should be able to trim the bindex', () => co(function *() {
+  it('should be able to trim the bindex', async () => {
     // Triming
-    const server = (yield toolbox.simpleNodeWith2Users({
+    const server = (await simpleNodeWith2Users({
       forksize: 9,
       sigQty: 1,
       dtDiffEval: 2,
@@ -144,13 +143,13 @@ describe("Triming", function(){
     })).s1;
     // const s1 = server.s1;
     for (let i = 0; i < 13; i++) {
-      yield server.commit();
+      await server.commit();
     }
-    (yield server.dal.bindexDAL.head(1)).should.have.property('number').equal(12);
-    (yield server.dal.bindexDAL.head(13)).should.have.property('number').equal(0);
-    yield server.commit();
-    should.not.exists(yield server.dal.bindexDAL.head(14)); // Trimed
-
-    yield server.closeCluster()
-  }));
-});
+    (await server.dal.bindexDAL.head(1)).should.have.property('number').equal(12);
+    (await server.dal.bindexDAL.head(13)).should.have.property('number').equal(0);
+    await server.commit();
+    should.not.exists(await server.dal.bindexDAL.head(14)); // Trimed
+
+    await server.closeCluster()
+  })
+})
diff --git a/test/data/blocks.js b/test/data/blocks-data.ts
similarity index 99%
rename from test/data/blocks.js
rename to test/data/blocks-data.ts
index 17094232ad9daf7126b7751d3fd878ad24e7999f..ccaa84559f9f4453701897a8fad0ea8cb9b163c1 100644
--- a/test/data/blocks.js
+++ b/test/data/blocks-data.ts
@@ -12,7 +12,7 @@
 // GNU Affero General Public License for more details.
 
 
-module.exports = {
+export const BLOCK_TEST_DATA = {
   WRONG_SIGNATURE:
     "Version: 10\n" +
     "Type: Block\n" +
diff --git a/test/eslint.js b/test/eslint-test.ts
similarity index 95%
rename from test/eslint.js
rename to test/eslint-test.ts
index c6714b15f3c9e1b1bdee884774d2201cc1b85386..ae87015a9fb58f03f47eee688ca43d889fad7696 100644
--- a/test/eslint.js
+++ b/test/eslint-test.ts
@@ -20,12 +20,11 @@ describe('Linting', () => {
   // matches a glob pattern
     const paths = [
       'app',
-      'bin/duniter',
       'test'
     ];
 
   // Specify style of output
-    const options = {};
+    const options:any = {};
     options.formatter = 'stylish';
 
   // Run the tests
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/block_local.js b/test/fast/block_local.js
deleted file mode 100644
index ed4d289e47dc953ebd2489eb4121719358e65061..0000000000000000000000000000000000000000
--- a/test/fast/block_local.js
+++ /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.
-
-"use strict";
-const co             = require('co');
-const should         = require('should');
-const parsers        = require('../../app/lib/common-libs/parsers').parsers
-const indexer        = require('../../app/lib/indexer').Indexer
-const LOCAL_RULES    = require('../../app/lib/rules/local_rules').LOCAL_RULES_FUNCTIONS
-const ALIAS          = require('../../app/lib/rules').ALIAS
-const blocks         = require('../data/blocks.js');
-const parser         = parsers.parseBlock;
-const BlockDTO       = require('../../app/lib/dto/BlockDTO').BlockDTO
-
-const conf = {
-
-  sigQty: 1,
-  powZeroMin: 1,
-  powPeriod: 18,
-  incDateMin: 10,
-  avgGenTime: 60,
-  medianTimeBlocks: 20,
-  dt: 100,
-  ud0: 100,
-  c: 0.1
-}
-
-describe("Block local coherence", function(){
-
-  it('a valid block should be well formatted',                                                      test(ALIAS.ALL_LOCAL_BUT_POW_AND_SIGNATURE, blocks.VALID_ROOT));
-
-  describe("should be rejected", function(){
-
-  it('if wrong signature block',                                                                    test(LOCAL_RULES.checkBlockSignature, blocks.WRONG_SIGNATURE, 'Block\'s signature must match'));
-  it('if root block does not have Parameters',                                                      test(LOCAL_RULES.checkParameters, blocks.ROOT_WITHOUT_PARAMETERS, 'Parameters must be provided for root block'));
-  it('if proof-of-work does not match PoWMin field',                                                test(LOCAL_RULES.checkProofOfWork, blocks.WRONG_PROOF_OF_WORK, 'Not a proof-of-work'));
-  it('if non-root has Parameters',                                                                  test(LOCAL_RULES.checkParameters, blocks.NON_ROOT_WITH_PARAMETERS, 'Parameters must not be provided for non-root block'));
-  it('if root block has PreviousHash',                                                              test(LOCAL_RULES.checkPreviousHash, blocks.ROOT_WITH_PREVIOUS_HASH, 'PreviousHash must not be provided for root block'));
-  it('if root block has PreviousIssuer',                                                            test(LOCAL_RULES.checkPreviousIssuer, blocks.ROOT_WITH_PREVIOUS_ISSUER, 'PreviousIssuer must not be provided for root block'));
-  it('if non-root block does not have PreviousHash',                                                test(LOCAL_RULES.checkPreviousHash, blocks.NON_ROOT_WITHOUT_PREVIOUS_HASH, 'PreviousHash must be provided for non-root block'));
-  it('if non-root block does not have PreviousIssuer',                                              test(LOCAL_RULES.checkPreviousIssuer, blocks.NON_ROOT_WITHOUT_PREVIOUS_ISSUER, 'PreviousIssuer must be provided for non-root block'));
-  it('a V2 block with Dividend must have UnitBase field',                                           test(LOCAL_RULES.checkUnitBase, blocks.UD_BLOCK_WIHTOUT_BASE, 'Document has unkown fields or wrong line ending format'));
-  it('a V3 root block must have UnitBase field',                                                    test(LOCAL_RULES.checkUnitBase, blocks.V3_ROOT_BLOCK_NOBASE, 'Document has unkown fields or wrong line ending format'));
-  it('a V3 root block must have UnitBase field equal 0',                                            test(LOCAL_RULES.checkUnitBase, blocks.V3_ROOT_BLOCK_POSITIVE_BASE, 'UnitBase must equal 0 for root block'));
-  it('a block with wrong date (in past)',                                                           test(LOCAL_RULES.checkBlockTimes, blocks.WRONG_DATE_LOWER, 'A block must have its Time between MedianTime and MedianTime + 1440'));
-  it('a block with wrong date (in future, but too far)',                                            test(LOCAL_RULES.checkBlockTimes, blocks.WRONG_DATE_HIGHER_BUT_TOO_HIGH, 'A block must have its Time between MedianTime and MedianTime + 1440'));
-  it('a root block with different time & medianTime should fail',                                   test(LOCAL_RULES.checkBlockTimes, blocks.WRONG_ROOT_TIMES, 'Root block must have Time equal MedianTime'));
-  it('a block with good date',                                                                      test(LOCAL_RULES.checkBlockTimes, blocks.GOOD_DATE_HIGHER));
-  it('Block cannot contain wrongly signed identities',                                              test(LOCAL_RULES.checkIdentitiesSignature, blocks.WRONGLY_SIGNED_IDENTITIES, 'Identity\'s signature must match'));
-  it('block with colliding uids in identities',                                                     test(LOCAL_RULES.checkIdentitiesUserIDConflict, blocks.COLLIDING_UIDS, 'Block must not contain twice same identity uid'));
-  it('a block with colliding pubkeys in identities',                                                test(LOCAL_RULES.checkIdentitiesPubkeyConflict, blocks.COLLIDING_PUBKEYS, 'Block must not contain twice same identity pubkey'));
-  it('a block with identities not matchin joins',                                                   test(LOCAL_RULES.checkIdentitiesMatchJoin, blocks.WRONG_IDTY_MATCH_JOINS, 'Each identity must match a newcomer line with same userid and certts'));
-  it('Block cannot contain wrongly signed join',                                                    test(LOCAL_RULES.checkMembershipsSignature, blocks.WRONGLY_SIGNED_JOIN, 'Membership\'s signature must match'));
-  it('Block cannot contain wrongly signed active',                                                  test(LOCAL_RULES.checkMembershipsSignature, blocks.WRONGLY_SIGNED_ACTIVE, 'Membership\'s signature must match'));
-  it('Block cannot contain wrongly signed leave',                                                   test(LOCAL_RULES.checkMembershipsSignature, blocks.WRONGLY_SIGNED_LEAVE, 'Membership\'s signature must match'));
-  it('Block cannot contain a same pubkey more than once in joiners',                                test(LOCAL_RULES.checkPubkeyUnicity, blocks.MULTIPLE_JOINERS, 'Block cannot contain a same pubkey more than once in joiners, actives, leavers and excluded'));
-  it('Block cannot contain a same pubkey more than once in actives',                                test(LOCAL_RULES.checkPubkeyUnicity, blocks.MULTIPLE_ACTIVES, 'Block cannot contain a same pubkey more than once in joiners, actives, leavers and excluded'));
-  it('Block cannot contain a same pubkey more than once in leavers',                                test(LOCAL_RULES.checkPubkeyUnicity, blocks.MULTIPLE_LEAVES, 'Block cannot contain a same pubkey more than once in joiners, actives, leavers and excluded'));
-  it('Block cannot contain a same pubkey more than once in excluded',                               test(LOCAL_RULES.checkPubkeyUnicity, blocks.MULTIPLE_EXCLUDED, 'Block cannot contain a same pubkey more than once in joiners, actives, leavers and excluded'));
-  it('Block cannot contain a same pubkey more than once in joiners, actives, leavers and excluded', test(LOCAL_RULES.checkPubkeyUnicity, blocks.MULTIPLE_OVER_ALL, 'Block cannot contain a same pubkey more than once in joiners, actives, leavers and excluded'));
-  it('Block cannot have revoked key in joiners,actives,leavers',                                    test(LOCAL_RULES.checkMembershipUnicity, blocks.REVOKED_WITH_MEMBERSHIPS, 'Unicity constraint PUBLIC_KEY on MINDEX is not respected'));
-  it('Block cannot have revoked key duplicates',                                                    test(LOCAL_RULES.checkRevokedUnicity, blocks.REVOKED_WITH_DUPLICATES, 'A single revocation per member is allowed'));
-  it('Block revoked keys must be in excluded',                                                      test(LOCAL_RULES.checkRevokedAreExcluded, blocks.REVOKED_NOT_IN_EXCLUDED, 'A revoked member must be excluded'));
-  it('Block cannot contain 2 certifications from same issuer',                                      test(LOCAL_RULES.checkCertificationOneByIssuer, blocks.MULTIPLE_CERTIFICATIONS_FROM_SAME_ISSUER, 'Block cannot contain two certifications from same issuer'));
-  it('Block cannot contain identical certifications',                                               test(LOCAL_RULES.checkCertificationUnicity, blocks.IDENTICAL_CERTIFICATIONS, 'Block cannot contain identical certifications (A -> B)'));
-  it('Block cannot contain certifications concerning a leaver',                                     test(LOCAL_RULES.checkCertificationIsntForLeaverOrExcluded, blocks.LEAVER_WITH_CERTIFICATIONS, 'Block cannot contain certifications concerning leavers or excluded members'));
-  it('Block cannot contain certifications concerning an excluded member',                           test(LOCAL_RULES.checkCertificationIsntForLeaverOrExcluded, blocks.EXCLUDED_WITH_CERTIFICATIONS, 'Block cannot contain certifications concerning leavers or excluded members'));
-  it('Block cannot contain transactions without issuers (1)',                                       test(LOCAL_RULES.checkTxIssuers, blocks.TRANSACTION_WITHOUT_ISSUERS, 'A transaction must have at least 1 issuer'));
-  it('Block cannot contain transactions without issuers (2)',                                       test(LOCAL_RULES.checkTxSources, blocks.TRANSACTION_WITHOUT_SOURCES, 'A transaction must have at least 1 source'));
-  it('Block cannot contain transactions without issuers (3)',                                       test(LOCAL_RULES.checkTxRecipients, blocks.TRANSACTION_WITHOUT_RECIPIENT, 'A transaction must have at least 1 recipient'));
-  it('Block cannot contain transactions with identical sources in one transaction',                 test(LOCAL_RULES.checkTxSources, blocks.TRANSACTION_WITH_DUPLICATED_SOURCE_SINGLE_TX, 'It cannot exist 2 identical sources for transactions inside a given block'));
-  it('Block cannot contain transactions with identical sources in a pack of transactions',          test(LOCAL_RULES.checkTxSources, blocks.TRANSACTION_WITH_DUPLICATED_SOURCE_MULTIPLE_TX, 'It cannot exist 2 identical sources for transactions inside a given block'));
-  it('Block cannot contain transactions with empty output conditions',                              test(LOCAL_RULES.checkTxRecipients, blocks.TRANSACTION_WITH_EMPTY_TX_CONDITIONS, 'Empty conditions are forbidden'));
-  it('Block cannot contain transactions with wrong total',                                          test(LOCAL_RULES.checkTxAmounts, blocks.TRANSACTION_WRONG_TOTAL, 'Transaction inputs sum must equal outputs sum'));
-  it('Block cannot contain transactions with wrong base transformation',                            test(LOCAL_RULES.checkTxAmounts, blocks.TRANSACTION_WRONG_TRANSFORM, 'Transaction output base amount does not equal previous base deltas'));
-  it('Block cannot contain transactions with unexisting lower base in sources',                     test(LOCAL_RULES.checkTxAmounts, blocks.TRANSACTION_WRONG_TRANSFORM_LOW_BASE, 'Transaction output base amount does not equal previous base deltas'));
-  it('Block cannot contain transactions with more than 100 lines',                                  test(LOCAL_RULES.checkTxLen, blocks.TRANSACTION_TOO_LONG, 'A transaction has a maximum size of 100 lines'));
-  it('Block cannot contain transactions with a too large output',                                   test(LOCAL_RULES.checkTxLen, blocks.OUTPUT_TOO_LONG, 'A transaction output has a maximum size of 2000 characters'));
-  it('Block cannot contain transactions with a too large unlock',                                   test(LOCAL_RULES.checkTxLen, blocks.UNLOCK_TOO_LONG, 'A transaction unlock has a maximum size of 2000 characters'));
-  it('Block cannot be refused with a good V3 transaction',                                          test(LOCAL_RULES.checkTxAmounts, blocks.TRANSACTION_V3_GOOD_AMOUNTS));
-  it('Block cannot contain transactions with wrong signatures',                                     test(LOCAL_RULES.checkTxSignature, blocks.TRANSACTION_WITH_WRONG_SIGNATURES, 'Signature from a transaction must match'));
-  });
-  
-});
-
-
-function test (rule, raw, expectedMessage) {
-  return () => co(function *() {
-    try {
-      let obj = parser.syncWrite(raw);
-      let block = BlockDTO.fromJSONObject(obj);
-      let index = indexer.localIndex(block, conf)
-      yield rule(block, conf, index); // conf parameter is not always used
-      if (expectedMessage) {
-        throw 'Test should have thrown an error';
-      }
-    } catch (e) {
-      if (!expectedMessage) {
-        console.error(e.stack || e);
-      }
-      if (e.uerr) {
-        // This is a controlled error
-        e.uerr.message.should.equal(expectedMessage);
-      } else if (e) {
-        // This is a controlled error
-        e.message.should.equal(expectedMessage);
-      } else {
-        // throw Error(e)
-        // Display non wrapped errors (wrapped error is an error in constants.js)
-        // console.error(e.stack || e);
-      }
-    }
-  });
-}
diff --git a/test/fast/cfs.js b/test/fast/cfs.js
deleted file mode 100644
index 2067d7b27217e1edca77a9da04c5fb79d28d5302..0000000000000000000000000000000000000000
--- a/test/fast/cfs.js
+++ /dev/null
@@ -1,155 +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";
-
-var assert = require('assert');
-var should = require('should');
-var co = require('co');
-var CFSCore = require('../../app/lib/dal/fileDALs/CFSCore').CFSCore;
-var mockFS = require('q-io/fs-mock')({
-  'B5_a': {
-    "A.json": '{ "text": "Content of A from B5_a" }'
-  },
-  'B4': {
-    'B.json': '{ "text": "Content of B" }'
-  },
-  'B3': {
-    'A.json': '{ "text": "Content of A from B3" }',
-    'C.json': '{ "text": "Content of C from B3" }'
-  },
-  'OTHER': {
-    'X.json': '{ "text": "Content of X" }'
-  }
-});
-
-describe("CFS", () => {
-
-  var coreB3 = new CFSCore('/B3', mockFS);
-  var coreB4 = new CFSCore('/B4', mockFS);
-  var coreB5 = new CFSCore('/B5_a', mockFS);
-
-  var rootCore = new CFSCore('/OTHER', mockFS);
-
-  // ------------ Direct READ ------------
-
-  it('should have the content of A.json from B5', () => {
-    return co(function *() {
-      var content = yield coreB5.readJSON('A.json');
-      content.should.have.property('text').equal('Content of A from B5_a');
-    });
-  });
-
-  // WRITE of file /C.json
-
-  it('should have the content of C.json modified from B5 (direct read)', () => {
-    return co(function *() {
-      yield coreB5.writeJSON('C.json', { text: 'Content of C from B5_a'});
-      var content = yield coreB5.readJSON('C.json');
-      content.should.have.property('text').equal('Content of C from B5_a');
-    });
-  });
-
-  // WRITE of file /D.json
-
-  it('should have the content of D.json modified from B4 (direct read/write)', () => {
-    return co(function *() {
-      yield coreB4.writeJSON('D.json', { text: 'Content of D'});
-      var content = yield coreB4.readJSON('D.json');
-      content.should.have.property('text').equal('Content of D');
-    });
-  });
-
-  // REMOVE file /D.json
-
-  it('should have the content of D.json modified from B5 (direct read/write)', () => {
-    return co(function *() {
-      var exists = yield coreB5.exists('D.json');
-      var content = yield coreB5.read('D.json');
-      assert.equal(exists, false);
-      assert.equal(content, null);
-    });
-  });
-
-  // ------------ LIST ------------
-
-  it('should have G,H,I as files from /DIR', () => {
-    return co(function *() {
-      yield coreB3.makeTree('/DIR');
-      yield coreB4.makeTree('/DIR');
-      yield coreB5.makeTree('/DIR');
-      yield coreB3.writeJSON('/DIR/G.json', { text: 'Content of DIR/I'});
-      yield coreB4.writeJSON('/DIR/H.json', { text: 'Content of DIR/H'});
-      yield coreB5.writeJSON('/DIR/I.json', { text: 'Content of DIR/G'});
-      (yield coreB3.list('/DIR')).should.deepEqual(['G.json']);
-      (yield coreB4.list('/DIR')).should.deepEqual(['H.json']);
-      (yield coreB5.list('/DIR')).should.deepEqual(['I.json']);
-    });
-  });
-
-  // WRITE of file /DIR2/I.json in B4
-
-  it('should have I as files from /DIR2', () => {
-    return co(function *() {
-      yield coreB3.makeTree('/DIR2');
-      yield coreB3.writeJSON('/DIR2/I.json', { text: 'Content of DIR2/I in B4'});
-      var files = yield coreB3.list('/DIR2');
-      files.should.have.length(1);
-      files.should.deepEqual(['I.json']);
-      // Check its contents
-      var contents = yield coreB3.listJSON('/DIR2');
-      contents.should.have.length(1);
-      contents.should.deepEqual([{ text: 'Content of DIR2/I in B4' }]);
-    });
-  });
-
-  // REMOVE of file /DIR2/I.json in B5
-
-  it('should have no files from /DIR2 after file DELETION', () => {
-    return co(function *() {
-      yield coreB3.remove('/DIR2/I.json');
-      var files = yield coreB3.list('/DIR2');
-      files.should.have.length(0);
-      // Check its contents
-      var contents = yield coreB3.listJSON('/DIR2');
-      contents.should.have.length(0);
-    });
-  });
-
-  describe("Root core", () => {
-
-    it('should have 1 file in /OTHER folder', () => {
-      return co(function *() {
-        var files = yield rootCore.list('/');
-        files.should.have.length(1);
-        // Check its contents
-        var contents = yield rootCore.listJSON('/');
-        contents.should.have.length(1);
-        contents.should.deepEqual([{ text: 'Content of X' }]);
-      });
-    });
-
-    // REMOVE of file /OTHER/X.json in rootCore
-
-    it('should have no files from /OTHER after file DELETION', () => {
-      return co(function *() {
-        yield rootCore.remove('/X.json');
-        var files = yield rootCore.list('/');
-        files.should.have.length(0);
-        // Check its contents
-        var contents = yield rootCore.listJSON('/');
-        contents.should.have.length(0);
-      });
-    });
-  });
-});
diff --git a/test/fast/common/crypto.js b/test/fast/crypto/crypto.ts
similarity index 68%
rename from test/fast/common/crypto.js
rename to test/fast/crypto/crypto.ts
index 4c2ee4325f6e595acc0bf1a5f4ce7199d51663ae..c494a67f98005093b4236a307ecab6d123c3956c 100644
--- a/test/fast/common/crypto.js
+++ b/test/fast/crypto/crypto.ts
@@ -12,31 +12,27 @@
 // GNU Affero General Public License for more details.
 
 "use strict";
-const should = require('should');
-const co  = require('co');
-const nacl   = require('tweetnacl');
-const base58 = require('../../../app/lib/common-libs/crypto/base58')
-const naclUtil = require('../../../app/lib/common-libs/crypto/nacl-util')
-const keyring      = require('../../../app/lib/common-libs/crypto/keyring')
+import {Base58decode, Base58encode} from "../../../app/lib/common-libs/crypto/base58"
+import {decodeBase64, encodeBase64} from "../../../app/lib/common-libs/crypto/nacl-util"
+import {KeyGen, verify} from "../../../app/lib/common-libs/crypto/keyring"
 
-const Base58decode = base58.Base58decode
-const Base58encode = base58.Base58encode
+const should = require('should');
 
-const enc = naclUtil.encodeBase64
-const dec = naclUtil.decodeBase64
+const enc = encodeBase64
+const dec = decodeBase64
 
-let pub, sec, rawPub, rawSec;
+let pub:Uint8Array, sec:Uint8Array, rawPub:string, rawSec:string
 
 describe('ed25519 tests:', function(){
 
-  before(() => co(function*() {
+  before(async () => {
     // Generate the keypair
-    const keyPair = keyring.KeyGen('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP');
+    const keyPair = KeyGen('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP');
     pub = Base58decode(keyPair.publicKey);
     sec = Base58decode(keyPair.secretKey);
     rawPub = Base58encode(pub);
     rawSec = Base58encode(sec);
-  }));
+  })
 
   //it('good signature from existing secret key should be verified', function(done){
   //  const keys = nacl.sign.scryptKeyPair.fromSecretKey(dec("TM0Imyj/ltqdtsNG7BFOD1uKMZ81q6Yk2oz27U+4pvs9QBfD6EOJWpK3CqdNG368nJgszy7ElozAzVXxKvRmDA=="));
@@ -50,17 +46,16 @@ describe('ed25519 tests:', function(){
 
   it('good signature from generated key should be verified', function(done){
     const msg = "Some message to be signed";
-    const sig = keyring.KeyGen(rawPub, rawSec).signSync(msg);
-    const verified = keyring.verify(msg, sig, rawPub);
+    const sig = KeyGen(rawPub, rawSec).signSync(msg);
+    const verified = verify(msg, sig, rawPub);
     verified.should.equal(true);
     done();
   });
 
   it('wrong signature from generated key should NOT be verified', function(done){
     const msg = "Some message to be signed";
-    const cor = dec(enc(msg) + 'delta');
-    const sig = keyring.KeyGen(rawPub, rawSec).signSync(msg);
-    const verified = keyring.verify(cor, sig, rawPub);
+    const sig = KeyGen(rawPub, rawSec).signSync(msg);
+    const verified = verify(msg + 'delta', sig, rawPub);
     verified.should.equal(false);
     done();
   });
@@ -73,7 +68,7 @@ describe('ed25519 tests:', function(){
       "Block: 33291-0000088375C232A4DDAE171BB3D3C51347CB6DC8B7AA8BE4CD4DAEEADF26FEB8\n" +
       "Endpoints:\n" +
       "BASIC_MERKLED_API g1.duniter.org 10901\n"
-    const verified = keyring.verify(msg, "u8t1IoWrB/C7T+2rS0rKYJfjPG4FN/HkKGFiUO5tILIzjFDvxxQiVC+0o/Vaz805SMmqJvXqornI71U7//+wCg==", "3AF7bhGQRt6ymcBZgZTBMoDsEtSwruSarjNG8kDnaueX");
+    const verified = verify(msg, "u8t1IoWrB/C7T+2rS0rKYJfjPG4FN/HkKGFiUO5tILIzjFDvxxQiVC+0o/Vaz805SMmqJvXqornI71U7//+wCg==", "3AF7bhGQRt6ymcBZgZTBMoDsEtSwruSarjNG8kDnaueX");
     verified.should.equal(true);
     done();
   });
@@ -87,7 +82,7 @@ describe('ed25519 tests:', function(){
       "Endpoints:\n" +
       "BASIC_MERKLED_API g1.duniter.tednet.fr 37.187.0.204 8999\n" +
       "BMAS g1.duniter.tednet.fr 9000\n"
-    const verified = keyring.verify(msg, "ImvQDdpGv2M6CxSnBuseM/azJhBUGzWVgQhIvb5L2oGLm2GyLk/Sbi5wkb4IjbjbQfdRPdlcx5zxaHhvZCiWAA==", "Com8rJukCozHZyFao6AheSsfDQdPApxQRnz7QYFf64mm");
+    const verified = verify(msg, "ImvQDdpGv2M6CxSnBuseM/azJhBUGzWVgQhIvb5L2oGLm2GyLk/Sbi5wkb4IjbjbQfdRPdlcx5zxaHhvZCiWAA==", "Com8rJukCozHZyFao6AheSsfDQdPApxQRnz7QYFf64mm");
     verified.should.equal(true);
     done();
   });
diff --git a/test/fast/common/randomKey.js b/test/fast/crypto/randomKey.ts
similarity index 63%
rename from test/fast/common/randomKey.js
rename to test/fast/crypto/randomKey.ts
index b2a59e1ed6bbdf1960c7f09499b57c51db0c7946..c3a64cc91ee1bf6be035b63835a337da17bd03f1 100644
--- a/test/fast/common/randomKey.js
+++ b/test/fast/crypto/randomKey.ts
@@ -11,37 +11,31 @@
 // 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 keyring  = require('../../../app/lib/common-libs/crypto/keyring')
-const naclUtil = require('../../../app/lib/common-libs/crypto/nacl-util')
+import {Key, KeyGen, randomKey, verify} from "../../../app/lib/common-libs/crypto/keyring"
 
-const enc = naclUtil.encodeBase64
-const dec = naclUtil.decodeBase64
+const should = require('should');
 
-let key;
+let key:Key
 
 describe('Random keypair', function(){
 
-  before(() => co(function*() {
+  before(async () => {
     // Generate the keypair
-    key = keyring.randomKey()
-  }));
+    key = randomKey()
+  })
 
   it('good signature from generated key should be verified', function(done){
     const msg = "Some message to be signed";
-    const sig = keyring.KeyGen(key.publicKey, key.secretKey).signSync(msg);
-    const verified = keyring.verify(msg, sig, key.publicKey);
+    const sig = KeyGen(key.publicKey, key.secretKey).signSync(msg);
+    const verified = verify(msg, sig, key.publicKey);
     verified.should.equal(true);
     done();
   });
 
   it('wrong signature from generated key should NOT be verified', function(done){
     const msg = "Some message to be signed";
-    const cor = dec(enc(msg) + 'delta');
-    const sig = keyring.KeyGen(key.publicKey, key.secretKey).signSync(msg);
-    const verified = keyring.verify(cor, sig, key.publicKey);
+    const sig = KeyGen(key.publicKey, key.secretKey).signSync(msg);
+    const verified = verify(msg + 'delta', sig, key.publicKey);
     verified.should.equal(false);
     done();
   });
diff --git a/test/fast/dal/basic-loki.ts b/test/fast/dal/basic-loki.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2f26a3b84c81be50d2ca34fc03a7b52359aeea94
--- /dev/null
+++ b/test/fast/dal/basic-loki.ts
@@ -0,0 +1,50 @@
+// 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 * as assert from "assert"
+import {LokiIndex} from "../../../app/lib/dal/indexDAL/loki/LokiIndex"
+import {LokiProtocolIndex} from "../../../app/lib/dal/indexDAL/loki/LokiProtocolIndex"
+
+const loki = require('lokijs')
+
+interface TestEntity {
+  name: string
+  written_on: string
+  writtenOn: number
+}
+
+let lokiIndex:LokiIndex<TestEntity>
+
+class TheIndex extends LokiProtocolIndex<TestEntity> {
+}
+
+describe("Basic LokiJS database", () => {
+
+  before(async () => {
+    lokiIndex = new TheIndex(new loki('index.db'), 'iindex', [])
+    await lokiIndex.triggerInit()
+    await lokiIndex.init()
+  })
+
+  it('should be able instanciate the index', async () => {
+    assert.notEqual(null, lokiIndex)
+    assert.notEqual(undefined, lokiIndex)
+  })
+
+  it('should be able add new records', async () => {
+    assert.equal(0, (await lokiIndex.findRaw()).length)
+    await lokiIndex.insert({ written_on: '9-ABC', writtenOn: 9, name: 'A' })
+    assert.equal(1, (await lokiIndex.findRaw()).length)
+  })
+
+})
diff --git a/test/fast/dal/iindex-loki.ts b/test/fast/dal/iindex-loki.ts
new file mode 100644
index 0000000000000000000000000000000000000000..107f321933d5f660e23566d873e6ceaef267f9b3
--- /dev/null
+++ b/test/fast/dal/iindex-loki.ts
@@ -0,0 +1,77 @@
+// 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 * as assert from "assert"
+import {LokiIIndex} from "../../../app/lib/dal/indexDAL/loki/LokiIIndex"
+
+const loki = require('lokijs')
+
+let lokiIndex:LokiIIndex
+
+describe("IIndex LokiJS", () => {
+
+  before(async () => {
+    lokiIndex = new LokiIIndex(new loki('index.db'))
+    await lokiIndex.triggerInit()
+    await lokiIndex.init()
+  })
+
+  it('should be able instanciate the index', async () => {
+    assert.notEqual(null, lokiIndex)
+    assert.notEqual(undefined, lokiIndex)
+  })
+
+  it('should be able to add new records', async () => {
+    assert.equal(0, (await lokiIndex.findRaw()).length)
+    await lokiIndex.insert({
+      index: 'iindex',
+      op: 'CREATE',
+      uid: 'test-uid',
+      pub: 'test-pub',
+      hash: 'test-hash',
+      sig: 'test-sig',
+      created_on: '1-HASH_1',
+      written_on: '2-HASH_2',
+      writtenOn: 2,
+      age: 0,
+      member: true,
+      wasMember: true,
+      kick: false,
+      wotb_id: null
+    })
+    await lokiIndex.insert({
+      index: 'iindex',
+      op: 'UPDATE',
+      uid: null,
+      pub: 'test-pub',
+      hash: null,
+      sig: null,
+      created_on: '1-HASH_1',
+      written_on: '3-HASH_3',
+      writtenOn: 3,
+      age: 0,
+      member: false,
+      wasMember: true,
+      kick: false,
+      wotb_id: null
+    })
+    assert.equal(2, (await lokiIndex.findRaw()).length)
+  })
+
+  it('should be able to trim records', async () => {
+    assert.equal(2, (await lokiIndex.findRaw()).length)
+    await lokiIndex.trimRecords(4)
+    assert.equal(1, (await lokiIndex.findRaw()).length)
+  })
+
+})
diff --git a/test/fast/fork-resolution-3-3.ts b/test/fast/fork-resolution-3-3.ts
index 10e37d1fe9c14e68f2a5221894300e2825e01efd..1b63fa6fb677db9d1c7d2c5b3cf0016ad11d3b3e 100644
--- a/test/fast/fork-resolution-3-3.ts
+++ b/test/fast/fork-resolution-3-3.ts
@@ -206,7 +206,7 @@ class TestingSwitcherDao implements SwitcherDao<Block> {
   }
 
 
-  async getSandboxBlock(number: number, hash: string): Promise<Block | any> {
+  async getAbsoluteBlockInForkWindow(number: number, hash: string): Promise<Block | any> {
     return this.sbx.getBlock(number, hash)
   }
 
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/block_format.js b/test/fast/misc/block-format.ts
similarity index 92%
rename from test/fast/block_format.js
rename to test/fast/misc/block-format.ts
index 345b6838bc311a9c89fd828f94bc51f40d426bdd..eb9b7356e5fde1fe68eaadcb19c13e170fe09a02 100644
--- a/test/fast/block_format.js
+++ b/test/fast/misc/block-format.ts
@@ -11,9 +11,9 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {parsers} from "../../../app/lib/common-libs/parsers/index"
+
 const should  = require('should');
-const parsers = require('../../app/lib/common-libs/parsers').parsers
 
 const raw = "Version: 10\n" +
   "Type: Block\n" +
@@ -63,17 +63,9 @@ const raw = "Version: 10\n" +
 
 describe("Block format", function(){
 
-  var parser = parsers.parseBlock;
+  const parser = parsers.parseBlock;
 
-  it('a valid block should be well formatted', () => parser.syncWrite(raw, {
-    trace: (msg, p1) => {
-      if (p1) {
-        console.log(msg, p1)
-      } else {
-        console.log(msg)
-      }
-    }
-  }));
+  it('a valid block should be well formatted', () => parser.syncWrite(raw))
 
   describe("should be rejected", function(){
 
diff --git a/test/fast/misc/block-local.ts b/test/fast/misc/block-local.ts
new file mode 100644
index 0000000000000000000000000000000000000000..413aff68d0eea7d34871817132954d59ac9e1b9e
--- /dev/null
+++ b/test/fast/misc/block-local.ts
@@ -0,0 +1,122 @@
+// 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 {parsers} from "../../../app/lib/common-libs/parsers/index"
+import {Indexer} from "../../../app/lib/indexer"
+import {LOCAL_RULES_FUNCTIONS} from "../../../app/lib/rules/local_rules"
+import {ALIAS} from "../../../app/lib/rules/index"
+import {BLOCK_TEST_DATA} from "../../data/blocks-data"
+import {BlockDTO} from "../../../app/lib/dto/BlockDTO"
+
+const should = require('should');
+
+const conf = {
+
+  sigQty: 1,
+  powZeroMin: 1,
+  powPeriod: 18,
+  incDateMin: 10,
+  avgGenTime: 60,
+  medianTimeBlocks: 20,
+  dt: 100,
+  ud0: 100,
+  c: 0.1
+}
+
+describe("Block local coherence", function(){
+
+  it('a valid block should be well formatted',                                                      test(ALIAS.ALL_LOCAL_BUT_POW_AND_SIGNATURE, BLOCK_TEST_DATA.VALID_ROOT));
+
+  describe("should be rejected", function(){
+
+  it('if wrong signature block',                                                                    test(LOCAL_RULES_FUNCTIONS.checkBlockSignature, BLOCK_TEST_DATA.WRONG_SIGNATURE, 'Block\'s signature must match'));
+  it('if root block does not have Parameters',                                                      test(LOCAL_RULES_FUNCTIONS.checkParameters, BLOCK_TEST_DATA.ROOT_WITHOUT_PARAMETERS, 'Parameters must be provided for root block'));
+  it('if proof-of-work does not match PoWMin field',                                                test(LOCAL_RULES_FUNCTIONS.checkProofOfWork, BLOCK_TEST_DATA.WRONG_PROOF_OF_WORK, 'Not a proof-of-work'));
+  it('if non-root has Parameters',                                                                  test(LOCAL_RULES_FUNCTIONS.checkParameters, BLOCK_TEST_DATA.NON_ROOT_WITH_PARAMETERS, 'Parameters must not be provided for non-root block'));
+  it('if root block has PreviousHash',                                                              test(LOCAL_RULES_FUNCTIONS.checkPreviousHash, BLOCK_TEST_DATA.ROOT_WITH_PREVIOUS_HASH, 'PreviousHash must not be provided for root block'));
+  it('if root block has PreviousIssuer',                                                            test(LOCAL_RULES_FUNCTIONS.checkPreviousIssuer, BLOCK_TEST_DATA.ROOT_WITH_PREVIOUS_ISSUER, 'PreviousIssuer must not be provided for root block'));
+  it('if non-root block does not have PreviousHash',                                                test(LOCAL_RULES_FUNCTIONS.checkPreviousHash, BLOCK_TEST_DATA.NON_ROOT_WITHOUT_PREVIOUS_HASH, 'PreviousHash must be provided for non-root block'));
+  it('if non-root block does not have PreviousIssuer',                                              test(LOCAL_RULES_FUNCTIONS.checkPreviousIssuer, BLOCK_TEST_DATA.NON_ROOT_WITHOUT_PREVIOUS_ISSUER, 'PreviousIssuer must be provided for non-root block'));
+  it('a V2 block with Dividend must have UnitBase field',                                           test(LOCAL_RULES_FUNCTIONS.checkUnitBase, BLOCK_TEST_DATA.UD_BLOCK_WIHTOUT_BASE, 'Document has unkown fields or wrong line ending format'));
+  it('a V3 root block must have UnitBase field',                                                    test(LOCAL_RULES_FUNCTIONS.checkUnitBase, BLOCK_TEST_DATA.V3_ROOT_BLOCK_NOBASE, 'Document has unkown fields or wrong line ending format'));
+  it('a V3 root block must have UnitBase field equal 0',                                            test(LOCAL_RULES_FUNCTIONS.checkUnitBase, BLOCK_TEST_DATA.V3_ROOT_BLOCK_POSITIVE_BASE, 'UnitBase must equal 0 for root block'));
+  it('a block with wrong date (in past)',                                                           test(LOCAL_RULES_FUNCTIONS.checkBlockTimes, BLOCK_TEST_DATA.WRONG_DATE_LOWER, 'A block must have its Time between MedianTime and MedianTime + 1440'));
+  it('a block with wrong date (in future, but too far)',                                            test(LOCAL_RULES_FUNCTIONS.checkBlockTimes, BLOCK_TEST_DATA.WRONG_DATE_HIGHER_BUT_TOO_HIGH, 'A block must have its Time between MedianTime and MedianTime + 1440'));
+  it('a root block with different time & medianTime should fail',                                   test(LOCAL_RULES_FUNCTIONS.checkBlockTimes, BLOCK_TEST_DATA.WRONG_ROOT_TIMES, 'Root block must have Time equal MedianTime'));
+  it('a block with good date',                                                                      test(LOCAL_RULES_FUNCTIONS.checkBlockTimes, BLOCK_TEST_DATA.GOOD_DATE_HIGHER));
+  it('Block cannot contain wrongly signed identities',                                              test(LOCAL_RULES_FUNCTIONS.checkIdentitiesSignature, BLOCK_TEST_DATA.WRONGLY_SIGNED_IDENTITIES, 'Identity\'s signature must match'));
+  it('block with colliding uids in identities',                                                     test(LOCAL_RULES_FUNCTIONS.checkIdentitiesUserIDConflict, BLOCK_TEST_DATA.COLLIDING_UIDS, 'Block must not contain twice same identity uid'));
+  it('a block with colliding pubkeys in identities',                                                test(LOCAL_RULES_FUNCTIONS.checkIdentitiesPubkeyConflict, BLOCK_TEST_DATA.COLLIDING_PUBKEYS, 'Block must not contain twice same identity pubkey'));
+  it('a block with identities not matchin joins',                                                   test(LOCAL_RULES_FUNCTIONS.checkIdentitiesMatchJoin, BLOCK_TEST_DATA.WRONG_IDTY_MATCH_JOINS, 'Each identity must match a newcomer line with same userid and certts'));
+  it('Block cannot contain wrongly signed join',                                                    test(LOCAL_RULES_FUNCTIONS.checkMembershipsSignature, BLOCK_TEST_DATA.WRONGLY_SIGNED_JOIN, 'Membership\'s signature must match'));
+  it('Block cannot contain wrongly signed active',                                                  test(LOCAL_RULES_FUNCTIONS.checkMembershipsSignature, BLOCK_TEST_DATA.WRONGLY_SIGNED_ACTIVE, 'Membership\'s signature must match'));
+  it('Block cannot contain wrongly signed leave',                                                   test(LOCAL_RULES_FUNCTIONS.checkMembershipsSignature, BLOCK_TEST_DATA.WRONGLY_SIGNED_LEAVE, 'Membership\'s signature must match'));
+  it('Block cannot contain a same pubkey more than once in joiners',                                test(LOCAL_RULES_FUNCTIONS.checkPubkeyUnicity, BLOCK_TEST_DATA.MULTIPLE_JOINERS, 'Block cannot contain a same pubkey more than once in joiners, actives, leavers and excluded'));
+  it('Block cannot contain a same pubkey more than once in actives',                                test(LOCAL_RULES_FUNCTIONS.checkPubkeyUnicity, BLOCK_TEST_DATA.MULTIPLE_ACTIVES, 'Block cannot contain a same pubkey more than once in joiners, actives, leavers and excluded'));
+  it('Block cannot contain a same pubkey more than once in leavers',                                test(LOCAL_RULES_FUNCTIONS.checkPubkeyUnicity, BLOCK_TEST_DATA.MULTIPLE_LEAVES, 'Block cannot contain a same pubkey more than once in joiners, actives, leavers and excluded'));
+  it('Block cannot contain a same pubkey more than once in excluded',                               test(LOCAL_RULES_FUNCTIONS.checkPubkeyUnicity, BLOCK_TEST_DATA.MULTIPLE_EXCLUDED, 'Block cannot contain a same pubkey more than once in joiners, actives, leavers and excluded'));
+  it('Block cannot contain a same pubkey more than once in joiners, actives, leavers and excluded', test(LOCAL_RULES_FUNCTIONS.checkPubkeyUnicity, BLOCK_TEST_DATA.MULTIPLE_OVER_ALL, 'Block cannot contain a same pubkey more than once in joiners, actives, leavers and excluded'));
+  it('Block cannot have revoked key in joiners,actives,leavers',                                    test(LOCAL_RULES_FUNCTIONS.checkMembershipUnicity, BLOCK_TEST_DATA.REVOKED_WITH_MEMBERSHIPS, 'Unicity constraint PUBLIC_KEY on MINDEX is not respected'));
+  it('Block cannot have revoked key duplicates',                                                    test(LOCAL_RULES_FUNCTIONS.checkRevokedUnicity, BLOCK_TEST_DATA.REVOKED_WITH_DUPLICATES, 'A single revocation per member is allowed'));
+  it('Block revoked keys must be in excluded',                                                      test(LOCAL_RULES_FUNCTIONS.checkRevokedAreExcluded, BLOCK_TEST_DATA.REVOKED_NOT_IN_EXCLUDED, 'A revoked member must be excluded'));
+  it('Block cannot contain 2 certifications from same issuer',                                      test(LOCAL_RULES_FUNCTIONS.checkCertificationOneByIssuer, BLOCK_TEST_DATA.MULTIPLE_CERTIFICATIONS_FROM_SAME_ISSUER, 'Block cannot contain two certifications from same issuer'));
+  it('Block cannot contain identical certifications',                                               test(LOCAL_RULES_FUNCTIONS.checkCertificationUnicity, BLOCK_TEST_DATA.IDENTICAL_CERTIFICATIONS, 'Block cannot contain identical certifications (A -> B)'));
+  it('Block cannot contain certifications concerning a leaver',                                     test(LOCAL_RULES_FUNCTIONS.checkCertificationIsntForLeaverOrExcluded, BLOCK_TEST_DATA.LEAVER_WITH_CERTIFICATIONS, 'Block cannot contain certifications concerning leavers or excluded members'));
+  it('Block cannot contain certifications concerning an excluded member',                           test(LOCAL_RULES_FUNCTIONS.checkCertificationIsntForLeaverOrExcluded, BLOCK_TEST_DATA.EXCLUDED_WITH_CERTIFICATIONS, 'Block cannot contain certifications concerning leavers or excluded members'));
+  it('Block cannot contain transactions without issuers (1)',                                       test(LOCAL_RULES_FUNCTIONS.checkTxIssuers, BLOCK_TEST_DATA.TRANSACTION_WITHOUT_ISSUERS, 'A transaction must have at least 1 issuer'));
+  it('Block cannot contain transactions without issuers (2)',                                       test(LOCAL_RULES_FUNCTIONS.checkTxSources, BLOCK_TEST_DATA.TRANSACTION_WITHOUT_SOURCES, 'A transaction must have at least 1 source'));
+  it('Block cannot contain transactions without issuers (3)',                                       test(LOCAL_RULES_FUNCTIONS.checkTxRecipients, BLOCK_TEST_DATA.TRANSACTION_WITHOUT_RECIPIENT, 'A transaction must have at least 1 recipient'));
+  it('Block cannot contain transactions with identical sources in one transaction',                 test(LOCAL_RULES_FUNCTIONS.checkTxSources, BLOCK_TEST_DATA.TRANSACTION_WITH_DUPLICATED_SOURCE_SINGLE_TX, 'It cannot exist 2 identical sources for transactions inside a given block'));
+  it('Block cannot contain transactions with identical sources in a pack of transactions',          test(LOCAL_RULES_FUNCTIONS.checkTxSources, BLOCK_TEST_DATA.TRANSACTION_WITH_DUPLICATED_SOURCE_MULTIPLE_TX, 'It cannot exist 2 identical sources for transactions inside a given block'));
+  it('Block cannot contain transactions with empty output conditions',                              test(LOCAL_RULES_FUNCTIONS.checkTxRecipients, BLOCK_TEST_DATA.TRANSACTION_WITH_EMPTY_TX_CONDITIONS, 'Empty conditions are forbidden'));
+  it('Block cannot contain transactions with wrong total',                                          test(LOCAL_RULES_FUNCTIONS.checkTxAmounts, BLOCK_TEST_DATA.TRANSACTION_WRONG_TOTAL, 'Transaction inputs sum must equal outputs sum'));
+  it('Block cannot contain transactions with wrong base transformation',                            test(LOCAL_RULES_FUNCTIONS.checkTxAmounts, BLOCK_TEST_DATA.TRANSACTION_WRONG_TRANSFORM, 'Transaction output base amount does not equal previous base deltas'));
+  it('Block cannot contain transactions with unexisting lower base in sources',                     test(LOCAL_RULES_FUNCTIONS.checkTxAmounts, BLOCK_TEST_DATA.TRANSACTION_WRONG_TRANSFORM_LOW_BASE, 'Transaction output base amount does not equal previous base deltas'));
+  it('Block cannot contain transactions with more than 100 lines',                                  test(LOCAL_RULES_FUNCTIONS.checkTxLen, BLOCK_TEST_DATA.TRANSACTION_TOO_LONG, 'A transaction has a maximum size of 100 lines'));
+  it('Block cannot contain transactions with a too large output',                                   test(LOCAL_RULES_FUNCTIONS.checkTxLen, BLOCK_TEST_DATA.OUTPUT_TOO_LONG, 'A transaction output has a maximum size of 2000 characters'));
+  it('Block cannot contain transactions with a too large unlock',                                   test(LOCAL_RULES_FUNCTIONS.checkTxLen, BLOCK_TEST_DATA.UNLOCK_TOO_LONG, 'A transaction unlock has a maximum size of 2000 characters'));
+  it('Block cannot be refused with a good V3 transaction',                                          test(LOCAL_RULES_FUNCTIONS.checkTxAmounts, BLOCK_TEST_DATA.TRANSACTION_V3_GOOD_AMOUNTS));
+  it('Block cannot contain transactions with wrong signatures',                                     test(LOCAL_RULES_FUNCTIONS.checkTxSignature, BLOCK_TEST_DATA.TRANSACTION_WITH_WRONG_SIGNATURES, 'Signature from a transaction must match'));
+  });
+  
+});
+
+
+function test (rule:any, raw:string, expectedMessage?:string) {
+  return async () => {
+    try {
+      let obj = parsers.parseBlock.syncWrite(raw);
+      let block = BlockDTO.fromJSONObject(obj);
+      let index = Indexer.localIndex(block, conf as any)
+      await rule(block, conf, index); // conf parameter is not always used
+      if (expectedMessage) {
+        throw 'Test should have thrown an error';
+      }
+    } catch (e) {
+      if (!expectedMessage) {
+        console.error(e.stack || e);
+      }
+      if (e.uerr) {
+        // This is a controlled error
+        e.uerr.message.should.equal(expectedMessage);
+      } else if (e) {
+        // This is a controlled error
+        e.message.should.equal(expectedMessage);
+      } else {
+        // throw Error(e)
+        // Display non wrapped errors (wrapped error is an error in constants.js)
+        // console.error(e.stack || e);
+      }
+    }
+  }
+}
diff --git a/test/fast/misc/cfs.ts b/test/fast/misc/cfs.ts
new file mode 100644
index 0000000000000000000000000000000000000000..db937d26e21806534ea77355bc40645009f0e01f
--- /dev/null
+++ b/test/fast/misc/cfs.ts
@@ -0,0 +1,137 @@
+// 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 {CFSCore} from "../../../app/lib/dal/fileDALs/CFSCore"
+import {MemFS} from "../../../app/lib/system/directory"
+
+const assert = require('assert')
+const should = require('should')
+
+const mockFS = MemFS({
+  'B5_a': {
+    "A.json": '{ "text": "Content of A from B5_a" }'
+  },
+  'B4': {
+    'B.json': '{ "text": "Content of B" }'
+  },
+  'B3': {
+    'A.json': '{ "text": "Content of A from B3" }',
+    'C.json': '{ "text": "Content of C from B3" }'
+  },
+  'OTHER': {
+    'X.json': '{ "text": "Content of X" }'
+  }
+});
+
+describe("CFS", () => {
+
+  const coreB3 = new CFSCore('/B3', mockFS);
+  const coreB4 = new CFSCore('/B4', mockFS);
+  const coreB5 = new CFSCore('/B5_a', mockFS);
+
+  const rootCore = new CFSCore('/OTHER', mockFS);
+
+  // ------------ Direct READ ------------
+
+  it('should have the content of A.json from B5', async () => {
+    const content = await coreB5.readJSON('A.json');
+    content.should.have.property('text').equal('Content of A from B5_a');
+  });
+
+  // WRITE of file /C.json
+
+  it('should have the content of C.json modified from B5 (direct read)', async () => {
+    await coreB5.writeJSON('C.json', { text: 'Content of C from B5_a'});
+    const content = await coreB5.readJSON('C.json');
+    content.should.have.property('text').equal('Content of C from B5_a');
+  });
+
+  // WRITE of file /D.json
+
+  it('should have the content of D.json modified from B4 (direct read/write)', async () => {
+    await coreB4.writeJSON('D.json', { text: 'Content of D'});
+    const content = await coreB4.readJSON('D.json');
+    content.should.have.property('text').equal('Content of D');
+  });
+
+  // REMOVE file /D.json
+
+  it('should have the content of D.json modified from B5 (direct read/write)', async () => {
+    const exists = await coreB5.exists('D.json');
+    const content = await coreB5.read('D.json');
+    assert.equal(exists, false);
+    assert.equal(content, null);
+  });
+
+  // ------------ LIST ------------
+
+  it('should have G,H,I as files from /DIR', async () => {
+    await coreB3.makeTree('/DIR');
+    await coreB4.makeTree('/DIR');
+    await coreB5.makeTree('/DIR');
+    await coreB3.writeJSON('/DIR/G.json', { text: 'Content of DIR/I'});
+    await coreB4.writeJSON('/DIR/H.json', { text: 'Content of DIR/H'});
+    await coreB5.writeJSON('/DIR/I.json', { text: 'Content of DIR/G'});
+    (await coreB3.list('/DIR')).should.deepEqual(['G.json']);
+    (await coreB4.list('/DIR')).should.deepEqual(['H.json']);
+    (await coreB5.list('/DIR')).should.deepEqual(['I.json']);
+  });
+
+  // WRITE of file /DIR2/I.json in B4
+
+  it('should have I as files from /DIR2', async () => {
+    await coreB3.makeTree('/DIR2');
+    await coreB3.writeJSON('/DIR2/I.json', { text: 'Content of DIR2/I in B4'});
+    const files = await coreB3.list('/DIR2');
+    files.should.have.length(1);
+    files.should.deepEqual(['I.json']);
+    // Check its contents
+    const contents = await coreB3.listJSON('/DIR2');
+    contents.should.have.length(1);
+    contents.should.deepEqual([{ text: 'Content of DIR2/I in B4' }]);
+  });
+
+  // REMOVE of file /DIR2/I.json in B5
+
+  it('should have no files from /DIR2 after file DELETION', async () => {
+    await coreB3.remove('/DIR2/I.json');
+    const files = await coreB3.list('/DIR2');
+    files.should.have.length(0);
+    // Check its contents
+    const contents = await coreB3.listJSON('/DIR2');
+    contents.should.have.length(0);
+  });
+
+  describe("Root core", () => {
+
+    it('should have 1 file in /OTHER folder', async () => {
+      const files = await rootCore.list('/');
+      files.should.have.length(1);
+      // Check its contents
+      const contents = await rootCore.listJSON('/');
+      contents.should.have.length(1);
+      contents.should.deepEqual([{ text: 'Content of X' }]);
+    });
+
+    // REMOVE of file /OTHER/X.json in rootCore
+
+    it('should have no files from /OTHER after file DELETION', async () => {
+      await rootCore.remove('/X.json');
+      const files = await rootCore.list('/');
+      files.should.have.length(0);
+      // Check its contents
+      const contents = await rootCore.listJSON('/');
+      contents.should.have.length(0);
+    });
+  });
+});
diff --git a/test/fast/database.js b/test/fast/misc/database.ts
similarity index 62%
rename from test/fast/database.js
rename to test/fast/misc/database.ts
index fcf6c5e6de26b0fa3f8667d42cf652e1675dee8c..aeda0ec89d46e47513159b548079108935e9f869 100644
--- a/test/fast/database.js
+++ b/test/fast/misc/database.ts
@@ -11,12 +11,10 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {SQLiteDriver} from "../../../app/lib/dal/drivers/SQLiteDriver"
 
-const co     = require('co');
-const tmp = require('tmp');
-const should = require('should');
-const SQLiteDriver = require('../../app/lib/dal/drivers/SQLiteDriver').SQLiteDriver
+const tmp = require('tmp')
+const should = require('should')
 
 const MEMORY = ':memory:';
 const FILE = tmp.fileSync().name + '.db'; // We add an suffix to avoid Windows-locking of the file by the `tmp` module
@@ -41,38 +39,38 @@ describe("SQLite driver", function() {
 
     let rows;
 
-    it('should be openable and closable on will', () => co(function*() {
+    it('should be openable and closable on will', async () => {
       const driver = new SQLiteDriver(MEMORY)
-      yield driver.executeSql(CREATE_TABLE_SQL);
-      rows = yield driver.executeAll(SELECT_FROM_TABLE, []);
+      await driver.executeSql(CREATE_TABLE_SQL);
+      rows = await driver.executeAll(SELECT_FROM_TABLE, []);
       rows.should.have.length(0);
 
       try {
         // We close the memory database, it should not remember its state
-        yield driver.closeConnection();
-        yield driver.executeAll(SELECT_FROM_TABLE, []);
+        await driver.closeConnection();
+        await driver.executeAll(SELECT_FROM_TABLE, []);
         throw 'Should have thrown an exception';
       } catch (err) {
         err.should.have.property('message').match(/SQLITE_ERROR: no such table: duniter/)
       }
       // But if we populate it again, it will work
-      yield driver.executeSql(CREATE_TABLE_SQL);
-      rows = yield driver.executeAll(SELECT_FROM_TABLE, []);
+      await driver.executeSql(CREATE_TABLE_SQL);
+      rows = await driver.executeAll(SELECT_FROM_TABLE, []);
       rows.should.have.length(0);
 
       try {
         // We explicitely ask for destruction
-        yield driver.destroyDatabase();
-        yield driver.executeAll(SELECT_FROM_TABLE, []);
+        await driver.destroyDatabase();
+        await driver.executeAll(SELECT_FROM_TABLE, []);
         throw 'Should have thrown an exception';
       } catch (err) {
         err.should.have.property('message').match(/SQLITE_ERROR: no such table: duniter/)
       }
       // But if we populate it again, it will work
-      yield driver.executeSql(CREATE_TABLE_SQL);
-      rows = yield driver.executeAll(SELECT_FROM_TABLE, []);
+      await driver.executeSql(CREATE_TABLE_SQL);
+      rows = await driver.executeAll(SELECT_FROM_TABLE, []);
       rows.should.have.length(0);
-    }));
+    })
   });
 
   describe("File", function() {
@@ -80,35 +78,35 @@ describe("SQLite driver", function() {
     const driver = new SQLiteDriver(FILE);
     let rows;
 
-    it('should be able to open a new one', () => co(function*() {
-      yield driver.executeSql(CREATE_TABLE_SQL);
-      rows = yield driver.executeAll(SELECT_FROM_TABLE, []);
+    it('should be able to open a new one', async () => {
+      await driver.executeSql(CREATE_TABLE_SQL);
+      rows = await driver.executeAll(SELECT_FROM_TABLE, []);
       rows.should.have.length(0);
-      yield driver.closeConnection();
-    }));
+      await driver.closeConnection();
+    })
 
-    it('should be able to reopen the file', () => co(function*() {
+    it('should be able to reopen the file', async () => {
       // Reopens the file
-      rows = yield driver.executeAll(SELECT_FROM_TABLE, []);
+      rows = await driver.executeAll(SELECT_FROM_TABLE, []);
       rows.should.have.length(0);
-    }));
+    })
 
-    it('should be able to remove the file', () => co(function*() {
+    it('should be able to remove the file', async () => {
       try {
         // We explicitely ask for destruction
-        yield driver.destroyDatabase();
-        yield driver.executeAll(SELECT_FROM_TABLE, []);
+        await driver.destroyDatabase();
+        await driver.executeAll(SELECT_FROM_TABLE, []);
         throw 'Should have thrown an exception';
       } catch (err) {
         err.should.have.property('message').match(/SQLITE_ERROR: no such table: duniter/)
       }
-    }));
+    })
 
-    it('should be able to open the file after being removed', () => co(function*() {
+    it('should be able to open the file after being removed', async () => {
       // But if we populate it again, it will work
-      yield driver.executeSql(CREATE_TABLE_SQL);
-      rows = yield driver.executeAll(SELECT_FROM_TABLE, []);
+      await driver.executeSql(CREATE_TABLE_SQL);
+      rows = await driver.executeAll(SELECT_FROM_TABLE, []);
       rows.should.have.length(0);
-    }));
-  });
-});
+    })
+  })
+})
diff --git a/test/fast/entities.js b/test/fast/misc/entities.ts
similarity index 88%
rename from test/fast/entities.js
rename to test/fast/misc/entities.ts
index 4f5656354432f451b788c8d27d5fc0eb4f04f428..542e7d54145f2f820386918b76764076e93036db 100644
--- a/test/fast/entities.js
+++ b/test/fast/misc/entities.ts
@@ -11,9 +11,9 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
-let should = require('should');
-let BlockDTO = require('../../app/lib/dto/BlockDTO').BlockDTO
+import {BlockDTO} from "../../../app/lib/dto/BlockDTO"
+
+const should = require('should');
 
 describe('Entities', () => {
 
diff --git a/test/fast/merkle.js b/test/fast/misc/merkle.ts
similarity index 91%
rename from test/fast/merkle.js
rename to test/fast/misc/merkle.ts
index b93e6823d69ef147d6914ff167216033cea57b87..503ad947ec8dd2d1787e027e40a85ad33b4482bf 100644
--- a/test/fast/merkle.js
+++ b/test/fast/misc/merkle.ts
@@ -11,15 +11,14 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
-var should   = require('should');
-var assert   = require('assert');
+import {MerkleDTO} from "../../../app/lib/dto/MerkleDTO"
 
-var MerkleDTO = require('../../app/lib/dto/MerkleDTO').MerkleDTO
+const should = require('should');
+const assert = require('assert');
 
 describe("Merkle ['a', 'b', 'c', 'd', 'e']", function(){
 
-  var m = new MerkleDTO();
+  const m = new MerkleDTO() as any
   m.initialize(['a', 'b', 'c', 'd', 'e']);
 
   it('should have root 16E6BEB3E080910740A2923D6091618CAA9968AEAD8A52D187D725D199548E2C', function(){
@@ -53,7 +52,7 @@ describe("Merkle ['a', 'b', 'c', 'd', 'e']", function(){
 
 describe("Merkle []", function(){
 
-  var m = new MerkleDTO();
+  const m = new MerkleDTO() as any
   m.initialize([]);
 
   it('should have root empty', function(){
diff --git a/test/fast/modules/bma/ddos-test.js b/test/fast/modules/bma/bma-ddos-test.ts
similarity index 98%
rename from test/fast/modules/bma/ddos-test.js
rename to test/fast/modules/bma/bma-ddos-test.ts
index 7c1ab98a148a04c54005f6f3f7e916eaaa582e1c..0a3b551f3507964d480c8ef63dca151a47b7a136 100644
--- a/test/fast/modules/bma/ddos-test.js
+++ b/test/fast/modules/bma/bma-ddos-test.ts
@@ -13,7 +13,6 @@
 
 "use strict";
 // const should = require('should');
-// const co = require('co');
 // const limiter = require('../../app/lib/system/limiter');
 // const toolbox = require('../integration/tools/toolbox');
 // const TestUser = require('../integration/tools/TestUser').TestUser
diff --git a/test/fast/modules/bma/limiter-test.js b/test/fast/modules/bma/bma-limiter-test.ts
similarity index 98%
rename from test/fast/modules/bma/limiter-test.js
rename to test/fast/modules/bma/bma-limiter-test.ts
index f63ae5c4a7253155a11a0970fe7483ec98ffd864..cdc113d90f5d7daeaad3e38fe83e3780ddf51162 100644
--- a/test/fast/modules/bma/limiter-test.js
+++ b/test/fast/modules/bma/bma-limiter-test.ts
@@ -13,7 +13,6 @@
 
 "use strict";
 // const should = require('should');
-// const co = require('co');
 // const limiter = require('../lib/limiter');
 // const toolbox = require('../integration/tools/toolbox');
 // const TestUser = require('../integration/tools/TestUser').TestUser
diff --git a/test/fast/modules/bma/module-test.js b/test/fast/modules/bma/bma-module-test.ts
similarity index 67%
rename from test/fast/modules/bma/module-test.js
rename to test/fast/modules/bma/bma-module-test.ts
index 08c5757734c6b9c4a4e24cf645a4c192585043ed..4e85f3973022d4adb69fa9abece2d2946d7001ea 100644
--- a/test/fast/modules/bma/module-test.js
+++ b/test/fast/modules/bma/bma-module-test.ts
@@ -11,141 +11,139 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {BmaDependency} from "../../../../app/modules/bma/index"
+import {KeypairDependency} from "../../../../app/modules/keypair/index"
+import {Network} from "../../../../app/modules/bma/lib/network"
+
 const assert = require('assert');
 const should = require('should');
-const co  = require('co');
-const duniterBMA = require('../../../../app/modules/bma/index').BmaDependency
-const duniterKeypair = require('../../../../app/modules/keypair').KeypairDependency
-const network = require('../../../../app/modules/bma/lib/network').Network
 const duniter = require('../../../../index')
-const logger = require('../../../../app/lib/logger').NewLogger()
 const rp = require('request-promise');
 
 const stack = duniter.statics.minimalStack();
-stack.registerDependency(duniterKeypair, 'duniter-keypair');
-stack.registerDependency(duniterBMA,     'duniter-bma');
+stack.registerDependency(KeypairDependency, 'duniter-keypair');
+stack.registerDependency(BmaDependency,     'duniter-bma');
 
 describe('Module usage', () => {
 
-  it('/node/summary should answer', () => co(function*() {
+  it('/node/summary should answer', async () => {
     stack.registerDependency({
       duniter: {
         cli: [{
           name: 'test1',
           desc: 'Unit Test execution',
-          onDatabaseExecute: (server, conf, program, params, startServices) => co(function*() {
-            yield startServices();
-          })
+          onDatabaseExecute: async (server:any, conf:any, program:any, params:any, startServices:any) => {
+            await startServices();
+          }
         }]
       }
     }, 'duniter-automated-test');
-    yield stack.executeStack(['node', 'index.js', 'test1',
+    await stack.executeStack(['node', 'index.js', 'test1',
       '--memory',
       '--noupnp',
       '--ipv4', '127.0.0.1',
       '--port', '10400'
     ]);
-    const json = yield rp.get({
+    const json = await rp.get({
       url: 'http://127.0.0.1:10400/node/summary',
       json: true,
       timeout: 1000
     });
     should.exist(json);
     json.should.have.property('duniter').property('software').equal('duniter');
-  }));
+  })
 
-  it('remoteipv4 should NOT be filled if remote Host is declared', () => co(function*() {
+  it('remoteipv4 should NOT be filled if remote Host is declared', async () => {
     stack.registerDependency({
       duniter: {
         cli: [{
           name: 'test2',
           desc: 'Unit Test execution',
-          onConfiguredExecute: (server, conf, program, params, startServices) => co(function*() {
+          onConfiguredExecute: async (server:any, conf:any, program:any, params:any, startServices:any) => {
             conf.should.not.have.property('remoteipv4');
             conf.should.have.property('remoteipv6').equal(undefined);
             conf.should.have.property('remotehost').equal('localhost');
-          })
+          }
         }]
       }
     }, 'duniter-automated-test');
-    yield stack.executeStack(['node', 'index.js', 'test2',
+    await stack.executeStack(['node', 'index.js', 'test2',
       '--memory',
       '--ipv4',    '127.0.0.1',
       '--remoteh', 'localhost',
       '--port',    '10400'
     ]);
-  }));
+  })
 
-  it('remoteipv4 should NOT be filled if remote IPv6 is declared', () => co(function*() {
+  it('remoteipv4 should NOT be filled if remote IPv6 is declared', async () => {
     stack.registerDependency({
       duniter: {
         cli: [{
           name: 'test3',
           desc: 'Unit Test execution',
-          onConfiguredExecute: (server, conf, program, params, startServices) => co(function*() {
+          onConfiguredExecute: async (server:any, conf:any, program:any, params:any, startServices:any) => {
             conf.should.not.have.property('remoteipv4');
             conf.should.not.have.property('remotehost');
             conf.should.have.property('remoteipv6').equal('::1');
-          })
+          }
         }]
       }
     }, 'duniter-automated-test');
-    yield stack.executeStack(['node', 'index.js', 'test3',
+    await stack.executeStack(['node', 'index.js', 'test3',
       '--memory',
       '--ipv4',    '127.0.0.1',
       '--ipv6', '::1',
       '--port', '10400'
     ]);
-  }));
+  })
 
-  it('remoteipv4 should be NOT be auto-filled if manual remoteipv4 is declared', () => co(function*() {
+  it('remoteipv4 should be NOT be auto-filled if manual remoteipv4 is declared', async () => {
     stack.registerDependency({
       duniter: {
         cli: [{
           name: 'test4',
           desc: 'Unit Test execution',
-          onConfiguredExecute: (server, conf, program, params, startServices) => co(function*() {
+          onConfiguredExecute: async (server:any, conf:any, program:any, params:any, startServices:any) => {
             conf.should.not.have.property('remotehost');
             conf.should.have.property('remoteipv6').equal(undefined);
             conf.should.have.property('remoteipv4').equal('192.168.0.1');
-          })
+          }
         }]
       }
     }, 'duniter-automated-test');
-    yield stack.executeStack(['node', 'index.js', 'test4',
+    await stack.executeStack(['node', 'index.js', 'test4',
       '--memory',
       '--remote4', '192.168.0.1',
       '--ipv4', '127.0.0.1',
       '--port', '10400'
     ]);
-  }));
+  })
 
-  it('remoteipv4 should be filled if no remote is declared, but local IPv4 is', () => co(function*() {
+  it('remoteipv4 should be filled if no remote is declared, but local IPv4 is', async () => {
     stack.registerDependency({
       duniter: {
         cli: [{
           name: 'test5',
           desc: 'Unit Test execution',
-          onConfiguredExecute: (server, conf, program, params, startServices) => co(function*() {
+          onConfiguredExecute: async (server:any, conf:any, program:any, params:any, startServices:any) => {
             conf.should.not.have.property('remotehost');
             conf.should.have.property('remoteipv6').equal(undefined);
             conf.should.have.property('remoteipv4').equal('127.0.0.1');
-          })
+          }
         }]
       }
     }, 'duniter-automated-test');
-    yield stack.executeStack(['node', 'index.js', 'test5',
+    await stack.executeStack(['node', 'index.js', 'test5',
       '--memory',
       '--ipv4', '127.0.0.1',
       '--port', '10400'
     ]);
-  }));
+  })
 
-  it('default IPv6 should not be a local one', () => co(function*() {
-    const ipv6 = network.getBestLocalIPv6();
+  it('default IPv6 should not be a local one', async () => {
+    const ipv6 = Network.getBestLocalIPv6();
     if (ipv6) {
       ipv6.should.not.match(/fe80/);
     }
-  }));
-});
+  })
+})
diff --git a/test/fast/modules/common/crypto.js b/test/fast/modules/common/common-crypto-test.ts
similarity index 61%
rename from test/fast/modules/common/crypto.js
rename to test/fast/modules/common/common-crypto-test.ts
index 3a275f00f4069c388899ea2832cff44ebf9240cc..092e8d1cbe3d2c3267f2952ce961815848176cdc 100644
--- a/test/fast/modules/common/crypto.js
+++ b/test/fast/modules/common/common-crypto-test.ts
@@ -11,28 +11,23 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
-const should = require('should');
-const co  = require('co');
-const nacl   = require('tweetnacl');
-const base58 = require('../../../../app/lib/common-libs').base58
-const keyring      = require('../../../../app/lib/common-libs/crypto/keyring');
+import {KeyGen, verify} from "../../../../app/lib/common-libs/crypto/keyring"
+import {Base58decode, Base58encode} from "../../../../app/lib/common-libs/crypto/base58"
 
-const enc = require('../../../../app/lib/common-libs/crypto/nacl-util').encodeBase64,
-       dec = require('../../../../app/lib/common-libs/crypto/nacl-util').decodeBase64
+const should = require('should');
 
-let pub, sec, rawPub, rawSec;
+let pub:Uint8Array, sec:Uint8Array, rawPub:string, rawSec:string
 
 describe('ed25519 tests:', function(){
 
-  before(() => co(function*() {
+  before(async () => {
     // Generate the keypair
-    const keyPair = keyring.KeyGen('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP');
-    pub = base58.decode(keyPair.publicKey);
-    sec = base58.decode(keyPair.secretKey);
-    rawPub = base58.encode(pub);
-    rawSec = base58.encode(sec);
-  }));
+    const keyPair = KeyGen('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP');
+    pub = Base58decode(keyPair.publicKey);
+    sec = Base58decode(keyPair.secretKey);
+    rawPub = Base58encode(pub);
+    rawSec = Base58encode(sec);
+  })
 
   //it('good signature from existing secret key should be verified', function(done){
   //  const keys = nacl.sign.scryptKeyPair.fromSecretKey(dec("TM0Imyj/ltqdtsNG7BFOD1uKMZ81q6Yk2oz27U+4pvs9QBfD6EOJWpK3CqdNG368nJgszy7ElozAzVXxKvRmDA=="));
@@ -46,17 +41,16 @@ describe('ed25519 tests:', function(){
 
   it('good signature from generated key should be verified', function(done){
     const msg = "Some message to be signed";
-    const sig = keyring.KeyGen(rawPub, rawSec).signSync(msg);
-    const verified = keyring.verify(msg, sig, rawPub);
+    const sig = KeyGen(rawPub, rawSec).signSync(msg);
+    const verified = verify(msg, sig, rawPub);
     verified.should.equal(true);
     done();
   });
 
   it('wrong signature from generated key should NOT be verified', function(done){
     const msg = "Some message to be signed";
-    const cor = dec(enc(msg) + 'delta');
-    const sig = keyring.KeyGen(rawPub, rawSec).signSync(msg);
-    const verified = keyring.verify(cor, sig, rawPub);
+    const sig = KeyGen(rawPub, rawSec).signSync(msg);
+    const verified = verify(msg + 'delta', sig, rawPub);
     verified.should.equal(false);
     done();
   });
diff --git a/test/fast/modules/common/peering.js b/test/fast/modules/common/common-peering-test.ts
similarity index 93%
rename from test/fast/modules/common/peering.js
rename to test/fast/modules/common/common-peering-test.ts
index 954575e2460edad6fcc9d78826f1030270239719..9f3c4cea679fac09ef580c60f307258c670af24e 100644
--- a/test/fast/modules/common/peering.js
+++ b/test/fast/modules/common/common-peering-test.ts
@@ -11,11 +11,11 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {PeerDTO} from "../../../../app/lib/dto/PeerDTO"
+import {parsers} from "../../../../app/lib/common-libs/parsers/index"
+
 const should   = require('should');
 const assert   = require('assert');
-const parsers  = require('../../../../app/lib/common-libs/parsers').parsers
-const PeerDTO = require('../../../../app/lib/dto/PeerDTO').PeerDTO
 
 const rawPeer = "" +
   "Version: 10\n" +
@@ -32,7 +32,7 @@ describe('Peer', function(){
 
   describe('of some key', function(){
 
-    var pr;
+    let pr:any
 
     before(function(done) {
       pr = PeerDTO.fromJSONObject(parsers.parsePeer.syncWrite(rawPeer))
diff --git a/test/fast/modules/common/randomKey.js b/test/fast/modules/common/common-random-key.ts
similarity index 61%
rename from test/fast/modules/common/randomKey.js
rename to test/fast/modules/common/common-random-key.ts
index 0aabe14a27086d506b0253c9be9338cd94c4bce7..172154b8d23d52953843b058a6c3343289e8e0b1 100644
--- a/test/fast/modules/common/randomKey.js
+++ b/test/fast/modules/common/common-random-key.ts
@@ -11,38 +11,31 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
-const should = require('should');
-const co  = require('co');
-const nacl   = require('tweetnacl');
-const keyring      = require('../../../../app/lib/common-libs/crypto/keyring');
-
+import {Key, KeyGen, randomKey, verify} from "../../../../app/lib/common-libs/crypto/keyring"
 
-const enc = require('../../../../app/lib/common-libs/crypto/nacl-util').encodeBase64,
-  dec = require('../../../../app/lib/common-libs/crypto/nacl-util').decodeBase64
+const should = require('should');
 
-let key;
+let key:Key
 
 describe('Random keypair', function(){
 
-  before(() => co(function*() {
+  before(async () => {
     // Generate the keypair
-    key = keyring.randomKey()
-  }));
+    key = randomKey()
+  })
 
   it('good signature from generated key should be verified', function(done){
     const msg = "Some message to be signed";
-    const sig = keyring.KeyGen(key.publicKey, key.secretKey).signSync(msg);
-    const verified = keyring.verify(msg, sig, key.publicKey);
+    const sig = KeyGen(key.publicKey, key.secretKey).signSync(msg);
+    const verified = verify(msg, sig, key.publicKey);
     verified.should.equal(true);
     done();
   });
 
   it('wrong signature from generated key should NOT be verified', function(done){
     const msg = "Some message to be signed";
-    const cor = dec(enc(msg) + 'delta');
-    const sig = keyring.KeyGen(key.publicKey, key.secretKey).signSync(msg);
-    const verified = keyring.verify(cor, sig, key.publicKey);
+    const sig = KeyGen(key.publicKey, key.secretKey).signSync(msg);
+    const verified = verify(msg + 'delta', sig, key.publicKey);
     verified.should.equal(false);
     done();
   });
diff --git a/test/fast/modules/common/tx_format.js b/test/fast/modules/common/common-tx-format.ts
similarity index 88%
rename from test/fast/modules/common/tx_format.js
rename to test/fast/modules/common/common-tx-format.ts
index 5b0df732bcb24ee3babcb48941951a5b00f8f060..6c958119c9a3d9e33af4a6acc578acb3979cebf6 100644
--- a/test/fast/modules/common/tx_format.js
+++ b/test/fast/modules/common/common-tx-format.ts
@@ -11,11 +11,11 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
-var should  = require('should');
-var parsers = require('../../../../app/lib/common-libs/parsers').parsers
+import {parsers} from "../../../../app/lib/common-libs/parsers/index"
 
-var raw = "Version: 10\n" +
+const should  = require('should');
+
+const raw = "Version: 10\n" +
     "Type: Transaction\n" +
     "Currency: test_net\n" +
     "Blockstamp: 3-2A27BD040B16B7AF59DDD88890E616987F4DD28AA47B9ABDBBEE46257B88E945\n" +
@@ -34,7 +34,7 @@ var raw = "Version: 10\n" +
 
 describe("Transaction format", function(){
 
-    var parser = parsers.parseTransaction;
+    const parser = parsers.parseTransaction;
 
     it('a valid block should be well formatted', () => parser.syncWrite(raw));
 
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/modules/crawler/peers_garbaging.js b/test/fast/modules/crawler/crawler-peers-garbaging.ts
similarity index 58%
rename from test/fast/modules/crawler/peers_garbaging.js
rename to test/fast/modules/crawler/crawler-peers-garbaging.ts
index 4d44184db5b6171a2dff1dbb7ba8aaddb8cd9489..9bb881fc823aa43c9f632bd2e0ad711b68cac808 100644
--- a/test/fast/modules/crawler/peers_garbaging.js
+++ b/test/fast/modules/crawler/crawler-peers-garbaging.ts
@@ -11,14 +11,13 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
-const should = require('should');
-const co = require('co');
+import {cleanLongDownPeers} from "../../../../app/modules/crawler/lib/garbager"
+import {Server} from "../../../../server"
 
-const garbager = require('../../../../app/modules/crawler/lib/garbager')
+const should = require('should');
 const duniter = require('../../../../index')
 
-let stack
+let stack:any
 
 describe('Peers garbaging', () => {
 
@@ -33,23 +32,23 @@ describe('Peers garbaging', () => {
             name: 'garbage',
             desc: 'Garbage testing',
             logs: false,
-            onDatabaseExecute: (server, conf, program, params) => co(function*() {
-              yield server.dal.peerDAL.savePeer({ pubkey: 'A', version: 1, currency: 'c', first_down: null,          statusTS: 1485000000000, block: '2393-H' });
-              yield server.dal.peerDAL.savePeer({ pubkey: 'B', version: 1, currency: 'c', first_down: 1484827199999, statusTS: 1485000000000, block: '2393-H' });
-              yield server.dal.peerDAL.savePeer({ pubkey: 'C', version: 1, currency: 'c', first_down: 1484827200000, statusTS: 1485000000000, block: '2393-H' });
-              yield server.dal.peerDAL.savePeer({ pubkey: 'D', version: 1, currency: 'c', first_down: 1484820000000, statusTS: 1485000000000, block: '2393-H' });
-              (yield server.dal.peerDAL.sqlListAll()).should.have.length(4);
+            onDatabaseExecute: async (server:Server) => {
+              await server.dal.peerDAL.savePeer({ pubkey: 'A', version: 1, currency: 'c', first_down: null,          statusTS: 1485000000000, block: '2393-H' } as any);
+              await server.dal.peerDAL.savePeer({ pubkey: 'B', version: 1, currency: 'c', first_down: 1484827199999, statusTS: 1485000000000, block: '2393-H' } as any);
+              await server.dal.peerDAL.savePeer({ pubkey: 'C', version: 1, currency: 'c', first_down: 1484827200000, statusTS: 1485000000000, block: '2393-H' } as any);
+              await server.dal.peerDAL.savePeer({ pubkey: 'D', version: 1, currency: 'c', first_down: 1484820000000, statusTS: 1485000000000, block: '2393-H' } as any);
+              (await server.dal.peerDAL.listAll()).should.have.length(4);
               const now = 1485000000000;
-              yield garbager.cleanLongDownPeers(server, now);
-              (yield server.dal.peerDAL.sqlListAll()).should.have.length(2);
-            })
+              await cleanLongDownPeers(server, now);
+              (await server.dal.peerDAL.listAll()).should.have.length(2);
+            }
           }]
         }
       }
     }]);
   })
 
-  it('should be able to garbage some peers', () => co(function*() {
-    yield stack.executeStack(['node', 'b.js', '--memory', 'garbage']);
-  }));
-});
+  it('should be able to garbage some peers', async () => {
+    await stack.executeStack(['node', 'b.js', '--memory', 'garbage']);
+  })
+})
diff --git a/test/fast/modules/keypair/crypto-test.js b/test/fast/modules/keypair/keypair-crypto-test.ts
similarity index 77%
rename from test/fast/modules/keypair/crypto-test.js
rename to test/fast/modules/keypair/keypair-crypto-test.ts
index 3ea1686dae7c8a4c7a55c90fbb393b60cfee1e23..1424c649e671eec4885987c3de6bebad613b8595 100644
--- a/test/fast/modules/keypair/crypto-test.js
+++ b/test/fast/modules/keypair/keypair-crypto-test.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 {Scrypt} from "../../../../app/modules/keypair/lib/scrypt"
+
 const should = require('should');
-const co  = require('co');
-const scrypt = require('../../../../app/modules/keypair/lib/scrypt').Scrypt
 
 describe('Scrypt salt // key', () => {
 
-  it('abc // abc', () => co(function*() {
-    const pair = yield scrypt('abc', 'abc');
+  it('abc // abc', async () => {
+    const pair = await Scrypt('abc', 'abc');
     pair.should.have.property('pub').equal('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
     pair.should.have.property('sec').equal('51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP');
-  }));
+  })
 
-  it('abc // def', () => co(function*() {
-    const pair = yield scrypt('abc', 'def');
+  it('abc // def', async () => {
+    const pair = await Scrypt('abc', 'def');
     pair.should.have.property('pub').equal('G2CBgZBPLe6FSFUgpx2Jf1Aqsgta6iib3vmDRA1yLiqU');
     pair.should.have.property('sec').equal('58LDg8QLmF5pv6Dn9h7X4yFKfMTdP8fdAiWVcyDoTRJu454fwRihCLULH4MW37zncsg4ruoTGJPZneWk22QmG1w4');
-  }));
+  })
 
-  it('azerty // def', () => co(function*() {
-    const pair = yield scrypt('azerty', 'def');
+  it('azerty // def', async () => {
+    const pair = await Scrypt('azerty', 'def');
     pair.should.have.property('pub').equal('3dbw4NYVEm5mwTH6bFrqBhan1k39qNHubkQWdrw2C5AD');
     pair.should.have.property('sec').equal('4kemdi17CPkkBPnjXiPFf6oBhdGiiqhCL3R4Tuafe9THK8mzBs1evHw5r9u3f8xts2zn6VCBJYVrRMzdaEaWn5Ch');
-  }));
-});
+  })
+})
diff --git a/test/fast/modules/keypair/module-test.js b/test/fast/modules/keypair/keypair-module-test.ts
similarity index 75%
rename from test/fast/modules/keypair/module-test.js
rename to test/fast/modules/keypair/keypair-module-test.ts
index 7ea191e6ecbad9cbccbce817a7f16dee85f30e55..2b5f5db651266070c6591a4ea30e9590f737f737 100644
--- a/test/fast/modules/keypair/module-test.js
+++ b/test/fast/modules/keypair/keypair-module-test.ts
@@ -11,34 +11,32 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {KeypairDependency} from "../../../../app/modules/keypair/index"
+
 const should = require('should');
-const co  = require('co');
-const keypair = require('../../../../app/modules/keypair/index').KeypairDependency
-const assert = require('assert');
 const duniter = require('../../../../index')
 
 describe('Module usage', () => {
 
-  it('wrong options should throw', () => co(function*() {
+  it('wrong options should throw', async () => {
     let errMessage;
     try {
       const stack = duniter.statics.minimalStack();
-      stack.registerDependency(keypair, 'duniter-keypair');
-      yield stack.executeStack(['node', 'index.js', 'config', '--memory', '--keyN', '2048']);
+      stack.registerDependency(KeypairDependency, 'duniter-keypair');
+      await stack.executeStack(['node', 'index.js', 'config', '--memory', '--keyN', '2048']);
     } catch (e) {
       errMessage = e.message;
     }
     should.exist(errMessage);
     should.equal(errMessage, 'Missing --salt and --passwd options along with --keyN|keyr|keyp option');
-  }));
+  })
 
-  it('no options on brand new node should generate random key', () => co(function*() {
+  it('no options on brand new node should generate random key', async () => {
     const stack = duniter.statics.minimalStack();
-    stack.registerDependency(keypair, 'duniter-keypair');
-    const res = yield stack.executeStack(['node', 'index.js', 'config', '--memory']);
+    stack.registerDependency(KeypairDependency, 'duniter-keypair');
+    const res = await stack.executeStack(['node', 'index.js', 'config', '--memory']);
     // This is extremely very unlikely to happen
     res.pair.should.have.property('pub').not.equal('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
     res.pair.should.have.property('sec').not.equal('51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP');
-  }));
-});
+  })
+})
diff --git a/test/fast/protocol-brg107-udEffectiveTime.js b/test/fast/protocol-brg107-udEffectiveTime.js
deleted file mode 100644
index 80a724935d3b52d639ff9a1ef787aeb87e93213d..0000000000000000000000000000000000000000
--- a/test/fast/protocol-brg107-udEffectiveTime.js
+++ /dev/null
@@ -1,53 +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 indexer       = require('../../app/lib/indexer').Indexer
-
-describe("Protocol BR_G107 - udReevalTime", function(){
-
-  it('root block good udReevalTime', () => co(function*(){
-    const conf   = { udReevalTime0: 1500000000 };
-    const HEAD_1 = null;
-    const HEAD   = { number: 0 };
-    indexer.prepareUDTime(HEAD, HEAD_1, conf);
-    HEAD.udReevalTime.should.equal(conf.udReevalTime0);
-  }));
-
-  it('block with medianTime < udReevalTime', () => co(function*(){
-    const conf   = { dt: 100, dtReeval: 20 };
-    const HEAD_1 = { number: 59, udReevalTime: 1500000900 };
-    const HEAD   = { number: 60, medianTime:   1500000899 };
-    indexer.prepareUDTime(HEAD, HEAD_1, conf);
-    HEAD.udReevalTime.should.equal(HEAD_1.udReevalTime);
-  }));
-
-  it('block with medianTime == udReevalTime', () => co(function*(){
-    const conf   = { dt: 100, dtReeval: 20 };
-    const HEAD_1 = { number: 59, udReevalTime: 1500000900 };
-    const HEAD   = { number: 60, medianTime:   1500000900 };
-    indexer.prepareUDTime(HEAD, HEAD_1, conf);
-    HEAD.udReevalTime.should.equal(HEAD_1.udReevalTime + conf.dtReeval);
-  }));
-
-  it('block with medianTime > udReevalTime', () => co(function*(){
-    const conf   = { dt: 100, dtReeval: 20 };
-    const HEAD_1 = { number: 59, udReevalTime: 1500000900 };
-    const HEAD   = { number: 60, medianTime:   1500000901 };
-    indexer.prepareUDTime(HEAD, HEAD_1, conf);
-    HEAD.udReevalTime.should.equal(HEAD_1.udReevalTime + conf.dtReeval);
-  }));
-
-});
diff --git a/test/fast/protocol-brg11-udTime.js b/test/fast/protocol-brg11-udTime.js
deleted file mode 100644
index 9899b5b50fe7e0d2bc3cc771c33052ba33fdf76a..0000000000000000000000000000000000000000
--- a/test/fast/protocol-brg11-udTime.js
+++ /dev/null
@@ -1,53 +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 indexer       = require('../../app/lib/indexer').Indexer
-
-describe("Protocol BR_G11 - udTime", function(){
-
-  it('root block good udTime', () => co(function*(){
-    const conf   = { udTime0: 1500000000 };
-    const HEAD_1 = null;
-    const HEAD   = { number: 0 };
-    indexer.prepareUDTime(HEAD, HEAD_1, conf);
-    HEAD.udTime.should.equal(conf.udTime0);
-  }));
-
-  it('block with medianTime < udTime', () => co(function*(){
-    const conf   = { dt: 100 };
-    const HEAD_1 = { number: 59, udTime:     1500000900 };
-    const HEAD   = { number: 60, medianTime: 1500000899 };
-    indexer.prepareUDTime(HEAD, HEAD_1, conf);
-    HEAD.udTime.should.equal(HEAD_1.udTime);
-  }));
-
-  it('block with medianTime == udTime', () => co(function*(){
-    const conf   = { dt: 100 };
-    const HEAD_1 = { number: 59, udTime:     1500000900 };
-    const HEAD   = { number: 60, medianTime: 1500000900 };
-    indexer.prepareUDTime(HEAD, HEAD_1, conf);
-    HEAD.udTime.should.equal(HEAD_1.udTime + conf.dt);
-  }));
-
-  it('block with medianTime > udTime', () => co(function*(){
-    const conf   = { dt: 100 };
-    const HEAD_1 = { number: 59, udTime:     1500000900 };
-    const HEAD   = { number: 60, medianTime: 1500000901 };
-    indexer.prepareUDTime(HEAD, HEAD_1, conf);
-    HEAD.udTime.should.equal(HEAD_1.udTime + conf.dt);
-  }));
-
-});
diff --git a/test/fast/protocol-brg49-version.js b/test/fast/protocol-brg49-version.js
deleted file mode 100644
index 151134e3a78f57056d268cbf18a102708a30f739..0000000000000000000000000000000000000000
--- a/test/fast/protocol-brg49-version.js
+++ /dev/null
@@ -1,47 +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 indexer       = require('../../app/lib/indexer').Indexer
-
-const FAIL = false;
-const SUCCESS = true;
-
-describe("Protocol BR_G49 - Version", function(){
-
-  it('V13 following V12 should fail', () => co(function*(){
-    const HEAD_1 = { number: 17, version: 13 };
-    const HEAD   = { number: 18, version: 12 };
-    indexer.ruleVersion(HEAD, HEAD_1).should.equal(FAIL);
-  }));
-
-  it('V14 following V12 should fail', () => co(function*(){
-    const HEAD_1 = { number: 17, version: 14 };
-    const HEAD   = { number: 18, version: 12 };
-    indexer.ruleVersion(HEAD, HEAD_1).should.equal(FAIL);
-  }));
-
-  it('V13 following V14 should succeed', () => co(function*(){
-    const HEAD_1 = { number: 17, version: 13 };
-    const HEAD   = { number: 18, version: 14 };
-    indexer.ruleVersion(HEAD, HEAD_1).should.equal(SUCCESS);
-  }));
-
-  it('V13 following V15 should fail', () => co(function*(){
-    const HEAD_1 = { number: 17, version: 13 };
-    const HEAD   = { number: 18, version: 15 };
-    indexer.ruleVersion(HEAD, HEAD_1).should.equal(FAIL);
-  }));
-});
diff --git a/test/fast/protocol-brg50-blocksize.js b/test/fast/protocol-brg50-blocksize.js
deleted file mode 100644
index 8d19f9e3472847526ca5feb9db26ba755d3eb595..0000000000000000000000000000000000000000
--- a/test/fast/protocol-brg50-blocksize.js
+++ /dev/null
@@ -1,68 +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 indexer       = require('../../app/lib/indexer').Indexer
-
-const FAIL = false;
-const SUCCESS = true;
-
-describe("Protocol BR_G50 - Block size", function(){
-
-  it('2 for an AVG(10) should succeed', () => co(function*(){
-    const HEAD   = { number: 24, bsize: 2, avgBlockSize: 10 };
-    indexer.ruleBlockSize(HEAD).should.equal(SUCCESS);
-  }));
-
-  it('400 for an AVG(10) should succeed', () => co(function*(){
-    const HEAD   = { number: 24, bsize: 400, avgBlockSize: 10 };
-    indexer.ruleBlockSize(HEAD).should.equal(SUCCESS);
-  }));
-
-  it('499 for an AVG(10) should succeed', () => co(function*(){
-    const HEAD   = { number: 24, bsize: 499, avgBlockSize: 10 };
-    indexer.ruleBlockSize(HEAD).should.equal(SUCCESS);
-  }));
-
-  it('500 for an AVG(10) should fail', () => co(function*(){
-    const HEAD   = { number: 24, bsize: 500, avgBlockSize: 10 };
-    indexer.ruleBlockSize(HEAD).should.equal(FAIL);
-  }));
-
-  it('500 for an AVG(454) should fail', () => co(function*(){
-    const HEAD   = { number: 24, bsize: 500, avgBlockSize: 454 };
-    indexer.ruleBlockSize(HEAD).should.equal(FAIL);
-  }));
-
-  it('500 for an AVG(455) should succeed', () => co(function*(){
-    const HEAD   = { number: 24, bsize: 500, avgBlockSize: 455 };
-    indexer.ruleBlockSize(HEAD).should.equal(SUCCESS);
-  }));
-
-  it('1100 for an AVG(1000) should fail', () => co(function*(){
-    const HEAD   = { number: 24, bsize: 1100, avgBlockSize: 1000 };
-    indexer.ruleBlockSize(HEAD).should.equal(FAIL);
-  }));
-
-  it('1100 for an AVG(1001) should succeed', () => co(function*(){
-    const HEAD   = { number: 24, bsize: 1100, avgBlockSize: 1001 };
-    indexer.ruleBlockSize(HEAD).should.equal(SUCCESS);
-  }));
-
-  it('1100 for block#0 should succeed', () => co(function*(){
-    const HEAD   = { number: 0, bsize: 1100, avgBlockSize: 0 };
-    indexer.ruleBlockSize(HEAD).should.equal(SUCCESS);
-  }));
-});
diff --git a/test/fast/protocol-brg51-number.js b/test/fast/protocol-brg51-number.js
deleted file mode 100644
index 465238ea46a067a9674f33a9e045716cd394079b..0000000000000000000000000000000000000000
--- a/test/fast/protocol-brg51-number.js
+++ /dev/null
@@ -1,80 +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 indexer       = require('../../app/lib/indexer').Indexer
-
-const FAIL = false;
-const SUCCESS = true;
-
-describe("Protocol BR_G51 - Number", function(){
-
-  it('1 following 1 should fail', () => co(function*(){
-    const block  = { number: 1 };
-    const HEAD_1 = { number: 1 };
-    const HEAD   = {};
-    indexer.prepareNumber(HEAD, HEAD_1);
-    indexer.ruleNumber(block, HEAD).should.equal(FAIL);
-  }));
-
-  it('1 following 0 should succeed', () => co(function*(){
-    const block  = { number: 1 };
-    const HEAD_1 = { number: 0 };
-    const HEAD   = {};
-    indexer.prepareNumber(HEAD, HEAD_1);
-    indexer.ruleNumber(block, HEAD).should.equal(SUCCESS);
-  }));
-
-  it('0 following 0 should fail', () => co(function*(){
-    const block  = { number: 0 };
-    const HEAD_1 = { number: 0 };
-    const HEAD   = {};
-    indexer.prepareNumber(HEAD, HEAD_1);
-    indexer.ruleNumber(block, HEAD).should.equal(FAIL);
-  }));
-
-  it('0 following nothing should succeed', () => co(function*(){
-    const block  = { number: 0 };
-    const HEAD_1 = null;
-    const HEAD   = {};
-    indexer.prepareNumber(HEAD, HEAD_1);
-    indexer.ruleNumber(block, HEAD).should.equal(SUCCESS);
-  }));
-
-  it('4 following nothing should fail', () => co(function*(){
-    const block  = { number: 4 };
-    const HEAD_1 = null;
-    const HEAD   = {};
-    indexer.prepareNumber(HEAD, HEAD_1);
-    indexer.ruleNumber(block, HEAD).should.equal(FAIL);
-  }));
-
-  it('4 following 2 should fail', () => co(function*(){
-    const block  = { number: 4 };
-    const HEAD_1 = { number: 2 };
-    const HEAD   = {};
-    indexer.prepareNumber(HEAD, HEAD_1);
-    indexer.ruleNumber(block, HEAD).should.equal(FAIL);
-  }));
-
-  it('4 following 3 should succeed', () => co(function*(){
-    const block  = { number: 4 };
-    const HEAD_1 = { number: 3 };
-    const HEAD   = {};
-    indexer.prepareNumber(HEAD, HEAD_1);
-    indexer.ruleNumber(block, HEAD).should.equal(SUCCESS);
-  }));
-
-});
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/fast/protocol-brg106-number.js b/test/fast/protocol/protocol-brg106-number.ts
similarity index 88%
rename from test/fast/protocol-brg106-number.js
rename to test/fast/protocol/protocol-brg106-number.ts
index 334f18ab90fa645a24021737894c9e85389e2b48..8fe0242a26f88d228b1320c55a5d2df492909cc9 100644
--- a/test/fast/protocol-brg106-number.js
+++ b/test/fast/protocol/protocol-brg106-number.ts
@@ -11,22 +11,22 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
-const co            = require('co');
+import {Map} from "../../../app/lib/common-libs/crypto/map"
+import {Indexer} from "../../../app/lib/indexer"
+
 const should        = require('should');
-const indexer       = require('../../app/lib/indexer').Indexer
 
 describe("Protocol BR_G106 - Garbaging", function(){
 
-  it('An account with balance < 1,00 should be cleaned up', () => co(function*(){
-    const balances = {
+  it('An account with balance < 1,00 should be cleaned up', async () => {
+    const balances:Map<{ balance: number }> = {
       pubkeyA: { balance: 103 },
       pubkeyB: { balance: 11 + 22 + 68 }, // 101
       pubkeyC: { balance: 100 },
       pubkeyD: { balance: 0 },
       pubkeyE: { balance: 0 }
     }
-    const sources = {
+    const sources:any = {
       pubkeyA: [ // 103
         { amount: 103, base: 0, tx: 'A1', identifier: 'I1', pos: 0 }
       ],
@@ -42,13 +42,13 @@ describe("Protocol BR_G106 - Garbaging", function(){
       pubkeyE: []
     }
     const dal = {
-      getWallet: (conditions) => Promise.resolve(balances[conditions]),
+      getWallet: (conditions:string) => Promise.resolve(balances[conditions]),
       sindexDAL: {
-        getAvailableForConditions: (conditions) => Promise.resolve(sources[conditions])
+        getAvailableForConditions: (conditions:string) => Promise.resolve(sources[conditions])
       }
     };
-    const HEAD   = { unitBase: 0 };
-    const cleaning = yield indexer.ruleIndexGarbageSmallAccounts(HEAD, [
+    const HEAD   = { unitBase: 0 } as any
+    const cleaning = await Indexer.ruleIndexGarbageSmallAccounts(HEAD, [
       // A sends 3 to D --> A keeps 100
       { op: 'UPDATE', conditions: 'pubkeyA', amount: 103, base: 0, identifier: 'I1', pos: 0 },
       { op: 'CREATE', conditions: 'pubkeyA', amount: 100, base: 0, identifier: 'I2', pos: 0 },
@@ -62,7 +62,7 @@ describe("Protocol BR_G106 - Garbaging", function(){
       // C sends 100 to E --> C keeps 0
       { op: 'UPDATE', conditions: 'pubkeyC', amount: 100, base: 0, identifier: 'I8', pos: 0 },
       { op: 'CREATE', conditions: 'pubkeyE', amount: 100, base: 0, identifier: 'I9', pos: 0 }
-      ], dal);
+      ] as any, [], dal as any);
     cleaning.should.have.length(5);
     cleaning[0].should.have.property('identifier').equal('I3');
     cleaning[0].should.have.property('amount').equal(3);
@@ -98,5 +98,5 @@ describe("Protocol BR_G106 - Garbaging", function(){
     cleaning[4].should.have.property('tx').equal(null);
     cleaning[4].should.have.property('consumed').equal(true);
     cleaning[4].should.have.property('op').equal('UPDATE');
-  }));
-});
+  })
+})
diff --git a/test/fast/protocol/protocol-brg107-udEffectiveTime.ts b/test/fast/protocol/protocol-brg107-udEffectiveTime.ts
new file mode 100644
index 0000000000000000000000000000000000000000..43176bdc124e69ba5f6600589e0f235be9408713
--- /dev/null
+++ b/test/fast/protocol/protocol-brg107-udEffectiveTime.ts
@@ -0,0 +1,52 @@
+// 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 {Indexer} from "../../../app/lib/indexer"
+
+const should        = require('should');
+
+describe("Protocol BR_G107 - udReevalTime", function(){
+
+  it('root block good udReevalTime', async () => {
+    const conf   = { udReevalTime0: 1500000000 } as any
+    const HEAD_1 = null as any
+    const HEAD   = { number: 0 } as any
+    Indexer.prepareUDTime(HEAD, HEAD_1, conf);
+    HEAD.udReevalTime.should.equal(conf.udReevalTime0);
+  })
+
+  it('block with medianTime < udReevalTime', async () => {
+    const conf   = { dt: 100, dtReeval: 20 } as any
+    const HEAD_1 = { number: 59, udReevalTime: 1500000900 } as any
+    const HEAD   = { number: 60, medianTime:   1500000899 } as any
+    Indexer.prepareUDTime(HEAD, HEAD_1, conf);
+    HEAD.udReevalTime.should.equal(HEAD_1.udReevalTime);
+  })
+
+  it('block with medianTime == udReevalTime', async () => {
+    const conf   = { dt: 100, dtReeval: 20 } as any
+    const HEAD_1 = { number: 59, udReevalTime: 1500000900 } as any
+    const HEAD   = { number: 60, medianTime:   1500000900 } as any
+    Indexer.prepareUDTime(HEAD, HEAD_1, conf);
+    HEAD.udReevalTime.should.equal(HEAD_1.udReevalTime + conf.dtReeval);
+  })
+
+  it('block with medianTime > udReevalTime', async () => {
+    const conf   = { dt: 100, dtReeval: 20 } as any
+    const HEAD_1 = { number: 59, udReevalTime: 1500000900 } as any
+    const HEAD   = { number: 60, medianTime:   1500000901 } as any
+    Indexer.prepareUDTime(HEAD, HEAD_1, conf);
+    HEAD.udReevalTime.should.equal(HEAD_1.udReevalTime + conf.dtReeval);
+  })
+
+});
diff --git a/test/fast/protocol/protocol-brg11-udTime.ts b/test/fast/protocol/protocol-brg11-udTime.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0125226defae0105abb29909aeba6267eeb45176
--- /dev/null
+++ b/test/fast/protocol/protocol-brg11-udTime.ts
@@ -0,0 +1,52 @@
+// 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 {Indexer} from "../../../app/lib/indexer"
+
+const should        = require('should');
+
+describe("Protocol BR_G11 - udTime", function(){
+
+  it('root block good udTime', async () => {
+    const conf   = { udTime0: 1500000000 } as any
+    const HEAD_1 = null as any
+    const HEAD   = { number: 0 } as any
+    Indexer.prepareUDTime(HEAD, HEAD_1, conf);
+    HEAD.udTime.should.equal(conf.udTime0);
+  })
+
+  it('block with medianTime < udTime', async () => {
+    const conf   = { dt: 100 } as any
+    const HEAD_1 = { number: 59, udTime:     1500000900 }as any
+    const HEAD   = { number: 60, medianTime: 1500000899 }as any
+    Indexer.prepareUDTime(HEAD, HEAD_1, conf);
+    HEAD.udTime.should.equal(HEAD_1.udTime);
+  })
+
+  it('block with medianTime == udTime', async () => {
+    const conf   = { dt: 100 } as any
+    const HEAD_1 = { number: 59, udTime:     1500000900 }as any
+    const HEAD   = { number: 60, medianTime: 1500000900 }as any
+    Indexer.prepareUDTime(HEAD, HEAD_1, conf);
+    HEAD.udTime.should.equal(HEAD_1.udTime + conf.dt);
+  })
+
+  it('block with medianTime > udTime', async () => {
+    const conf   = { dt: 100 }as any
+    const HEAD_1 = { number: 59, udTime:     1500000900 }as any
+    const HEAD   = { number: 60, medianTime: 1500000901 }as any
+    Indexer.prepareUDTime(HEAD, HEAD_1, conf)
+    HEAD.udTime.should.equal(HEAD_1.udTime + conf.dt);
+  })
+
+})
diff --git a/test/fast/protocol-brg13-dividend.js b/test/fast/protocol/protocol-brg13-dividend.ts
similarity index 54%
rename from test/fast/protocol-brg13-dividend.js
rename to test/fast/protocol/protocol-brg13-dividend.ts
index 66025d6ce6f67e54dc1871a49af7abda7ced5706..e5d31d9178bc81221bbb7c9eea7c6961c93dfce8 100644
--- a/test/fast/protocol-brg13-dividend.js
+++ b/test/fast/protocol/protocol-brg13-dividend.ts
@@ -12,49 +12,49 @@
 // GNU Affero General Public License for more details.
 
 "use strict";
-const co            = require('co');
+import {Indexer} from "../../../app/lib/indexer"
+
 const should        = require('should');
-const indexer       = require('../../app/lib/indexer').Indexer
 
 describe("Protocol BR_G13 - dividend", function(){
 
-  it('root block has no dividend', () => co(function*(){
-    const conf   = { udTime0: 1500000000, dt: 100 };
-    const HEAD_1 = null;
-    const HEAD   = { number: 0 };
-    indexer.prepareUDTime(HEAD, HEAD_1, conf);
-    indexer.prepareDividend(HEAD, HEAD_1, conf);
+  it('root block has no dividend', async () => {
+    const conf   = { udTime0: 1500000000, dt: 100 } as any
+    const HEAD_1 = null as any
+    const HEAD   = { number: 0 } as any
+    Indexer.prepareUDTime(HEAD, HEAD_1, conf);
+    Indexer.prepareDividend(HEAD, HEAD_1, conf);
     should.equal(HEAD.dividend, null);
-  }));
-
-  it('block with medianTime < udTime has no dividend', () => co(function*(){
-    const conf   = { dt: 100 };
-    const HEAD_1 = { number: 59, udTime:     1500000900 };
-    const HEAD   = { number: 60, medianTime: 1500000899 };
-    indexer.prepareUDTime(HEAD, HEAD_1, conf);
-    indexer.prepareDividend(HEAD, HEAD_1, conf);
+  })
+
+  it('block with medianTime < udTime has no dividend', async () => {
+    const conf   = { dt: 100 } as any
+    const HEAD_1 = { number: 59, udTime:     1500000900 } as any
+    const HEAD   = { number: 60, medianTime: 1500000899 } as any
+    Indexer.prepareUDTime(HEAD, HEAD_1, conf);
+    Indexer.prepareDividend(HEAD, HEAD_1, conf);
     HEAD.udTime.should.equal(HEAD_1.udTime);
     should.equal(HEAD.dividend, null);
-  }));
-
-  it('block with medianTime == udTime', () => co(function*(){
-    const conf   = { dt: 100, dtReeval: 100, c: 0.0488 };
-    const HEAD_1 = { number: 59, udTime:     1500000900, udReevalTime: 1500000900, dividend: 100, mass: 18000, massReeval: 18000, unitBase: 1 };
-    const HEAD   = { number: 60, medianTime: 1500000900, membersCount: 3 };
-    indexer.prepareUDTime(HEAD, HEAD_1, conf);
-    indexer.prepareDividend(HEAD, HEAD_1, conf);
+  })
+
+  it('block with medianTime == udTime', async () => {
+    const conf   = { dt: 100, dtReeval: 100, c: 0.0488 } as any
+    const HEAD_1 = { number: 59, udTime:     1500000900, udReevalTime: 1500000900, dividend: 100, mass: 18000, massReeval: 18000, unitBase: 1 } as any
+    const HEAD   = { number: 60, medianTime: 1500000900, membersCount: 3 } as any
+    Indexer.prepareUDTime(HEAD, HEAD_1, conf);
+    Indexer.prepareDividend(HEAD, HEAD_1, conf);
     HEAD.udTime.should.equal(HEAD_1.udTime + conf.dt);
     should.equal(HEAD.dividend, 102);
-  }));
-
-  it('block with medianTime > udTime', () => co(function*(){
-    const conf   = { dt: 100, dtReeval: 100, c: 0.0488 };
-    const HEAD_1 = { number: 59, udTime:     1500000900, udReevalTime: 1500000900, dividend: 100, mass: 18000, massReeval: 18000, unitBase: 1 };
-    const HEAD   = { number: 60, medianTime: 1500000901, membersCount: 3 };
-    indexer.prepareUDTime(HEAD, HEAD_1, conf);
-    indexer.prepareDividend(HEAD, HEAD_1, conf);
+  })
+
+  it('block with medianTime > udTime', async () => {
+    const conf   = { dt: 100, dtReeval: 100, c: 0.0488 } as any
+    const HEAD_1 = { number: 59, udTime:     1500000900, udReevalTime: 1500000900, dividend: 100, mass: 18000, massReeval: 18000, unitBase: 1 } as any
+    const HEAD   = { number: 60, medianTime: 1500000901, membersCount: 3 } as any
+    Indexer.prepareUDTime(HEAD, HEAD_1, conf);
+    Indexer.prepareDividend(HEAD, HEAD_1, conf);
     HEAD.udTime.should.equal(HEAD_1.udTime + conf.dt);
     should.equal(HEAD.dividend, 102);
-  }));
+  })
 
-});
+})
diff --git a/test/fast/protocol/protocol-brg49-version.ts b/test/fast/protocol/protocol-brg49-version.ts
new file mode 100644
index 0000000000000000000000000000000000000000..44b0af7be63f33f3c4594f6192d1d197b3f1538b
--- /dev/null
+++ b/test/fast/protocol/protocol-brg49-version.ts
@@ -0,0 +1,46 @@
+// 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 {Indexer} from "../../../app/lib/indexer"
+
+const should        = require('should');
+
+const FAIL = false;
+const SUCCESS = true;
+
+describe("Protocol BR_G49 - Version", function(){
+
+  it('V13 following V12 should fail', async () => {
+    const HEAD_1 = { number: 17, version: 13 } as any
+    const HEAD   = { number: 18, version: 12 } as any
+    Indexer.ruleVersion(HEAD, HEAD_1).should.equal(FAIL);
+  })
+
+  it('V14 following V12 should fail', async () => {
+    const HEAD_1 = { number: 17, version: 14 } as any
+    const HEAD   = { number: 18, version: 12 } as any
+    Indexer.ruleVersion(HEAD, HEAD_1).should.equal(FAIL);
+  })
+
+  it('V13 following V14 should succeed', async () => {
+    const HEAD_1 = { number: 17, version: 13 } as any
+    const HEAD   = { number: 18, version: 14 } as any
+    Indexer.ruleVersion(HEAD, HEAD_1).should.equal(SUCCESS);
+  })
+
+  it('V13 following V15 should fail', async () => {
+    const HEAD_1 = { number: 17, version: 13 } as any
+    const HEAD   = { number: 18, version: 15 } as any
+    Indexer.ruleVersion(HEAD, HEAD_1).should.equal(FAIL);
+  })
+})
diff --git a/test/fast/protocol/protocol-brg50-blocksize.ts b/test/fast/protocol/protocol-brg50-blocksize.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3cdc44b5c90cae9817635333758bc34ba0f9ff10
--- /dev/null
+++ b/test/fast/protocol/protocol-brg50-blocksize.ts
@@ -0,0 +1,67 @@
+// 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 {Indexer} from "../../../app/lib/indexer"
+
+const should        = require('should');
+
+const FAIL = false;
+const SUCCESS = true;
+
+describe("Protocol BR_G50 - Block size", function(){
+  
+  it('2 for an AVG(10) should succeed', async () => {
+    const HEAD   = { number: 24, bsize: 2, avgBlockSize: 10 } as any
+    Indexer.ruleBlockSize(HEAD).should.equal(SUCCESS);
+  })
+
+  it('400 for an AVG(10) should succeed', async () => {
+    const HEAD   = { number: 24, bsize: 400, avgBlockSize: 10 } as any
+    Indexer.ruleBlockSize(HEAD).should.equal(SUCCESS);
+  })
+
+  it('499 for an AVG(10) should succeed', async () => {
+    const HEAD   = { number: 24, bsize: 499, avgBlockSize: 10 } as any
+    Indexer.ruleBlockSize(HEAD).should.equal(SUCCESS);
+  })
+
+  it('500 for an AVG(10) should fail', async () => {
+    const HEAD   = { number: 24, bsize: 500, avgBlockSize: 10 } as any
+    Indexer.ruleBlockSize(HEAD).should.equal(FAIL);
+  })
+
+  it('500 for an AVG(454) should fail', async () => {
+    const HEAD   = { number: 24, bsize: 500, avgBlockSize: 454} as any
+    Indexer.ruleBlockSize(HEAD).should.equal(FAIL);
+  })
+
+  it('500 for an AVG(455) should succeed', async () => {
+    const HEAD   = { number: 24, bsize: 500, avgBlockSize: 455} as any
+    Indexer.ruleBlockSize(HEAD).should.equal(SUCCESS);
+  })
+
+  it('1100 for an AVG(1000) should fail', async () => {
+    const HEAD   = { number: 24, bsize: 1100, avgBlockSize: 1000} as any
+    Indexer.ruleBlockSize(HEAD).should.equal(FAIL);
+  })
+
+  it('1100 for an AVG(1001) should succeed', async () => {
+    const HEAD   = { number: 24, bsize: 1100, avgBlockSize: 1001} as any
+    Indexer.ruleBlockSize(HEAD).should.equal(SUCCESS);
+  })
+
+  it('1100 for block#0 should succeed', async () => {
+    const HEAD   = { number: 0, bsize: 1100, avgBlockSize: 0} as any
+    Indexer.ruleBlockSize(HEAD).should.equal(SUCCESS);
+  })
+});
diff --git a/test/fast/protocol/protocol-brg51-number.ts b/test/fast/protocol/protocol-brg51-number.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5b55b44c6196af949c6aa3338d51e5afd296759f
--- /dev/null
+++ b/test/fast/protocol/protocol-brg51-number.ts
@@ -0,0 +1,79 @@
+// 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 {Indexer} from "../../../app/lib/indexer"
+
+const should        = require('should');
+
+const FAIL = false;
+const SUCCESS = true;
+
+describe("Protocol BR_G51 - Number", function(){
+
+  it('1 following 1 should fail', async () => {
+    const block  = { number: 1 } as any
+    const HEAD_1 = { number: 1 } as any
+    const HEAD   = {} as any
+    Indexer.prepareNumber(HEAD, HEAD_1);
+    Indexer.ruleNumber(block, HEAD).should.equal(FAIL);
+  })
+
+  it('1 following 0 should succeed', async () => {
+    const block  = { number: 1 } as any
+    const HEAD_1 = { number: 0 } as any
+    const HEAD   = {} as any
+    Indexer.prepareNumber(HEAD, HEAD_1);
+    Indexer.ruleNumber(block, HEAD).should.equal(SUCCESS);
+  })
+
+  it('0 following 0 should fail', async () => {
+    const block  = { number: 0 } as any
+    const HEAD_1 = { number: 0 } as any
+    const HEAD   = {} as any
+    Indexer.prepareNumber(HEAD, HEAD_1);
+    Indexer.ruleNumber(block, HEAD).should.equal(FAIL);
+  })
+
+  it('0 following nothing should succeed', async () => {
+    const block  = { number: 0 } as any
+    const HEAD_1 = null as any
+    const HEAD   = {} as any
+    Indexer.prepareNumber(HEAD, HEAD_1);
+    Indexer.ruleNumber(block, HEAD).should.equal(SUCCESS);
+  })
+
+  it('4 following nothing should fail', async () => {
+    const block  = { number: 4 } as any
+    const HEAD_1 = null as any
+    const HEAD   = {} as any
+    Indexer.prepareNumber(HEAD, HEAD_1);
+    Indexer.ruleNumber(block, HEAD).should.equal(FAIL);
+  })
+
+  it('4 following 2 should fail', async () => {
+    const block  = { number: 4 } as any
+    const HEAD_1 = { number: 2 } as any
+    const HEAD   = {} as any
+    Indexer.prepareNumber(HEAD, HEAD_1);
+    Indexer.ruleNumber(block, HEAD).should.equal(FAIL);
+  })
+
+  it('4 following 3 should succeed', async () => {
+    const block  = { number: 4 } as any
+    const HEAD_1 = { number: 3 } as any
+    const HEAD   = {} as any
+    Indexer.prepareNumber(HEAD, HEAD_1);
+    Indexer.ruleNumber(block, HEAD).should.equal(SUCCESS);
+  })
+
+})
diff --git a/test/fast/prover/pow-1-cluster.ts b/test/fast/prover/prover-pow-1-cluster.ts
similarity index 92%
rename from test/fast/prover/pow-1-cluster.ts
rename to test/fast/prover/prover-pow-1-cluster.ts
index 928e7243c5bea058905ebd797f71a1974de93a9c..da63563cc5003612d28ba12f729bb10556307752 100644
--- a/test/fast/prover/pow-1-cluster.ts
+++ b/test/fast/prover/prover-pow-1-cluster.ts
@@ -13,7 +13,6 @@
 
 import {Master} from "../../../app/modules/prover/lib/powCluster"
 
-const co = require('co')
 require('should')
 const logger = require('../../../app/lib/logger').NewLogger()
 
@@ -33,9 +32,9 @@ describe('PoW Cluster', () => {
     master.nbWorkers.should.equal(0)
   })
 
-  it('should answer for a basic PoW in more than 50ms (cold)', () => co(function*(){
+  it('should answer for a basic PoW in more than 50ms (cold)', async () => {
     const start = Date.now()
-    yield master.proveByWorkers({
+    await master.proveByWorkers({
       newPoW: {
         block: {
           number: 0
@@ -57,15 +56,15 @@ describe('PoW Cluster', () => {
     })
     const delay = Date.now() - start
     delay.should.be.above(50)
-  }))
+  })
 
   it('should have an non-empty cluster after a PoW was asked', () => {
     master.nbWorkers.should.above(0)
   })
 
-  it('should answer within 50ms for a basic PoW (warm)', () => co(function*(){
+  it('should answer within 50ms for a basic PoW (warm)', async () => {
     const start = Date.now()
-    yield master.proveByWorkers({
+    await master.proveByWorkers({
       newPoW: {
         block: {
           number: 0
@@ -87,7 +86,7 @@ describe('PoW Cluster', () => {
     })
     const delay = Date.now() - start
     delay.should.be.below(50)
-  }))
+  })
 
   it('should be able to stop all the cores on cancel', async () => {
     master.proveByWorkers({
diff --git a/test/fast/prover/pow-2-engine.js b/test/fast/prover/prover-pow-2-engine.ts
similarity index 75%
rename from test/fast/prover/pow-2-engine.js
rename to test/fast/prover/prover-pow-2-engine.ts
index 9f3e0aefe847fcbc5f536282fb70dc46a5d505cc..403f822ef58ba5f3a5064c154f38539ac4074fff 100644
--- a/test/fast/prover/pow-2-engine.js
+++ b/test/fast/prover/prover-pow-2-engine.ts
@@ -11,23 +11,22 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {PowEngine} from "../../../app/modules/prover/lib/engine"
+import {NewLogger} from "../../../app/lib/logger"
 
-const co = require('co');
 const should = require('should');
-const PowEngine = require('../../../app/modules/prover/lib/engine').PowEngine
-const logger = require('../../../app/lib/logger').NewLogger()
+const logger = NewLogger()
 
 describe('PoW Engine', () => {
 
-  it('should be configurable', () => co(function*(){
-    const e1 = new PowEngine({ nbCores: 1 }, logger);
-    (yield e1.setConf({ cpu: 0.2, prefix: '34' })).should.deepEqual({ cpu: 0.2, prefix: '34' });
-    yield e1.shutDown()
-  }));
+  it('should be configurable', async () => {
+    const e1 = new PowEngine({ nbCores: 1 } as any, logger);
+    (await e1.setConf({ cpu: 0.2, prefix: '34' })).should.deepEqual({ cpu: 0.2, prefix: '34' });
+    await e1.shutDown()
+  })
 
-  it('should be able to make a proof', () => co(function*(){
-    const e1 = new PowEngine({ nbCores: 1 }, logger);
+  it('should be able to make a proof', async () => {
+    const e1 = new PowEngine({ nbCores: 1 } as any, logger);
     const block = { number: 35 };
     const zeros = 2;
     const highMark = 'A';
@@ -38,7 +37,7 @@ describe('PoW Engine', () => {
     const forcedTime = 1;
     const medianTimeBlocks = 20;
     const avgGenTime = 5 * 60;
-    const proof = yield e1.prove({
+    const proof = await e1.prove({
         newPoW: {
           block,
           zeros,
@@ -66,12 +65,12 @@ describe('PoW Engine', () => {
         pow: '009A52E6E2E4EA7DE950A2DA673114FA55B070EBE350D75FF0C62C6AAE9A37E5'
       }
     });
-    yield e1.shutDown()
-  }));
+    await e1.shutDown()
+  })
 
-  it('should be able to stop a proof', () => co(function*(){
-    const e1 = new PowEngine({ nbCores: 1 }, logger);
-    yield e1.forceInit()
+  it('should be able to stop a proof', async () => {
+    const e1 = new PowEngine({ nbCores: 1 } as any, logger);
+    await e1.forceInit()
     const block = { number: 26 };
     const zeros = 10; // Requires hundreds of thousands of tries probably
     const highMark = 'A';
@@ -96,10 +95,10 @@ describe('PoW Engine', () => {
         }
       }
     )
-    yield new Promise((res) => setTimeout(res, 10))
-    yield e1.cancel()
-    // const proof = yield proofPromise;
+    await new Promise((res) => setTimeout(res, 10))
+    await e1.cancel()
+    // const proof = await proofPromise;
     // should.not.exist(proof);
-    yield e1.shutDown()
-  }));
-});
+    await e1.shutDown()
+  })
+})
diff --git a/test/fast/prover/pow-3-prover.js b/test/fast/prover/prover-pow-3-prover.ts
similarity index 77%
rename from test/fast/prover/pow-3-prover.js
rename to test/fast/prover/prover-pow-3-prover.ts
index 9246f8efdef34d4bc1f69b90af88d45754a1ad41..d2da6029e1b45457e9445a9103570fd74644e519 100644
--- a/test/fast/prover/pow-3-prover.js
+++ b/test/fast/prover/prover-pow-3-prover.ts
@@ -11,20 +11,17 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {BlockProver} from "../../../app/modules/prover/lib/blockProver"
 
-const co = require('co')
 const should = require('should')
-const moment = require('moment')
 const winston = require('winston')
-const BlockProver = require('../../../app/modules/prover/lib/blockProver').BlockProver
 
 // Mute logger
 winston.remove(winston.transports.Console)
 
 describe('PoW block prover', () => {
 
-  let prover
+  let prover:BlockProver
 
   before(() => {
     prover = new BlockProver({
@@ -39,23 +36,23 @@ describe('PoW block prover', () => {
       },
       push: () => {},
       logger: winston
-    })
+    } as any)
   })
 
-  it('should be configurable', () => co(function*(){
-    const res1 = yield prover.changeCPU(0.2)
+  it('should be configurable', async () => {
+    const res1 = await prover.changeCPU(0.2)
     res1.should.deepEqual({ cpu: 0.2 })
-    const res2 = yield prover.changePoWPrefix('34')
+    const res2 = await prover.changePoWPrefix('34')
     res2.should.deepEqual({ prefix: '34' })
-  }));
+  })
 
-  it('should be able to make a proof', () => co(function*(){
+  it('should be able to make a proof', async () => {
     const block = {
       number: 35,
       issuer: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd'
     }
     const forcedTime = 1;
-    const proof = yield prover.prove(block, 24, forcedTime)
+    const proof = await prover.prove(block, 24, forcedTime)
     proof.should.containEql({
       version: 10,
       nonce: 340000000000034,
@@ -79,33 +76,33 @@ describe('PoW block prover', () => {
       certifications: [],
       transactions: []
     });
-  }));
+  })
 
-  it('should be able to use a prefix maxed at 899', () => co(function*(){
+  it('should be able to use a prefix maxed at 899', async () => {
     const block = {
       number: 1,
       issuer: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd'
     }
-    const params = yield prover.changePoWPrefix('899')
+    const params = await prover.changePoWPrefix('899')
     params.should.deepEqual({ prefix: '899' })
     const forcedTime = 1;
-    const proof = yield prover.prove(block, 1, forcedTime)
+    const proof = await prover.prove(block, 1, forcedTime)
     proof.nonce.should.equal(8990000000000001)
     String(proof.nonce).should.have.length(16)
-  }));
+  })
 
-  it('should be able to stop a proof', () => co(function*(){
+  it('should be able to stop a proof', async () => {
     const block = {
       number: 35,
       issuer: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd'
     }
     const forcedTime = 1;
     const proofPromise = prover.prove(block, 70, forcedTime)
-    yield new Promise((res) => setTimeout(res, 20))
-    yield prover.cancel()
+    await new Promise((res) => setTimeout(res, 20))
+    await prover.cancel()
     let err = ''
     try {
-      yield proofPromise
+      await proofPromise
     } catch (e) {
       err = e
     } finally {
@@ -114,5 +111,5 @@ describe('PoW block prover', () => {
       }
       err.should.equal('Proof-of-work computation canceled because block received')
     }
-  }));
-});
+  })
+})
diff --git a/test/integration/collapse.js b/test/integration/block-generation/community-collapse.ts
similarity index 62%
rename from test/integration/collapse.js
rename to test/integration/block-generation/community-collapse.ts
index 974790da99cf8170ec0016a0bed76e93721171f5..6c9620538ca68199b9673c9941a1a038861563e3 100644
--- a/test/integration/collapse.js
+++ b/test/integration/block-generation/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"
+import {shutDownEngine} from "../tools/shutdown-engine"
+import {expectJSON} from "../tools/http-expect"
 
-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 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(() => {
@@ -78,7 +73,7 @@ describe("Community collapse", function() {
   })
 
   it('should be handled', function() {
-    return httpTest.expectJSON(rp('http://127.0.0.1:9340/blockchain/block/2', { json: true }), {
+    return expectJSON(rp('http://127.0.0.1:9340/blockchain/block/2', { json: true }), {
       number: 2
     });
   });
diff --git a/test/integration/newcomers-shuffling.js b/test/integration/block-generation/newcomers-shuffling.ts
similarity index 68%
rename from test/integration/newcomers-shuffling.js
rename to test/integration/block-generation/newcomers-shuffling.ts
index 31fb6f1dfcda2d6393712c597e1ec7217f2bdfc4..3a62ef2b55bf83ab219bb87f31b6b42278671e0c 100644
--- a/test/integration/newcomers-shuffling.js
+++ b/test/integration/block-generation/newcomers-shuffling.ts
@@ -11,22 +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"
 
-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');
+const assert = require('assert');
 
-let s1, cat, tac, toc, tic
+let s1:TestingServer, cat:TestUser, tac:TestUser, toc:TestUser, tic:TestUser
 
-describe("Newcomers shuffling", function() {
+/**
+ * Thist test is a bit useless as is, because we don't check the fact that the newcomers enter in a random manner.
+ */
 
-  before(() => co(function*() {
+describe("Newcomers shuffling", function() {
 
-    s1 = toolbox.server({
+  before(async () => {
+    
+    s1 = NewTestingServer({
       pair: {
         pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
         sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
@@ -38,17 +38,17 @@ describe("Newcomers shuffling", function() {
     toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
     tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
 
-    yield s1.prepareForNetwork();
+    await s1.prepareForNetwork();
 
     // Publishing identities
-    yield cat.createIdentity();
-    yield tac.createIdentity();
-    yield cat.cert(tac);
-    yield tac.cert(cat);
-    yield cat.join();
-    yield tac.join();
-    yield s1.commit()
-  }));
+    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([
@@ -56,16 +56,16 @@ describe("Newcomers shuffling", function() {
     ])
   })
 
-  it('toc and tic could join ', () => co(function*() {
-    yield toc.createIdentity();
-    yield tic.createIdentity();
-    yield toc.join();
-    yield tic.join();
+  it('toc and tic could join ', async () => {
+    await toc.createIdentity();
+    await tic.createIdentity();
+    await toc.join();
+    await tic.join();
     // same certifier for toc and tic
-    yield cat.cert(toc)
-    yield cat.cert(tic)
+    await cat.cert(toc)
+    await cat.cert(tic)
     // We do not known which one of toc or tic will be the first in!
-    yield s1.commit()
-    yield s1.commit()
-  }));
-});
+    await s1.commit()
+    await s1.commit()
+  })
+})
diff --git a/test/integration/block-generation/start-generate-blocks.ts b/test/integration/block-generation/start-generate-blocks.ts
new file mode 100644
index 0000000000000000000000000000000000000000..04c52d83b6715b21338ec0360b79a71eb1f6b002
--- /dev/null
+++ b/test/integration/block-generation/start-generate-blocks.ts
@@ -0,0 +1,141 @@
+// 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"
+import {until} from "../tools/test-until"
+import {sync} from "../tools/test-sync"
+import {shutDownEngine} from "../tools/shutdown-engine"
+import {expectJSON} from "../tools/http-expect"
+
+const rp        = require('request-promise');
+
+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._server, s2._server);
+    // 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 69%
rename from test/integration/branches2.ts
rename to test/integration/branches/branches2.ts
index 2000dacc69cb11b3b7ea9404af3d27137a1379fb..0654d7e83dfa052364e540b9d9383262ce0b4f90 100644
--- a/test/integration/branches2.ts
+++ b/test/integration/branches/branches2.ts
@@ -11,25 +11,19 @@
 // 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";
-
-const co        = require('co');
-const _         = require('underscore');
-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 expectJSON     = httpTest.expectJSON;
-const expectHttpCode = httpTest.expectHttpCode;
+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 {NewTestingServer, TestingServer, waitForkResolution, waitToHaveBlock} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
+import {CrawlerDependency} from "../../../app/modules/crawler/index"
+import {sync} from "../tools/test-sync"
+import {shutDownEngine} from "../tools/shutdown-engine"
+import {expectHttpCode, expectJSON} from "../tools/http-expect"
+
+const rp        = require('request-promise');
 
 if (OtherConstants.MUTE_LOGS_DURING_UNIT_TESTS) {
   NewLogger().mute();
@@ -52,18 +46,18 @@ const commonConf = {
   sigQty: 1
 };
 
-let s1:any, s2:any, cat, toc
+let s1:TestingServer, s2:TestingServer, cat:TestUser, toc:TestUser
 
 const now = Math.round(new Date().getTime() / 1000);
 
 describe("SelfFork", function() {
 
-  before(() => co(function *() {
+  before(async () => {
 
-    s1 = duniter(
-      '/bb4',
-      MEMORY_MODE,
-      _.extend({
+    s1 = NewTestingServer(
+      Underscore.extend({
+        name: 'bb4',
+        memory: MEMORY_MODE,
         port: '7781',
         pair: {
           pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
@@ -71,10 +65,10 @@ describe("SelfFork", function() {
         }
       }, commonConf));
 
-    s2 = duniter(
-      '/bb5',
-      MEMORY_MODE,
-      _.extend({
+    s2 = NewTestingServer(
+      Underscore.extend({
+        name: 'bb5',
+        memory: MEMORY_MODE,
         port: '7782',
         pair: {
           pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo',
@@ -85,51 +79,46 @@ describe("SelfFork", function() {
     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, {
-      time: now + 37180
-    });
-
-    yield s1.initWithDAL().then(bma).then((bmapi:any) => bmapi.openConnections());
-    yield s2.initWithDAL().then(bma).then((bmapi:any) => bmapi.openConnections());
-    s1.addEndpointsDefinitions(() => BmaDependency.duniter.methods.getMainEndpoint(s1.conf))
-    s2.addEndpointsDefinitions(() => BmaDependency.duniter.methods.getMainEndpoint(s2.conf))
+    await s1.initWithDAL().then(BmaDependency.duniter.methods.bma).then((bmapi:any) => bmapi.openConnections());
+    await s2.initWithDAL().then(BmaDependency.duniter.methods.bma).then((bmapi:any) => bmapi.openConnections());
+    s1._server.addEndpointsDefinitions(() => BmaDependency.duniter.methods.getMainEndpoint(s1.conf))
+    s2._server.addEndpointsDefinitions(() => BmaDependency.duniter.methods.getMainEndpoint(s2.conf))
 
     // Server 1
-    yield cat.createIdentity();
-    yield toc.createIdentity();
-    yield toc.cert(cat);
-    yield cat.cert(toc);
-    yield cat.join();
-    yield toc.join();
-
-    yield commitS1({
+    await cat.createIdentity();
+    await toc.createIdentity();
+    await toc.cert(cat);
+    await cat.cert(toc);
+    await cat.join();
+    await toc.join();
+
+    await s1.commit({
       time: now
     });
-    yield commitS1();
-    yield commitS1();
-    yield commitS1();
+    await s1.commit();
+    await s1.commit();
+    await s1.commit();
 
     // Server 2
-    yield sync(0, 2, s1, s2);
-    yield waitToHaveBlock(s2, 2)
-    let s2p = yield s2.PeeringService.peer();
-
-    yield commitS2();
-    yield commitS2();
-    yield commitS2();
-    yield commitS2();
-    yield commitS2();
-    yield commitS2();
-    yield commitS2();
-
-    yield s1.writePeer(s2p);
+    await sync(0, 2, s1._server, s2._server);
+    await waitToHaveBlock(s2._server, 2)
+    let s2p = await s2.PeeringService.peer();
+
+    await s2.commit({ time: now + 37180 }); // <-- block#3 is a fork block, S2 is committing another one than S1 issued
+    await s2.commit({ time: now + 37180 });
+    await s2.commit({ time: now + 37180 });
+    await s2.commit({ time: now + 37180 });
+    await s2.commit({ time: now + 37180 });
+    await s2.commit({ time: now + 37180 });
+    await s2.commit({ time: now + 37180 });
+
+    await s1.writePeer(s2p);
     // Forking S1 from S2
-    yield Promise.all([
-      waitForkResolution(s1, 9),
-      CrawlerDependency.duniter.methods.pullBlocks(s1, s2p.pubkey)
+    await Promise.all([
+      waitForkResolution(s1._server, 9),
+      CrawlerDependency.duniter.methods.pullBlocks(s1._server, s2p.pubkey)
     ])
-  }));
+  })
 
   after(() => {
     return Promise.all([
@@ -223,7 +212,7 @@ describe("SelfFork", function() {
     });
 
     it('should have 2 branch', async () => {
-      const branches:any[] = await s1.BlockchainService.branches()
+      const branches = await s1.BlockchainService.branches()
       branches.should.have.length(1)
     })
   });
@@ -252,9 +241,9 @@ describe("SelfFork", function() {
       });
     });
 
-    it('should have 1 branch', () => co(function*() {
-      const branches = yield s2.BlockchainService.branches();
+    it('should have 1 branch', async () => {
+      const branches = await s2.BlockchainService.branches();
       branches.should.have.length(1);
-    }));
-  });
-});
+    })
+  })
+})
diff --git a/test/integration/branches_pending_data.js b/test/integration/branches/branches_pending_data.ts
similarity index 65%
rename from test/integration/branches_pending_data.js
rename to test/integration/branches/branches_pending_data.ts
index e4fe8f9c3d16065f1d83a04c2a3469dcf43ddcef..ca29812f524ac579b7ee6c6e626d17b351263a1d 100644
--- a/test/integration/branches_pending_data.js
+++ b/test/integration/branches/branches_pending_data.ts
@@ -11,20 +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"
+import {shutDownEngine} from "../tools/shutdown-engine"
+import {expectAnswer, expectJSON} from "../tools/http-expect"
 
-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 expectJSON     = httpTest.expectJSON;
-const expectAnswer   = httpTest.expectAnswer;
 
 const MEMORY_MODE = true;
 const commonConf = {
@@ -35,50 +29,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 +85,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 +93,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 69%
rename from test/integration/branches_revert2.js
rename to test/integration/branches/branches_revert2.ts
index 93295937b62184b760c658afbaf20e5a555e76af..f00cf81a5f6446d48b0d0668cfcb3a905944c5f2 100644
--- a/test/integration/branches_revert2.js
+++ b/test/integration/branches/branches_revert2.ts
@@ -11,24 +11,18 @@
 // 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 {ProverConstants} from "../../../app/modules/prover/lib/constants"
+import {shutDownEngine} from "../tools/shutdown-engine"
+import {expectAnswer, expectHttpCode, expectJSON} from "../tools/http-expect"
 
-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');
 
-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
-
-const expectJSON     = httpTest.expectJSON;
-const expectHttpCode = httpTest.expectHttpCode;
-const expectAnswer = httpTest.expectAnswer;
+ProverConstants.CORES_MAXIMUM_USE_IN_PARALLEL = 1
+BmaDependency.duniter.methods.noLimit(); // Disables the HTTP limiter
 
 const now = 1490000000;
 
@@ -42,16 +36,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({
+    s1 = NewTestingServer(
+      Underscore.extend({
+        name: 'bb11',
+        memory: MEMORY_MODE,
         port: '7712',
         pair: {
           pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
@@ -66,20 +60,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 s1.commit({ time: now });
+    await s1.commit({ time: now + 1 });
+    await s1.commit({ time: now + 1 });
+    await cat.sendMoney(51, toc);
+    await s1.commit({ time: now + 1 });
   });
 
   after(() => {
@@ -110,15 +102,15 @@ 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) => {
+    it('/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd should have nothing left because of garbaging', function() {
+      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,18 +125,18 @@ 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);
       });
     });
   })
 
-  describe("after revert", () => {
+  describe("after revert of transaction", () => {
 
-    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 +156,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 +167,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,21 +178,60 @@ 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);
       });
     });
   })
 
+  describe("after revert of UD", () => {
+
+    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 }), {
+        number: 0
+      });
+    });
+
+    it('/block/2 should NOT exist', function() {
+      return expectHttpCode(404, rp('http://127.0.0.1:7712/blockchain/block/2', { json: true }));
+    });
+
+    it('/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd should have nothing', function() {
+      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 nothing', function() {
+      return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo'), (body:string) => {
+        let res = JSON.parse(body);
+        res.sources.should.have.length(0)
+      });
+    });
+
+    it('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV should have nothing', function() {
+      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)
+      });
+    });
+  })
+
   describe("commit again (but send less, to check that the account is not cleaned this time)", () => {
 
-    before(() => co(function*() {
-      yield s1.dal.txsDAL.sqlDeleteAll()
-      yield cat.sendP(19, toc);
-      yield s1.dal.blockDAL.exec('DELETE FROM block WHERE fork AND number = 3')
-      yield commit(s1)({ time: now + 1 });
-    }))
+    before(async () => {
+      await s1.dal.txsDAL.removeAll()
+      await s1.resolveExistingBlock(1) // UD block
+      await cat.sendMoney(19, toc);
+      await s1.dal.blockDAL.removeBlock('DELETE FROM block WHERE fork AND number = 3')
+      await s1.commit({ 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 +254,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 +265,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 +280,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 b586b053ecb079cd2a5b71adec5227f766e5841e..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.exec('DELETE FROM block WHERE fork AND number = 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 59%
rename from test/integration/branches_switch.ts
rename to test/integration/branches/branches_switch.ts
index 08a13ed914bb8fd97550f455e37e44b34ae96a02..94786b98c734bd41fe80d35c8d5b6c6ad96c1242 100644
--- a/test/integration/branches_switch.ts
+++ b/test/integration/branches/branches_switch.ts
@@ -11,23 +11,17 @@
 // 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"
-
-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
+import {Underscore} from "../../../app/lib/common-libs/underscore"
+import {BmaDependency} from "../../../app/modules/bma/index"
+import {CrawlerDependency} from "../../../app/modules/crawler/index"
+import {NewTestingServer, TestingServer} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
+import {sync} from "../tools/test-sync"
+import {shutDownEngine} from "../tools/shutdown-engine"
+import {expectJSON} from "../tools/http-expect"
+
 const rp        = require('request-promise');
-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 expectJSON     = httpTest.expectJSON;
 
 const MEMORY_MODE = true;
 const commonConf = {
@@ -39,18 +33,18 @@ const commonConf = {
   sigQty: 1
 };
 
-let s1:any, s2:any, cat, toc
+let s1:TestingServer, s2:TestingServer, cat:TestUser, toc:TestUser
 
 describe("Switch", function() {
 
-  before(() => co(function *() {
+  before(async () => {
 
     cluster.setMaxListeners(6)
 
-    s1 = duniter(
-      '/bb11',
-      MEMORY_MODE,
-      _.extend({
+    s1 = NewTestingServer(
+      Underscore.extend({
+        name: 'bb11',
+        memory: MEMORY_MODE,
         switchOnHeadAdvance: 0,
         port: '7788',
         pair: {
@@ -61,10 +55,10 @@ describe("Switch", function() {
         sigQty: 1, dt: 1, ud0: 120
       }, commonConf));
 
-    s2 = duniter(
-      '/bb12',
-      MEMORY_MODE,
-      _.extend({
+    s2 = NewTestingServer(
+      Underscore.extend({
+        name: 'bb12',
+        memory: MEMORY_MODE,
         switchOnHeadAdvance: 0,
         port: '7789',
         pair: {
@@ -76,41 +70,41 @@ describe("Switch", function() {
     cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
     toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
 
-    yield s1.initWithDAL().then(bma).then((bmapi:any) => bmapi.openConnections());
-    yield s2.initWithDAL().then(bma).then((bmapi:any) => bmapi.openConnections());
-    s1.addEndpointsDefinitions(() => BmaDependency.duniter.methods.getMainEndpoint(s1.conf))
-    s2.addEndpointsDefinitions(() => BmaDependency.duniter.methods.getMainEndpoint(s2.conf))
-    yield cat.createIdentity();
-    yield toc.createIdentity();
-    yield toc.cert(cat);
-    yield cat.cert(toc);
-    yield cat.join();
-    yield toc.join();
-    yield commit(s1)();
-    yield commit(s1)();
-    yield commit(s1)();
-    yield sync(0, 2, s1, s2);
-
-    let s2p = yield s2.PeeringService.peer();
-
-    yield commit(s1)();
-    yield commit(s1)();
-    yield commit(s2)();
-    yield commit(s2)();
-    yield commit(s2)();
-    yield commit(s2)();
-    yield commit(s2)();
-    yield commit(s2)();
-    yield commit(s2)();
+    await s1.initWithDAL().then(BmaDependency.duniter.methods.bma).then((bmapi:any) => bmapi.openConnections());
+    await s2.initWithDAL().then(BmaDependency.duniter.methods.bma).then((bmapi:any) => bmapi.openConnections());
+    s1._server.addEndpointsDefinitions(() => BmaDependency.duniter.methods.getMainEndpoint(s1.conf))
+    s2._server.addEndpointsDefinitions(() => BmaDependency.duniter.methods.getMainEndpoint(s2.conf))
+    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 s1.commit();
+    await sync(0, 2, s1._server, s2._server);
+
+    let s2p = await s2.PeeringService.peer();
+
+    await s1.commit();
+    await s1.commit();
+    await s2.commit();
+    await s2.commit();
+    await s2.commit();
+    await s2.commit();
+    await s2.commit();
+    await s2.commit();
+    await s2.commit();
     // So we now have:
     // S1 01234
     // S2   `3456789
-    yield s1.writePeer(s2p)
+    await s1.writePeer(s2p)
 
     // Forking S1 from S2
-    yield CrawlerDependency.duniter.methods.pullBlocks(s1, s2p.pubkey);
+    await CrawlerDependency.duniter.methods.pullBlocks(s1._server, s2p.pubkey);
     // S1 should have switched to the other branch
-  }));
+  })
 
   after(() => {
     cluster.setMaxListeners(3)
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 b40919e7d0fd6555bd9121fa0fe1b80cbb0ded14..0000000000000000000000000000000000000000
--- a/test/integration/branches_revert_memberships.js
+++ /dev/null
@@ -1,273 +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 bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const TestUser  = require('./tools/TestUser').TestUser
-const commit    = require('./tools/commit');
-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 66%
rename from test/integration/certification_chainability.js
rename to test/integration/certification/certification_chainability.ts
index 5ca1cf28343a2e0533827e57969cb1cdab9b9615..d232c9d13fb90af88060454383cc11f71620c55d 100644
--- a/test/integration/certification_chainability.js
+++ b/test/integration/certification/certification_chainability.ts
@@ -11,21 +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"
+import {shutDownEngine} from "../tools/shutdown-engine"
+import {expectAnswer} from "../tools/http-expect"
 
-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 expectAnswer   = httpTest.expectAnswer;
 
 const MEMORY_MODE = true;
 const commonConf = {
@@ -37,16 +32,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 +56,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 +96,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/documents-currency.ts b/test/integration/documents-currency.ts
index eb135a09947a8a311dd3797cf0e567698859e6e8..1aeb9edc33c3f6d3a86270a59074136bded3db1f 100644
--- a/test/integration/documents-currency.ts
+++ b/test/integration/documents-currency.ts
@@ -12,14 +12,10 @@
 // GNU Affero General Public License for more details.
 
 
-import { NewTestingServer, TestingServer } from './tools/toolbox';
-import { unlock } from '../../app/lib/common-libs/txunlock';
-import { ConfDTO, CurrencyConfDTO } from '../../app/lib/dto/ConfDTO';
-import { Server } from '../../server';
+import {NewTestingServer} from './tools/toolbox';
+import {TestUser} from "./tools/TestUser"
 
-const co        = require('co');
 const should    = require('should');
-const TestUser  = require('./tools/TestUser').TestUser
 
 let s1:any, s2:any, cat1:any, tac1:any, toc2:any, tic2:any;
 
@@ -27,7 +23,7 @@ describe("Document pool currency", function() {
 
   const now = 1500000000
 
-  before(() => co(function*() {
+  before(async () => {
 
     s1 = NewTestingServer({
       currency: 'currency_one',
@@ -52,19 +48,19 @@ describe("Document pool currency", function() {
     toc2 = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s2 });
     tic2 = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s2 });
 
-    yield s1.prepareForNetwork();
-    yield s2.prepareForNetwork();
+    await s1.prepareForNetwork();
+    await s2.prepareForNetwork();
 
     // Publishing identities
-    yield cat1.createIdentity();
-    yield tac1.createIdentity();
-    yield cat1.join();
-    yield tac1.join();
-    yield toc2.createIdentity();
-    yield tic2.createIdentity();
-    yield toc2.join();
-    yield tic2.join();
-  }));
+    await cat1.createIdentity();
+    await tac1.createIdentity();
+    await cat1.join();
+    await tac1.join();
+    await toc2.createIdentity();
+    await tic2.createIdentity();
+    await toc2.join();
+    await tic2.join();
+  })
 
   after(() => {
     return Promise.all([
@@ -73,95 +69,95 @@ describe("Document pool currency", function() {
     ])
   })
 
-  it('Identity with wrong currency should be rejected', () => co(function*() {
-    const idtyCat1 = yield s1.lookup2identity(cat1.pub);
+  it('Identity with wrong currency should be rejected', async () => {
+    const idtyCat1 = await s1.lookup2identity(cat1.pub);
     idtyCat1.getRawSigned()
     try {
-      yield s2.postIdentity(idtyCat1);
+      await s2.postIdentity(idtyCat1);
       throw "Identity should not have been accepted, since it has an unknown currency name";
     } catch (e) {
       should.exist(e.error);
       e.should.be.an.Object();
       e.error.message.should.match(/Signature does not match/);
     }
-  }));
+  })
 
-  it('Identity absorption with wrong currency should be rejected', () => co(function*() {
+  it('Identity absorption with wrong currency should be rejected', async () => {
     try {
-      const cert = yield toc2.makeCert(cat1, s1);
-      yield s2.postCert(cert);
+      const cert = await toc2.makeCert(cat1, s1);
+      await s2.postCert(cert);
       throw "Certification should not have been accepted, since it has an unknown currency name";
     } catch (e) {
       should.exist(e.error);
       e.should.be.an.Object();
       e.error.message.should.match(/Signature does not match/);
     }
-  }));
+  })
 
-  it('Certification with wrong currency should be rejected', () => co(function*() {
+  it('Certification with wrong currency should be rejected', async () => {
     try {
-      const cert = yield toc2.makeCert(tic2, null, {
+      const cert = await toc2.makeCert(tic2, null, {
         currency: "wrong_currency"
       });
-      yield s2.postCert(cert);
+      await s2.postCert(cert);
       throw "Certification should not have been accepted, since it has an unknown currency name";
     } catch (e) {
       should.exist(e.error);
       e.should.be.an.Object();
       e.error.message.should.match(/Wrong signature for certification/);
     }
-  }));
+  })
 
-  it('Membership with wrong currency should be rejected', () => co(function*() {
+  it('Membership with wrong currency should be rejected', async () => {
     try {
-      const join = yield toc2.makeMembership('IN', null, {
+      const join = await toc2.makeMembership('IN', null, {
         currency: "wrong_currency"
       });
-      yield s2.postMembership(join);
+      await s2.postMembership(join);
       throw "Membership should not have been accepted, since it has an unknown currency name";
     } catch (e) {
       should.exist(e.error);
       e.should.be.an.Object();
       e.error.message.should.match(/wrong signature for membership/);
     }
-  }));
+  })
 
-  it('Revocation with wrong currency should be rejected', () => co(function*() {
+  it('Revocation with wrong currency should be rejected', async () => {
     try {
-      const revocation = yield toc2.makeRevocation(null, {
+      const revocation = await toc2.makeRevocation(null, {
         currency: "wrong_currency"
       });
-      yield s2.postRevocation(revocation);
+      await s2.postRevocation(revocation);
       throw "Revocation should not have been accepted, since it has an unknown currency name";
     } catch (e) {
       should.exist(e.error);
       e.should.be.an.Object();
       e.error.message.should.match(/Wrong signature for revocation/);
     }
-  }));
+  })
 
-  it('Block with wrong currency should be rejected', () => co(function*() {
-    yield toc2.cert(tic2);
-    yield tic2.cert(toc2);
-    yield s2.commit();
-    const b2 = yield s2.makeNext({ currency: "wrong_currency" });
+  it('Block with wrong currency should be rejected', async () => {
+    await toc2.cert(tic2);
+    await tic2.cert(toc2);
+    await s2.commit();
+    const b2 = await s2.makeNext({ currency: "wrong_currency" });
     try {
-      yield s2.postBlock(b2);
+      await s2.postBlock(b2);
       throw "Currency should have been rejected";
     } catch (e) {
       should.exist(e.error);
       e.should.be.an.Object();
       e.error.message.should.match(/Wrong currency/);
     }
-  }));
+  })
 
-  it('Transaction with wrong currency should be rejected', () => co(function*() {
+  it('Transaction with wrong currency should be rejected', async () => {
     try {
-      yield cat1.cert(tac1);
-      yield tac1.cert(cat1);
-      yield s1.commit({ time: now });
-      yield s1.commit({ time: now });
-      const current = yield s1.get('/blockchain/current');
+      await cat1.cert(tac1);
+      await tac1.cert(cat1);
+      await s1.commit({ time: now });
+      await s1.commit({ time: now });
+      const current = await s1.get('/blockchain/current');
       const tx = cat1.makeTX(
         [{
           src: "1500:0:D:DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo:1",
@@ -176,18 +172,18 @@ describe("Document pool currency", function() {
           currency: "wrong_currency",
           blockstamp: [current.number, current.hash].join('-')
         });
-      yield s1.postRawTX(tx);
+      await s1.postRawTX(tx);
       throw "Transaction should not have been accepted, since it has an unknown currency name";
     } catch (e) {
       should.exist(e.error);
       e.should.be.an.Object();
       e.error.message.should.match(/Signature from a transaction must match/);
     }
-  }));
+  })
 
-  it('Transaction with wrong XHX should be rejected', () => co(function*() {
+  it('Transaction with wrong XHX should be rejected', async () => {
     try {
-      const current = yield s1.get('/blockchain/current');
+      const current = await s1.get('/blockchain/current');
       const tx = cat1.makeTX(
         [{
           src: "1500:1:D:HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd:1",
@@ -201,27 +197,27 @@ describe("Document pool currency", function() {
         {
           blockstamp: [current.number, current.hash].join('-')
         });
-      yield s1.postRawTX(tx);
+      await s1.postRawTX(tx);
       throw "Transaction should not have been accepted, since it has wrong output format";
     } catch (e) {
       should.exist(e.error);
       e.should.be.an.Object();
       e.error.message.should.match(/Wrong output format/);
     }
-  }));
+  })
 
-  it('Peer with wrong currency should be rejected', () => co(function*() {
+  it('Peer with wrong currency should be rejected', async () => {
     try {
-      const peer = yield toc2.makePeer(['BASIC_MERKLED_API localhost 10901'], {
+      const peer = await toc2.makePeer(['BASIC_MERKLED_API localhost 10901'], {
         version: 10,
         currency: "wrong_currency"
       });
-      yield s2.postPeer(peer);
+      await s2.postPeer(peer);
       throw "Peer should not have been accepted, since it has an unknown currency name";
     } catch (e) {
       should.exist(e.error);
       e.should.be.an.Object();
       e.error.message.should.match(/Signature from a peer must match/);
     }
-  }));
-});
+  })
+})
diff --git a/test/integration/register-fork-blocks.js b/test/integration/fork-resolution/register-fork-blocks.ts
similarity index 55%
rename from test/integration/register-fork-blocks.js
rename to test/integration/fork-resolution/register-fork-blocks.ts
index b31bbe2d75b2e8f39c60a44700e0af80d1002d9f..d976ad2ccb8052d486c1d3629d12564aa85dbabf 100644
--- a/test/integration/register-fork-blocks.js
+++ b/test/integration/fork-resolution/register-fork-blocks.ts
@@ -11,26 +11,24 @@
 // 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 {CommonConstants} from "../../../app/lib/common-libs/constants"
+import {BlockDTO} from "../../../app/lib/dto/BlockDTO"
+import {HttpBranches} from "../../../app/modules/bma/lib/dtos"
 
-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');
-const CommonConstants = require('../../app/lib/common-libs/constants').CommonConstants
 
 const now = 1500000000
 const forksize = 10
 
-let s1, s2, s3, cat1, tac1, toc1
+let s1:TestingServer, s2:TestingServer, s3:TestingServer, cat1:TestUser, tac1:TestUser, toc1:TestUser
 
 describe("Fork blocks", function() {
 
-  before(() => co(function*() {
+  before(async () => {
 
-    s1 = toolbox.server({
+    s1 = NewTestingServer({
 
       // The common conf
       nbCores:1,
@@ -46,7 +44,7 @@ describe("Fork blocks", function() {
       }
     });
 
-    s2 = toolbox.server({
+    s2 = NewTestingServer({
 
       // Particular conf
       nbCores:1,
@@ -59,7 +57,7 @@ describe("Fork blocks", function() {
       }
     });
 
-    s3 = toolbox.server({
+    s3 = NewTestingServer({
 
       // Particular conf
       nbCores:1,
@@ -76,21 +74,21 @@ describe("Fork blocks", function() {
     tac1 = new TestUser('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
     toc1 = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
 
-    yield s1.prepareForNetwork();
-    yield s2.prepareForNetwork();
-    yield s3.prepareForNetwork();
+    await s1.prepareForNetwork();
+    await s2.prepareForNetwork();
+    await s3.prepareForNetwork();
 
     // Publishing identities
-    yield cat1.createIdentity();
-    yield tac1.createIdentity();
-    yield toc1.createIdentity();
-    yield cat1.cert(tac1);
-    yield tac1.cert(cat1);
-    yield tac1.cert(toc1);
-    yield cat1.join();
-    yield tac1.join();
-    yield toc1.join();
-  }));
+    await cat1.createIdentity();
+    await tac1.createIdentity();
+    await toc1.createIdentity();
+    await cat1.cert(tac1);
+    await tac1.cert(cat1);
+    await tac1.cert(toc1);
+    await cat1.join();
+    await tac1.join();
+    await toc1.join();
+  })
 
   after(() => {
     return Promise.all([
@@ -100,85 +98,85 @@ describe("Fork blocks", function() {
     ])
   })
 
-  it('should create a common blockchain', () => co(function*() {
-    const b0 = yield s1.commit({ time: now })
-    const b1 = yield s1.commit({ time: now + 11 })
-    const b2 = yield s1.commit({ time: now + 22 })
-    yield s2.writeBlock(b0)
-    yield s2.writeBlock(b1)
-    yield s2.writeBlock(b2)
-    yield s3.writeBlock(b0)
-    yield s3.writeBlock(b1)
-    yield s3.writeBlock(b2)
-    yield s2.waitToHaveBlock(2)
-    yield s3.waitToHaveBlock(2)
-  }))
-
-  it('should exist the same block on each node', () => co(function*() {
-    yield s1.expectJSON('/blockchain/current', {
+  it('should create a common blockchain', async () => {
+    const b0 = await s1.commit({ time: now })
+    const b1 = await s1.commit({ time: now + 11 })
+    const b2 = await s1.commit({ time: now + 22 })
+    await s2.writeBlock(b0)
+    await s2.writeBlock(b1)
+    await s2.writeBlock(b2)
+    await s3.writeBlock(b0)
+    await s3.writeBlock(b1)
+    await s3.writeBlock(b2)
+    await s2.waitToHaveBlock(2)
+    await s3.waitToHaveBlock(2)
+  })
+
+  it('should exist the same block on each node', async () => {
+    await s1.expectJSON('/blockchain/current', {
       number: 2
     })
-    yield s2.expectJSON('/blockchain/current', {
+    await s2.expectJSON('/blockchain/current', {
       number: 2
     })
-  }))
-
-  it('should be able to fork, and notify each node', () => co(function*() {
-    const b3a = yield s1.commit({ time: now + 33 })
-    const b3b = yield s2.commit({ time: now + 33 })
-    yield s1.writeBlock(b3b)
-    yield s2.writeBlock(b3a)
-    yield s1.waitToHaveBlock(3)
-    yield s2.waitToHaveBlock(3)
-  }))
-
-  it('should exist a different third block on each node', () => co(function*() {
-    yield s1.expectJSON('/blockchain/current', {
+  })
+
+  it('should be able to fork, and notify each node', async () => {
+    const b3a = await s1.commit({ time: now + 33 })
+    const b3b = await s2.commit({ time: now + 33 })
+    await s1.writeBlock(b3b)
+    await s2.writeBlock(b3a)
+    await s1.waitToHaveBlock(3)
+    await s2.waitToHaveBlock(3)
+  })
+
+  it('should exist a different third block on each node', async () => {
+    await s1.expectJSON('/blockchain/current', {
       number: 3,
       hash: "74AB356F0E6CD9AA6F752E58FFCD65D5F8C95CDAA93576A40457CC3598C4E3D1"
     })
-    yield s2.expectJSON('/blockchain/current', {
+    await s2.expectJSON('/blockchain/current', {
       number: 3,
       hash: "2C3555F4009461C81F7209EAAD7DA831D8451708D06BB1173CCB40746CD0641B"
     })
-  }))
+  })
 
-  it('should exist both branches on each node', () => co(function*() {
-    yield s1.expect('/blockchain/branches', (res) => {
+  it('should exist both branches on each node', async () => {
+    await s1.expect('/blockchain/branches', (res:HttpBranches) => {
       assert.equal(res.blocks.length, 2)
       assert.equal(res.blocks[0].number, 3)
       assert.equal(res.blocks[0].hash, '2C3555F4009461C81F7209EAAD7DA831D8451708D06BB1173CCB40746CD0641B')
       assert.equal(res.blocks[1].number, 3)
       assert.equal(res.blocks[1].hash, '74AB356F0E6CD9AA6F752E58FFCD65D5F8C95CDAA93576A40457CC3598C4E3D1')
     })
-    yield s2.expect('/blockchain/branches', (res) => {
+    await s2.expect('/blockchain/branches', (res:HttpBranches) => {
       assert.equal(res.blocks.length, 2)
       assert.equal(res.blocks[0].number, 3)
       assert.equal(res.blocks[0].hash, '74AB356F0E6CD9AA6F752E58FFCD65D5F8C95CDAA93576A40457CC3598C4E3D1')
       assert.equal(res.blocks[1].number, 3)
       assert.equal(res.blocks[1].hash, '2C3555F4009461C81F7209EAAD7DA831D8451708D06BB1173CCB40746CD0641B')
     })
-  }))
-
-  let b4a, b5a, b6a, b7a, b8a
-
-  it('should be able to grow S1\'s blockchain', () => co(function*() {
-    b4a = yield s1.commit({time: now + 44})
-    b5a = yield s1.commit({time: now + 55})
-    b6a = yield s1.commit({time: now + 66})
-    b7a = yield s1.commit({time: now + 77})
-    b8a = yield s1.commit({time: now + 88})
-    yield s1.waitToHaveBlock(8)
-  }))
-
-  it('should refuse known fork blocks', () => co(function*() {
-    yield s1.sharePeeringWith(s2)
-    yield s2.sharePeeringWith(s1)
-    yield s2.writeBlock(b4a)
-    const b3c = yield s3.commit({ time: now + 33 })
-    yield new Promise((res, rej) => {
+  })
+
+  let b4a:BlockDTO, b5a:BlockDTO, b6a:BlockDTO, b7a:BlockDTO, b8a:BlockDTO
+
+  it('should be able to grow S1\'s blockchain', async () => {
+    b4a = (await s1.commit({time: now + 44})) as BlockDTO
+    b5a = (await s1.commit({time: now + 55})) as BlockDTO
+    b6a = (await s1.commit({time: now + 66})) as BlockDTO
+    b7a = (await s1.commit({time: now + 77})) as BlockDTO
+    b8a = (await s1.commit({time: now + 88})) as BlockDTO
+    await s1.waitToHaveBlock(8)
+  })
+
+  it('should refuse known fork blocks', async () => {
+    await s1.sharePeeringWith(s2)
+    await s2.sharePeeringWith(s1)
+    await s2.writeBlock(b4a)
+    const b3c = await s3.commit({ time: now + 33 })
+    await new Promise((res, rej) => {
       const event = CommonConstants.DocumentError
-      s2.on(event, (e) => {
+      s2.on(event, (e:any) => {
         try {
           assert.equal(e, 'Block already known')
           res()
@@ -189,46 +187,48 @@ describe("Fork blocks", function() {
       // Trigger the third-party fork block writing
       s2.writeBlock(b3c)
     })
-  }))
-
-  it('should be able to make one fork grow enough to make one node switch', () => co(function*() {
-    yield s2.writeBlock(b5a)
-    yield s2.writeBlock(b6a)
-    yield s2.writeBlock(b7a)
-    yield s2.writeBlock(b8a)
-    yield s2.waitToHaveBlock(8)
-    yield s2.waitForkResolution(8)
-  }))
-
-  it('should exist a same current block on each node', () => co(function*() {
-    yield s1.expectJSON('/blockchain/current', {
+  })
+
+  it('should be able to make one fork grow enough to make one node switch', async () => {
+    await s2.writeBlock(b5a)
+    await s2.writeBlock(b6a)
+    await s2.writeBlock(b7a)
+    await s2.writeBlock(b8a)
+    await Promise.all([
+      s2.waitToHaveBlock(8),
+      s2.waitForkResolution(8)
+    ])
+  })
+
+  it('should exist a same current block on each node', async () => {
+    await s1.expectJSON('/blockchain/current', {
       number: 8,
       hash: "B8D2AA2A5556F7A2837FB4B881FCF50595F855D0BF8F71C0B432E27216BBA40B"
     })
-    yield s2.expectJSON('/blockchain/current', {
+    await s2.expectJSON('/blockchain/current', {
       number: 8,
       hash: "B8D2AA2A5556F7A2837FB4B881FCF50595F855D0BF8F71C0B432E27216BBA40B"
     })
-  }))
+  })
 
-  it('should exist 2 branches on each node', () => co(function*() {
-    yield s1.expect('/blockchain/branches', (res) => {
+  it('should exist 2 branches on each node', async () => {
+    await s1.expect('/blockchain/branches', (res:HttpBranches) => {
       assert.equal(res.blocks.length, 3)
       assert.equal(res.blocks[0].number, 3)
-      assert.equal(res.blocks[0].hash, '9A0FA1F0899124444ADC5B2C0AB66AC5B4303A0D851BED2E7382BB57E10AA2C5')
+      assert.equal(res.blocks[0].hash, '2C3555F4009461C81F7209EAAD7DA831D8451708D06BB1173CCB40746CD0641B') // This is s2 fork!
       assert.equal(res.blocks[1].number, 3)
-      assert.equal(res.blocks[1].hash, '2C3555F4009461C81F7209EAAD7DA831D8451708D06BB1173CCB40746CD0641B') // This is s2 fork!
+      assert.equal(res.blocks[1].hash, '9A0FA1F0899124444ADC5B2C0AB66AC5B4303A0D851BED2E7382BB57E10AA2C5')
       assert.equal(res.blocks[2].number, 8)
       assert.equal(res.blocks[2].hash, 'B8D2AA2A5556F7A2837FB4B881FCF50595F855D0BF8F71C0B432E27216BBA40B')
     })
-    yield s2.expect('/blockchain/branches', (res) => {
+    await s2.expect('/blockchain/branches', (res:HttpBranches) => {
       assert.equal(res.blocks.length, 3)
       assert.equal(res.blocks[0].number, 3)
-      assert.equal(res.blocks[0].hash, '9A0FA1F0899124444ADC5B2C0AB66AC5B4303A0D851BED2E7382BB57E10AA2C5')
+      assert.equal(res.blocks[0].hash, '2C3555F4009461C81F7209EAAD7DA831D8451708D06BB1173CCB40746CD0641B') // This is s2 fork!
       assert.equal(res.blocks[1].number, 3)
-      assert.equal(res.blocks[1].hash, '2C3555F4009461C81F7209EAAD7DA831D8451708D06BB1173CCB40746CD0641B') // This is s2 fork!
+      assert.equal(res.blocks[1].hash, '9A0FA1F0899124444ADC5B2C0AB66AC5B4303A0D851BED2E7382BB57E10AA2C5')
       assert.equal(res.blocks[2].number, 8)
       assert.equal(res.blocks[2].hash, 'B8D2AA2A5556F7A2837FB4B881FCF50595F855D0BF8F71C0B432E27216BBA40B')
     })
-  }))
-});
+  })
+})
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-absorption.js b/test/integration/identity/identity-absorption.ts
similarity index 62%
rename from test/integration/identity-absorption.js
rename to test/integration/identity/identity-absorption.ts
index 3335529e5d17b8334e588e120002094becdfd659..4ee1051e018870ed5beecdeadabf905a1427465e 100644
--- a/test/integration/identity-absorption.js
+++ b/test/integration/identity/identity-absorption.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 {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"
+import {shutDownEngine} from "../tools/shutdown-engine"
+import {expectAnswer} from "../tools/http-expect"
 
-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 expectAnswer   = httpTest.expectAnswer;
 
 const MEMORY_MODE = true;
 const commonConf = {
@@ -36,16 +33,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 +53,7 @@ describe("Identity absorption", function() {
     s2 = duniter(
       '/bb12',
       MEMORY_MODE,
-      _.extend({
+      Underscore.extend({
         port: '4451',
         pair: {
           pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV',
@@ -67,12 +64,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 +77,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 63%
rename from test/integration/identity-clean-test.js
rename to test/integration/identity/identity-clean-test.ts
index a042d79d8dbe8f2a7d87cdef5e936da0fa4f31ba..2a40b596cd4837ea2c7fb7c3169cc6caca83e798 100644
--- a/test/integration/identity-clean-test.js
+++ b/test/integration/identity/identity-clean-test.ts
@@ -11,19 +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 {HttpMembers} from "../../../app/modules/bma/lib/dtos"
+import {shutDownEngine} from "../tools/shutdown-engine"
+import {expectAnswer} from "../tools/http-expect"
 
-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 commit    = require('./tools/commit');
-const shutDownEngine  = require('./tools/shutDownEngine');
-
-const expectAnswer   = httpTest.expectAnswer;
 
 const MEMORY_MODE = true;
 const commonConf = {
@@ -36,16 +32,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({
+    s1 = NewTestingServer(
+      Underscore.extend({
+        name: 'bb12',
+        memory: MEMORY_MODE,
         port: '7733',
         pair: {
           pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
@@ -58,33 +54,29 @@ describe("Identities cleaned", function() {
     toc = new TestUser('cat', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
     tac = new TestUser('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
 
-    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();
+    await s1.initWithDAL().then(BmaDependency.duniter.methods.bma).then((bmapi) => bmapi.openConnections());
+    await cat.createIdentity();
+    await tic.createIdentity();
+    await 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
-      });
+    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
+    });
 
-      yield cat.cert(tic);
-      yield tic.cert(cat);
-      yield cat.join();
-      yield tic.join();
-      yield commitS1();
+    await cat.cert(tic);
+    await tic.cert(cat);
+    await cat.join();
+    await tic.join();
+    await s1.commit()
 
-      // We have the following WoT (diameter 1):
+    // We have the following WoT (diameter 1):
 
-      /**
-       *  cat <-> tic
-       */
-    });
+    /**
+     *  cat <-> tic
+     */
   });
 
   after(() => {
@@ -94,14 +86,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 +101,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..9085e381afc640a6bba6fb368242ebe844761931
--- /dev/null
+++ b/test/integration/identity/identity-expiry.ts
@@ -0,0 +1,106 @@
+// 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"
+import {shutDownEngine} from "../tools/shutdown-engine"
+import {expectAnswer, expectError} from "../tools/http-expect"
+
+const should    = require('should');
+const rp        = require('request-promise');
+
+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-implicit-revocation.js b/test/integration/identity/identity-implicit-revocation.ts
similarity index 63%
rename from test/integration/identity-implicit-revocation.js
rename to test/integration/identity/identity-implicit-revocation.ts
index 1037ebad4e5c5b8ef4eafc4229948b94b34a8956..728b31c89229c5158c9b86d6d3c9153d3617a65e 100644
--- a/test/integration/identity-implicit-revocation.js
+++ b/test/integration/identity/identity-implicit-revocation.ts
@@ -11,27 +11,23 @@
 // 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 {FullMindexEntry} from "../../../app/lib/indexer"
+import {HttpBlock, HttpLookup} from "../../../app/modules/bma/lib/dtos"
 
-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("Implicit revocation", function() {
 
-  before(() => co(function *() {
+  before(async () => {
 
-    s1 = toolbox.server({
+    s1 = NewTestingServer({
       pair: {
         pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
         sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
@@ -46,31 +42,31 @@ describe("Implicit revocation", 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 tic.createIdentity();
-    yield cat.cert(tac);
-    yield tac.cert(tic);
-    yield tic.cert(cat);
-    yield cat.join();
-    yield tac.join();
-    yield tic.join();
-    yield s1.commit({ time: now });
-    yield s1.commit({ time: now + 8 });
-    yield s1.commit({ time: now + 9 });
-    yield cat.join();
-    yield tac.join();
-    yield s1.commit({ time: now + 10 });
-    yield s1.commit({ time: now + 10 });
-    yield s1.commit({ time: now + 11 });
-    yield s1.commit({ time: now + 15 });
-    yield s1.commit({ time: now + 15 });
-    yield cat.join();
-    yield tac.join();
-    yield s1.commit({ time: now + 20 });
-    yield s1.commit({ time: now + 20 });
-  }));
+    await s1.initDalBmaConnections();
+    await cat.createIdentity();
+    await tac.createIdentity();
+    await tic.createIdentity();
+    await cat.cert(tac);
+    await tac.cert(tic);
+    await tic.cert(cat);
+    await cat.join();
+    await tac.join();
+    await tic.join();
+    await s1.commit({ time: now });
+    await s1.commit({ time: now + 8 });
+    await s1.commit({ time: now + 9 });
+    await cat.join();
+    await tac.join();
+    await s1.commit({ time: now + 10 });
+    await s1.commit({ time: now + 10 });
+    await s1.commit({ time: now + 11 });
+    await s1.commit({ time: now + 15 });
+    await s1.commit({ time: now + 15 });
+    await cat.join();
+    await tac.join();
+    await s1.commit({ time: now + 20 });
+    await s1.commit({ time: now + 20 });
+  })
 
   after(() => {
     return Promise.all([
@@ -78,18 +74,18 @@ describe("Implicit revocation", function() {
     ])
   })
 
-  it('block#4 should have kicked tic', () => s1.expectThat('/blockchain/block/5', (res) => {
+  it('block#4 should have kicked tic', () => s1.expectThat('/blockchain/block/5', (res:HttpBlock) => {
     assert.deepEqual(res.excluded, [
       'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV'
     ]);
   }));
 
-  it('should exist implicit revocation traces', () => co(function*() {
-    const ms = yield s1.dal.mindexDAL.getReducedMS('DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV')
+  it('should exist implicit revocation traces', async () => {
+    const ms = (await s1.dal.mindexDAL.getReducedMS('DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV')) as FullMindexEntry
     ms.should.have.property('revoked_on').equal(1480000020)
-  }));
+  })
 
-  it('should answer that tic is revoked on API', () => s1.expectThat('/wot/lookup/tic', (res) => {
+  it('should answer that tic is revoked on API', () => s1.expectThat('/wot/lookup/tic', (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('tic');
diff --git a/test/integration/identity-kicking-by-certs.js b/test/integration/identity/identity-kicking-by-certs.ts
similarity index 64%
rename from test/integration/identity-kicking-by-certs.js
rename to test/integration/identity/identity-kicking-by-certs.ts
index c9e2274c2cc0f46d5fca835579bda372350fed04..ecf3f46202bf44c05a2984ecd30a732a2cbf9f6b 100644
--- a/test/integration/identity-kicking-by-certs.js
+++ b/test/integration/identity/identity-kicking-by-certs.ts
@@ -11,22 +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 {HttpBlock} from "../../../app/modules/bma/lib/dtos"
 
-const co        = require('co');
 const assert    = require('assert');
-const TestUser  = require('./tools/TestUser').TestUser
-const toolbox   = require('./tools/toolbox');
 
 const now = 1480000000;
 
-let s1, cat, tac, tic, toc, tuc
+let s1:TestingServer, cat:TestUser, tac:TestUser, tic:TestUser, toc:TestUser, tuc:TestUser
 
 describe("Identities kicking by certs", function() {
 
-  before(() => co(function *() {
+  before(async () => {
 
-    s1 = toolbox.server({
+    s1 = NewTestingServer({
       pair: {
         pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
         sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
@@ -44,41 +43,41 @@ describe("Identities kicking by certs", function() {
     toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
     tuc = new TestUser('tuc', { pub: '3conGDUXdrTGbQPMQQhEC4Ubu1MCAnFrAYvUaewbUhtk', sec: '5ks7qQ8Fpkin7ycXpxQSxxjVhs8VTzpM3vEBMqM7NfC1ZiFJ93uQryDcoM93Mj77T6hDAABdeHZJDFnkDb35bgiU'}, { server: s1 });
 
-    yield s1.initDalBmaConnections();
-    yield cat.createIdentity();
-    yield tac.createIdentity();
-    yield toc.createIdentity();
-    yield cat.cert(tac);
-    yield cat.cert(toc);
-    yield tac.cert(cat);
-    yield tac.cert(toc);
-    yield toc.cert(cat);
-    yield toc.cert(tac);
-    yield cat.join();
-    yield tac.join();
-    yield toc.join();
-    yield s1.commit({ time: now });
-    yield s1.commit({ time: now + 3 });
-    yield s1.commit({ time: now + 5 });
-    yield tic.createIdentity();
-    yield cat.cert(tic);
-    yield tac.cert(tic);
-    yield tic.join();
-    yield tuc.createIdentity();
-    yield s1.commit({ time: now + 8 });
-    yield tic.cert(cat);
-    yield cat.cert(tuc);
-    yield tac.cert(tuc);
-    yield tuc.join();
-    yield s1.commit({ time: now + 8 });
-    yield tuc.cert(cat);
-    yield s1.commit({ time: now + 8 });
-    yield s1.commit({ time: now + 8 });
-    yield s1.commit({ time: now + 8 });
-    yield cat.revoke();
-    yield s1.commitWaitError({ time: now + 8, excluded: ['3conGDUXdrTGbQPMQQhEC4Ubu1MCAnFrAYvUaewbUhtk'] }, "ruleToBeKickedArePresent")
-    yield s1.commit({ time: now + 8 });
-  }));
+    await s1.initDalBmaConnections();
+    await cat.createIdentity();
+    await tac.createIdentity();
+    await toc.createIdentity();
+    await cat.cert(tac);
+    await cat.cert(toc);
+    await tac.cert(cat);
+    await tac.cert(toc);
+    await toc.cert(cat);
+    await toc.cert(tac);
+    await cat.join();
+    await tac.join();
+    await toc.join();
+    await s1.commit({ time: now });
+    await s1.commit({ time: now + 3 });
+    await s1.commit({ time: now + 5 });
+    await tic.createIdentity();
+    await cat.cert(tic);
+    await tac.cert(tic);
+    await tic.join();
+    await tuc.createIdentity();
+    await s1.commit({ time: now + 8 });
+    await tic.cert(cat);
+    await cat.cert(tuc);
+    await tac.cert(tuc);
+    await tuc.join();
+    await s1.commit({ time: now + 8 });
+    await tuc.cert(cat);
+    await s1.commit({ time: now + 8 });
+    await s1.commit({ time: now + 8 });
+    await s1.commit({ time: now + 8 });
+    await cat.revoke();
+    await s1.commitWaitError({ time: now + 8, excluded: ['3conGDUXdrTGbQPMQQhEC4Ubu1MCAnFrAYvUaewbUhtk'] }, "ruleToBeKickedArePresent")
+    await s1.commit({ time: now + 8 });
+  })
 
   after(() => {
     return Promise.all([
@@ -86,14 +85,14 @@ describe("Identities kicking by certs", function() {
     ])
   })
 
-  it('block#7 should have kicked 2 member', () => s1.expectJSON('/blockchain/block/7', (res) => {
+  it('block#7 should have kicked 2 member', () => s1.expectJSON('/blockchain/block/7', (res:HttpBlock) => {
     assert.deepEqual(res.excluded, [
       '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc',
       'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo'
     ]);
   }));
 
-  it('block#8 should have kicked 1 member', () => s1.expectJSON('/blockchain/block/8', (res) => {
+  it('block#8 should have kicked 1 member', () => s1.expectJSON('/blockchain/block/8', (res:HttpBlock) => {
     assert.deepEqual(res.excluded, [
       'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd'
     ]);
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..dfccca03d6f85b5e7187909582a59be3cdc5ddf5 100644
--- a/test/integration/identity-kicking.js
+++ b/test/integration/identity/identity-kicking.ts
@@ -11,21 +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"
+import {shutDownEngine} from "../tools/shutdown-engine"
+import {expectAnswer} from "../tools/http-expect"
 
-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 expectAnswer   = httpTest.expectAnswer;
 
 const MEMORY_MODE = true;
 const commonConf = {
@@ -39,70 +35,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 +108,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 +118,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 +128,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 72%
rename from test/integration/lookup.js
rename to test/integration/identity/identity-lookup.ts
index 3ce8d834f1093fdd4cdae8a57747cf52db26ef61..574005094ddaa2372103c09844b52c49df265156 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"
+import {shutDownEngine} from "../tools/shutdown-engine"
+import {expectAnswer} from "../tools/http-expect"
 
-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 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', () => 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', () => 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,11 +95,11 @@ 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', () => 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');
-    res.memberships[0].should.have.property('version').equal(0);
+    res.memberships[0].should.have.property('version').equal(10);
     res.memberships[0].should.have.property('currency').equal('bb');
     res.memberships[0].should.have.property('membership').equal('IN');
     res.memberships[0].should.have.property('blockNumber').equal(0);
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 0dad545100d4a80187b62c296c5a17d21910b143..a624b121767e2519886899257f8175201dc23246 100644
--- a/test/integration/revocation-test.js
+++ b/test/integration/identity/identity-revocation-test.ts
@@ -13,20 +13,18 @@
 
 "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"
+import {shutDownEngine} from "../tools/shutdown-engine"
+import {expectAnswer} from "../tools/http-expect"
+
 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 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 +38,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 +101,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 +116,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 +127,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 +143,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 +152,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 +166,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.exec('DELETE FROM block WHERE fork AND number >= 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 +201,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 +214,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/identity-same-pubkey.js b/test/integration/identity/identity-same-pubkey.ts
similarity index 83%
rename from test/integration/identity-same-pubkey.js
rename to test/integration/identity/identity-same-pubkey.ts
index 1e1949422b208c4bafd7e4a1cc604f1b96192798..e3e0fc2cc63477fb63fa6ba3348241d8eaa45ca0 100644
--- a/test/integration/identity-same-pubkey.js
+++ b/test/integration/identity/identity-same-pubkey.ts
@@ -11,22 +11,19 @@
 // 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 {HttpLookup} from "../../../app/modules/bma/lib/dtos"
 
-const co        = require('co');
 const should    = require('should');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const TestUser  = require('./tools/TestUser').TestUser
-const commit    = require('./tools/commit');
-const toolbox   = require('./tools/toolbox');
 
-let s1, cat1, cat2, catb
+let s1:TestingServer, cat1:TestUser, cat2:TestUser, catb:TestUser
 
 describe("Identities with shared pubkey", function() {
 
-  before(() => co(function*() {
+  before(async () => {
 
-    s1 = toolbox.server({
+    s1 = NewTestingServer({
       pair: {
         pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
         sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
@@ -37,18 +34,18 @@ describe("Identities with shared pubkey", function() {
     cat2 = new TestUser('cat2', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
     catb = new TestUser('cat1', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
 
-    yield s1.initDalBmaConnections();
+    await s1.initDalBmaConnections();
 
-    yield cat2.createIdentity();
+    await cat2.createIdentity();
 
     // Early certification, to have only one matching 'HgTT' key at this moment
-    yield catb.cert(cat2);
+    await catb.cert(cat2);
 
     // catb gets certified by 'HgTT'
-    yield cat1.createIdentity();
-    yield catb.createIdentity();
-    yield cat1.cert(catb);
-  }));
+    await cat1.createIdentity();
+    await catb.createIdentity();
+    await cat1.cert(catb);
+  })
 
   after(() => {
     return Promise.all([
@@ -56,13 +53,13 @@ describe("Identities with shared pubkey", function() {
     ])
   })
 
-  it('should exit 2 pubkey result', () => s1.expect('/wot/lookup/cat', (res) => {
+  it('should exit 2 pubkey result', () => s1.expect('/wot/lookup/cat', (res:HttpLookup) => {
     res.results.should.have.length(2);
     res.results[0].should.have.property('pubkey').equal('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
     res.results[1].should.have.property('pubkey').equal('2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc');
   }));
 
-  it('pubkey HgTT should have signed 1 key', () => s1.expect('/wot/lookup/cat', (res) => {
+  it('pubkey HgTT should have signed 1 key', () => s1.expect('/wot/lookup/cat', (res:HttpLookup) => {
     res.results.should.have.length(2);
     res.results[0].should.have.property('signed').length(1);
     const pubkey_hgtt = res.results[0];
diff --git a/test/integration/identity/identity-several-tests.ts b/test/integration/identity/identity-several-tests.ts
new file mode 100644
index 0000000000000000000000000000000000000000..67621a0f15c33cba61d79a0986a34d7f3960419d
--- /dev/null
+++ b/test/integration/identity/identity-several-tests.ts
@@ -0,0 +1,304 @@
+// 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 {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"
+import {shutDownEngine} from "../tools/shutdown-engine"
+import {shouldFail} from "../../unit-tools"
+import {expectAnswer} from "../tools/http-expect"
+
+const should = require('should');
+const assert = require('assert');
+const constants = require('../../../app/lib/constants');
+const jspckg = require('../../../package');
+const rp        = require('request-promise');
+
+const MEMORY_MODE = true;
+
+BmaDependency.duniter.methods.noLimit(); // Disables the HTTP limiter
+
+describe("Integration", function() {
+
+  let node1:TestingServer, cat:TestUser, tac:TestUser, tic:TestUser, toc:TestUser
+
+  before(async () => {
+    node1 = NewTestingServer({
+      name: 'db1',
+      memory: MEMORY_MODE,
+      currency: 'bb', ipv4: 'localhost', port: 9999, remoteipv4: 'localhost', remoteport: 9999, httplogs: false,
+      rootoffset: 0,
+      sigQty: 1, sigPeriod: 0,
+      pair: {
+        pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
+        sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
+      }
+    })
+
+    cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: node1 })
+    tac = new TestUser('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: node1 })
+    tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: node1 })
+    toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: node1 })
+    await node1.initWithDAL().then(BmaDependency.duniter.methods.bma).then((bmapi) => bmapi.openConnections());
+  })
+
+  describe("Node 1", function() {
+
+    describe("Testing technical API", function(){
+
+      it('/node/summary should give package.json version', () => node1.expectJSON('/node/summary', (summary:HttpSummary) => {
+        should.exists(summary);
+        should.exists(summary.duniter);
+        should.exists(summary.duniter.software);
+        should.exists(summary.duniter.version);
+        assert.equal(summary.duniter.software, "duniter");
+        assert.equal(summary.duniter.version, jspckg.version);
+      }))
+    })
+
+    describe("Testing malformed documents", () => {
+
+      it('should not have crashed because of wrong tx', async () => {
+        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";
+
+        await shouldFail(node1.post('/tx/process', {
+          json: {
+            transaction: malformedTransaction
+          }
+        }), '400 - {"ucode":1106,"message":"Requires a transaction"}')
+      })
+    })
+
+    describe("Lookup on", function(){
+
+      before(async () => {
+
+        // Self certifications
+        await cat.createIdentity();
+        await tac.createIdentity();
+        await tic.createIdentity();
+        await toc.createIdentity();
+        // Certifications
+        await cat.cert(tac);
+      });
+
+      describe("identities collisions", () => {
+
+        it("sending same identity should fail", async () => {
+
+          // We send again the same
+          try {
+            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", async () => {
+
+          // We send again the same
+          try {
+            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.expectJSON('/wot/lookup/cat', (res:HttpLookup) => {
+          should.exists(res);
+          assert.equal(res.results.length, 1);
+        }));
+
+        it('should have sent 1 signature', () => node1.expectJSON('/wot/lookup/cat', (res:HttpLookup) => {
+          should.exists(res);
+          assert.equal(res.results[0].signed.length, 1);
+          should.exists(res.results[0].signed[0].isMember);
+          should.exists(res.results[0].signed[0].wasMember);
+          assert.equal(res.results[0].signed[0].isMember, false);
+          assert.equal(res.results[0].signed[0].wasMember, false);
+        }));
+      });
+
+      describe("user tac", function(){
+
+        it('should give only 1 result', () => node1.expectJSON('/wot/lookup/tac', (res:HttpLookup) => {
+          should.exists(res);
+          assert.equal(res.results.length, 1);
+        }));
+
+        it('should have 1 signature', () => node1.expectJSON('/wot/lookup/tac', (res:HttpLookup) => {
+          should.exists(res);
+          assert.equal(res.results[0].uids[0].others.length, 1);
+        }));
+
+        it('should have sent 0 signature', () => node1.expectJSON('/wot/lookup/tac', (res:HttpLookup) => {
+          should.exists(res);
+          assert.equal(res.results[0].signed.length, 0);
+        }));
+      });
+
+      it('toc should give only 1 result', () => node1.expectJSON('/wot/lookup/toc', (res:HttpLookup) => {
+        should.exists(res);
+        assert.equal(res.results.length, 1);
+      }));
+
+      it('tic should give only 1 result', () => node1.expectJSON('/wot/lookup/tic', (res:HttpLookup) => {
+        should.exists(res);
+        assert.equal(res.results.length, 1);
+      }));
+    });
+  });
+
+  describe("Testing leavers", function(){
+
+    let node3:TestingServer, cat:TestUser, tac:TestUser, tic:TestUser, toc:TestUser
+
+    before(async () => {
+
+      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'
+        }
+      });
+
+      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
+      });
+    });
+
+    after(() => {
+      return Promise.all([
+        shutDownEngine(node3)
+      ])
+    })
+
+    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:HttpLookup) {
+      should.exists(res);
+      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 = 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);
+      assert.equal(tac_signed.uid, "tac");
+      assert.equal(tac_signed.isMember, true);
+      assert.equal(tac_signed.wasMember, true);
+      assert.equal(toc_signed.uid, "toc");
+      assert.equal(toc_signed.isMember, true);
+      assert.equal(toc_signed.wasMember, true);
+      assert.equal(res.results[0].uids[0].others.length, 3);
+      assert.equal(res.results[0].uids[0].others[0].uids.length, 1);
+      assert.equal(res.results[0].uids[0].others[0].isMember, true);
+      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:HttpBlock) {
+      should.exists(block);
+      assert.equal(block.number, 2);
+      assert.equal(block.membersCount, 4);
+    }));
+
+    blockShouldHaveCerts(0, 8);
+    blockShouldHaveCerts(1, 0);
+    blockShouldHaveCerts(2, 0);
+    blockShouldHaveCerts(3, 1);
+    blockShouldHaveCerts(4, 1);
+    blockShouldHaveCerts(5, 0);
+
+    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 82%
rename from test/integration/identity-test.js
rename to test/integration/identity/identity-test.ts
index ec434a0d0bccd9e385921f1feaeb918ac42519a4..c1e0150bb41f021af17b9e2432aa78758f038192 100644
--- a/test/integration/identity-test.js
+++ b/test/integration/identity/identity-test.ts
@@ -11,23 +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"
+import {shutDownEngine} from "../tools/shutdown-engine"
+import {expectAnswer, expectError} from "../tools/http-expect"
 
-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');
 
-require('../../app/modules/bma').BmaDependency.duniter.methods.noLimit(); // Disables the HTTP limiter
-
-const expectAnswer   = httpTest.expectAnswer;
+BmaDependency.duniter.methods.noLimit(); // Disables the HTTP limiter
 
 const MEMORY_MODE = true;
 const commonConf = {
@@ -40,16 +43,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 +69,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 +135,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 +150,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 +158,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;
@@ -167,11 +166,11 @@ describe("Identities collision", function() {
   });
 
   it('should have identity-of/aaa', function() {
-    return httpTest.expectError(404, "No member matching this pubkey or uid", rp('http://127.0.0.1:7799/wot/identity-of/aaa'));
+    return expectError(404, "No member matching this pubkey or uid", rp('http://127.0.0.1:7799/wot/identity-of/aaa'));
   });
 
   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 +193,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 +214,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 +235,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 +252,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 +271,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 +299,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 +309,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 +344,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 +360,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 +375,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 +393,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,10 +409,10 @@ 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'));
+  //   return expectHttpCode(404, rp('http://127.0.0.1:7799/blockchain/memberships/man3'));
   // });
   //
   // it('difficulties', function() {
@@ -424,4 +423,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 51%
rename from test/integration/cli.js
rename to test/integration/misc/cli.ts
index 5700267beaaaf3c83b04abaf5dde435e044bc888..a4540493bfc591fa046194e28e995b6327cccb0f 100644
--- a/test/integration/cli.js
+++ b/test/integration/misc/cli.ts
@@ -11,68 +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 constants = require('../../app/lib/constants');
-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));
@@ -82,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;
             }
@@ -114,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']);
+  })
 });
 
 /**
@@ -171,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);
 }
 
 /**
@@ -186,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 61%
rename from test/integration/http_api.js
rename to test/integration/misc/http-api.ts
index 22ee16aca9f47af5fa7d5bd7ad19ecbe9293a84a..349ebabc3f4eefb6c19780da6a1f1999edac56e7 100644
--- a/test/integration/http_api.js
+++ b/test/integration/misc/http-api.ts
@@ -11,36 +11,37 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+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"
+import {shutDownEngine} from "../tools/shutdown-engine"
+import {expectAnswer, expectError} from "../tools/http-expect"
+import {WebSocket} from "../../../app/lib/common-libs/websocket"
 
-const co        = require('co');
-const _         = require('underscore');
 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');
 
-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 +58,9 @@ describe("HTTP API", function() {
         }
       });
 
-    server2 = duniter(
-      '/bb12',
-      true,
+    server2 = NewTestingServer(
       {
+        name: 'bb12',
         ipv4: '127.0.0.1',
         port: '30410',
         currency: 'bb',
@@ -82,33 +82,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 +116,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() {
@@ -170,7 +168,7 @@ describe("HTTP API", function() {
     })
 
     it('/block/88 should not exist', function() {
-      return http.expectError(404, rp('http://127.0.0.1:7777/blockchain/block/88'));
+      return expectError(404, rp('http://127.0.0.1:7777/blockchain/block/88'));
     });
 
     it('/current should exist', function() {
@@ -180,7 +178,7 @@ describe("HTTP API", function() {
     });
 
     it('/membership should not accept wrong signature', function() {
-      return http.expectError(400, 'wrong signature for membership', rp.post('http://127.0.0.1:7777/blockchain/membership', {
+      return expectError(400, 'wrong signature for membership', rp.post('http://127.0.0.1:7777/blockchain/membership', {
         json: {
           membership: 'Version: 10\n' +
           'Type: Membership\n' +
@@ -196,7 +194,7 @@ describe("HTTP API", function() {
     });
 
     it('/membership should not accept wrong signature 2', function() {
-      return http.expectError(400, 'Document has unkown fields or wrong line ending format', rp.post('http://127.0.0.1:7777/blockchain/membership', {
+      return expectError(400, 'Document has unkown fields or wrong line ending format', rp.post('http://127.0.0.1:7777/blockchain/membership', {
         json: {
           membership: 'Version: 2\n' +
           'Type: Membership\n' +
@@ -211,7 +209,7 @@ describe("HTTP API", function() {
     });
 
     it('/membership should not accept wrong signature 3', function() {
-      return http.expectError(400, 'Document has unkown fields or wrong line ending format', rp.post('http://127.0.0.1:7777/blockchain/membership', {
+      return expectError(400, 'Document has unkown fields or wrong line ending format', rp.post('http://127.0.0.1:7777/blockchain/membership', {
         json: {
           membership: 'Version: 2\n' +
           'Type: Membership\n' +
@@ -227,7 +225,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 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);
       });
@@ -237,7 +235,7 @@ describe("HTTP API", function() {
   describe("/ws", function() {
 
     it('/block should exist', function(done) {
-      const client = new ws('ws://127.0.0.1:7777/ws/block');
+      const client = new WebSocket('ws://127.0.0.1:7777/ws/block');
       client.on('open', function open() {
         client.terminate();
         done();
@@ -246,8 +244,8 @@ 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) {
+      const client = new WebSocket('ws://127.0.0.1:7777/ws/block');
+      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 +258,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 }))
-      const client = new ws('ws://127.0.0.1:7777/ws/block');
-      let resolve5, resolve6, resolve7
+    it('/block (number 5,6,7) should send a block', async () => {
+      server2.writeBlock(await commit({ time: now + 120 * 5 }))
+      const client = new WebSocket('ws://127.0.0.1:7777/ws/block');
+      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) {
+      const client = new WebSocket('ws://127.0.0.1:7777/ws/block');
+      client.on('pong', function message() {
         client.terminate();
         done();
       });
@@ -303,73 +301,71 @@ describe("HTTP API", function() {
       });
     });
 
-    it('/peer (number 5,6,7) should send a peer document', () => co(function*() {
-      const client = new ws('ws://127.0.0.1:30410/ws/peer');
-      let resolve5, resolve6, resolve7
+    it('/peer (number 5,6,7) should send a peer document', async () => {
+      const client = new WebSocket('ws://127.0.0.1:30410/ws/peer');
+      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"))
-      const p1 = yield server.PeeringService.generateSelfPeer({
-        currency: server.conf.currency
-      }, 0)
-      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)
           return resolve5(peer)
         }
-        if (peer.block.match(/1-/) && peer.pubkey === 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo') {
+        if ((peer.block.match(/1-/) || peer.block.match(/3-/)) && peer.pubkey === 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo') {
           return resolve6(peer)
         }
       })
-      yield server2.writeRawPeer(PeerDTO.fromJSONObject(p1).getRawSigned())
-      const b5 = yield p5
+      const p1 = await server.PeeringService.generateSelfPeer({
+        currency: server.conf.currency
+      }, 0)
+      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/single-document-treatment.js b/test/integration/misc/single-document-treatment.ts
similarity index 69%
rename from test/integration/single-document-treatment.js
rename to test/integration/misc/single-document-treatment.ts
index 58aa5229afb2810676af006837910cda605708b1..1f73502196cc56e87d1bdae365cb10ac5a508b10 100644
--- a/test/integration/single-document-treatment.js
+++ b/test/integration/misc/single-document-treatment.ts
@@ -11,25 +11,20 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {NewTestingServer, serverWaitBlock, TestingServer} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
 
-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');
-const CommonConstants = require('../../app/lib/common-libs/constants').CommonConstants
 
 const now = 1500000000
 
-let s1, s2, cat, tac
+let s1:TestingServer, s2:TestingServer, cat:TestUser, tac:TestUser
 
 describe("Single document treatment", function() {
 
-  before(() => co(function*() {
+  before(async () => {
 
-    s1 = toolbox.server({
+    s1 = NewTestingServer({
       // The common conf
       medianTimeBlocks: 1,
       avgGenTime: 11,
@@ -41,7 +36,7 @@ describe("Single document treatment", function() {
       }
     });
 
-    s2 = toolbox.server({
+    s2 = NewTestingServer({
       pair: {
         pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc',
         sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'
@@ -51,17 +46,17 @@ describe("Single document treatment", function() {
     cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
     tac = new TestUser('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
 
-    yield s1.prepareForNetwork();
-    yield s2.prepareForNetwork();
+    await s1.prepareForNetwork();
+    await s2.prepareForNetwork();
 
     // Publishing identities
-    yield cat.createIdentity();
-    yield tac.createIdentity();
-    yield cat.cert(tac);
-    yield tac.cert(cat);
-    yield cat.join();
-    yield tac.join();
-  }));
+    await cat.createIdentity();
+    await tac.createIdentity();
+    await cat.cert(tac);
+    await tac.cert(cat);
+    await cat.join();
+    await tac.join();
+  })
 
   after(() => {
     return Promise.all([
@@ -70,29 +65,29 @@ describe("Single document treatment", function() {
     ])
   })
 
-  it('should create a common blockchain', () => co(function*() {
-    const b0 = yield s1.commit({ time: now })
-    const b1 = yield s1.commit({ time: now + 11 })
-    const b2 = yield s1.commit({ time: now + 22 })
-    yield s2.writeBlock(b0)
-    yield s2.writeBlock(b1)
-    yield s2.writeBlock(b2)
-    yield toolbox.serverWaitBlock(s2, 2)
-  }))
-
-  it('should exist the same block on each node', () => co(function*() {
-    yield s1.expectJSON('/blockchain/current', {
+  it('should create a common blockchain', async () => {
+    const b0 = await s1.commit({ time: now })
+    const b1 = await s1.commit({ time: now + 11 })
+    const b2 = await s1.commit({ time: now + 22 })
+    await s2.writeBlock(b0)
+    await s2.writeBlock(b1)
+    await s2.writeBlock(b2)
+    await serverWaitBlock(s2._server, 2)
+  })
+
+  it('should exist the same block on each node', async () => {
+    await s1.expectJSON('/blockchain/current', {
       number: 2
     })
-    yield s2.expectJSON('/blockchain/current', {
+    await s2.expectJSON('/blockchain/current', {
       number: 2
     })
-  }))
+  })
 
-  it('should refuse known fork blocks', () => co(function*() {
-    const p1 = yield s1.getPeer()
+  it('should refuse known fork blocks', async () => {
+    const p1 = await s1.getPeer()
     // Trigger the multiple writings in parallel
-    const res = yield Promise.all([
+    const res = await Promise.all([
       s2.writePeer(p1).then(p => p).catch(e => { assert.equal(e.uerr.message, "Document already under treatment"); return null }),
       s2.writePeer(p1).then(p => p).catch(e => { assert.equal(e.uerr.message, "Document already under treatment"); return null }),
       s2.writePeer(p1).then(p => p).catch(e => { assert.equal(e.uerr.message, "Document already under treatment"); return null }),
@@ -108,6 +103,6 @@ describe("Single document treatment", function() {
     assert.equal(res[4], null)
     assert.equal(res[5], null)
 
-  }))
+  })
 
 })
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 87%
rename from test/integration/network.js
rename to test/integration/network/network-merkle.ts
index 9f75b690445779c9511a5629e529cf5a63dc2970..d1ea5d084537f2be595610d24fb14aad9ece9638 100644
--- a/test/integration/network.js
+++ b/test/integration/network/network-merkle.ts
@@ -11,18 +11,13 @@
 // 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"
+import {NewTestingServer} from "../tools/toolbox"
+import {expectAnswer, expectHttpCode} from "../tools/http-expect"
 
-const co = require('co');
-const _         = require('underscore');
 const rp        = require('request-promise');
-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 +28,8 @@ const commonConf = {
   sigQty: 1
 };
 
-const s1 = node('bb33', _.extend({
+const s1 = NewTestingServer(Underscore.extend({
+  name: 'bb33',
   ipv4: '127.0.0.1',
   port: '20501',
   remoteport: '20501',
@@ -46,7 +42,8 @@ const s1 = node('bb33', _.extend({
   sigQty: 1, dt: 0, ud0: 120
 }, commonConf));
 
-const s2 = node('bb12', _.extend({
+const s2 = NewTestingServer(Underscore.extend({
+  name: 'bb12',
   port: '20502',
   remoteport: '20502',
   ws2p: { upnp: false },
@@ -58,20 +55,18 @@ 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.initDalBmaConnections()
+    await s2.initDalBmaConnections()
+    await s1._server.PeeringService.generateSelfPeer(s1._server.conf, 0)
+    await s2._server.PeeringService.generateSelfPeer(s1._server.conf, 0)
+    await s1.sharePeeringWith(s2)
+  })
 
   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 53%
rename from test/integration/peerings.js
rename to test/integration/network/network-peerings.ts
index f9c42296e841edfd09aacd026c013116a6aed438..a1a58f729d1f1357a96274ee1ec8c61a4f5b941d 100644
--- a/test/integration/peerings.js
+++ b/test/integration/network/network-peerings.ts
@@ -11,27 +11,20 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {NewTestingServer, serverWaitBlock, 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"
+import {sync} from "../tools/test-sync"
+import {shutDownEngine} from "../tools/shutdown-engine"
+import {expectJSON} from "../tools/http-expect"
 
-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 expectJSON     = httpTest.expectJSON;
 
 const MEMORY_MODE = true;
 const commonConf = {
@@ -44,20 +37,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 +58,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 +69,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 +84,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._server, s2._server);
+        await serverWaitBlock(s1._server, 0)
+        // Server 3 syncs block 0
+        await sync(0, 0, s1._server, s3._server);
+        await 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([
+          serverWaitBlock(s2._server, 1),
+          serverWaitBlock(s3._server, 1)
+        ])
+        // A block was successfully spread accross the network
+        await s2.bma.closeConnections();
+        await s1.commit();
+        await serverWaitBlock(s3._server, 2)
+        // Server 2 syncs block number 2 (it did not have it)
+        await sync(2, 2, s1._server, s2._server);
+        await serverWaitBlock(s2._server, 2)
+        await s2.recomputeSelfPeer();
+        await s2.bma.openConnections();
+        await new Promise((resolve) => setTimeout(resolve, 1000));
+        await Promise.all([
+          serverWaitBlock(s2._server, 4),
+          serverWaitBlock(s3._server, 4),
+          s1.commit().then(() => s1.commit())
+         ])
+        await Promise.all([
+          serverWaitBlock(s1._server, 5),
+          serverWaitBlock(s2._server, 5),
+          s3.commit()
+        ])
+        await Promise.all([
+          serverWaitBlock(s1._server, 6),
+          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..f6a35980af983fa98e8a67df37ce7b209011d6a4 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"
+import {until} from "../tools/test-until"
+import {sync} from "../tools/test-sync"
 
-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 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._server, s2._server);
+    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._server, s3._server);
+    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..4c0a523d88a388af5b0fd4a4156bf82082e814e4
--- /dev/null
+++ b/test/integration/network/network-update.ts
@@ -0,0 +1,104 @@
+// 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"
+import {sync} from "../tools/test-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._server, s2._server);
+
+    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/peer-outdated.js b/test/integration/network/peer-outdated.ts
similarity index 65%
rename from test/integration/peer-outdated.js
rename to test/integration/network/peer-outdated.ts
index 79a61acffb5b52c5b85c8528b2ec54791d543ead..a83d9540e72b060a8579d28be0b77d0778c9249f 100644
--- a/test/integration/peer-outdated.js
+++ b/test/integration/network/peer-outdated.ts
@@ -11,36 +11,33 @@
 // 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 {HttpPeer, HttpPeers} from "../../../app/modules/bma/lib/dtos"
+import {PeerDTO} from "../../../app/lib/dto/PeerDTO"
+import {RouterDependency} from "../../../app/modules/router"
+import {Multicaster} from "../../../app/lib/streams/multicaster"
+import {until} from "../tools/test-until"
 
-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');
-const until     = require('./tools/until');
-const toolbox   = require('./tools/toolbox');
-const Multicaster = require('../../app/lib/streams/multicaster').Multicaster
-const PeerDTO = require('../../app/lib/dto/PeerDTO').PeerDTO
 
-let s1, s2, cat, toc
+let s1:TestingServer, s2:TestingServer, cat:TestUser, toc:TestUser
 
 describe("Peer document expiry", function() {
 
-  let peer1V1;
+  let peer1V1:HttpPeer
 
-  before(() => co(function*() {
+  before(async () => {
 
-    s1 = toolbox.server({
+    s1 = NewTestingServer({
       pair: {
         pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
         sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
       }
     });
 
-    s2 = toolbox.server({
+    s2 = NewTestingServer({
       pair: {
         pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo',
         sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'
@@ -50,30 +47,28 @@ describe("Peer document expiry", function() {
     cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
     toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
 
-    const commitS1 = commit(s1);
-
-    yield [s1, s2].reduce((p, server) => co(function*() {
-      yield p;
-      yield server.initDalBmaConnections()
-      require('../../app/modules/router').RouterDependency.duniter.methods.routeToNetwork(server);
-    }), Promise.resolve());
+    await [s1, s2].reduce(async (p:Promise<any>, server:TestingServer) => {
+      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
-    peer1V1 = yield s1.get('/network/peering');
-    yield commitS1(); // block#2
-    yield s1.recomputeSelfPeer(); // peer#2
-    yield s2.syncFrom(s1, 0, 2);
-    yield s2.waitToHaveBlock(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
+    peer1V1 = await s1.get('/network/peering');
+    await s1.commit(); // block#2
+    await s1.recomputeSelfPeer(); // peer#2
+    await s2.syncFrom(s1._server, 0, 2);
+    await s2.waitToHaveBlock(2)
+  })
 
   after(() => {
     return Promise.all([
@@ -82,50 +77,50 @@ describe("Peer document expiry", function() {
     ])
   })
 
-  it('sending back V1 peer document should return the latest known one', () => co(function*() {
+  it('sending back V1 peer document should return the latest known one', async () => {
     let res;
     try {
-      yield s1.post('/network/peering/peers', { peer: PeerDTO.fromJSONObject(peer1V1).getRawSigned() });
+      await s1.post('/network/peering/peers', { peer: PeerDTO.fromJSONObject(peer1V1).getRawSigned() });
     } catch (e) {
       res = e;
     }
     should.exist(res);
     res.should.have.property("error").property("peer").property("block").match(/^2-/);
-  }));
+  })
 
-  it('routing V1 peer document should raise an "outdated" event', () => co(function*() {
+  it('routing V1 peer document should raise an "outdated" event', async () => {
     const caster = new Multicaster();
     return new Promise((resolve) => {
       caster
-        .pipe(es.mapSync((obj) => {
+        .pipe(es.mapSync((obj:any) => {
           obj.should.have.property("outdated").equal(true);
           resolve();
         }));
       caster.sendPeering(PeerDTO.fromJSONObject(peer1V1), PeerDTO.fromJSONObject(peer1V1));
     });
-  }));
+  })
 
   it('mirror should have 3 known blocks', () => s2.expectJSON('/blockchain/current', {
     number: 2
   }));
 
-  it('mirror should have 1 known peers', () => s2.expect('/network/peers', (res) => {
+  it('mirror should have 1 known peers', () => s2.expect('/network/peers', (res:HttpPeers) => {
     res.should.have.property("peers").length(1);
     res.peers[0].should.have.property("pubkey").equal('DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo');
   }));
 
-  it('routing V1 peer document should inject newer peer', () => co(function*() {
-    yield [
+  it('routing V1 peer document should inject newer peer', async () => {
+    await [
       s2.writePeer(peer1V1),
       until(s2, 'peer', 2)
     ];
-  }));
+  })
 
-  it('mirror should now have 2 known peers', () => s2.expect('/network/peers', (res) => {
+  it('mirror should now have 2 known peers', () => s2.expect('/network/peers', (res:HttpPeers) => {
     res.should.have.property("peers").length(2);
     res.peers[0].should.have.property("pubkey").equal('DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo');
     res.peers[0].should.have.property("block").match(/^0-/);
     res.peers[1].should.have.property("pubkey").equal('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
     res.peers[1].should.have.property("block").match(/^2-/);
-  }));
-});
+  }))
+})
diff --git a/test/integration/continuous-proof.js b/test/integration/proof-of-work/continuous-proof.ts
similarity index 63%
rename from test/integration/continuous-proof.js
rename to test/integration/proof-of-work/continuous-proof.ts
index ffe8615b33bd37db02e9ffaf2564cfddd3d53c1c..452f7c2d0a454122446c7e7853470f0c3b38d1c8 100644
--- a/test/integration/continuous-proof.js
+++ b/test/integration/proof-of-work/continuous-proof.ts
@@ -11,24 +11,22 @@
 // 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, simpleNetworkOf2NodesAnd2Users, TestingServer} from "../tools/toolbox"
+import {CrawlerDependency} from "../../../app/modules/crawler/index"
 
-const co        = require('co');
 const es        = require('event-stream');
 const should    = require('should');
-const TestUser  = require('./tools/TestUser').TestUser
-const toolbox   = require('./tools/toolbox');
-const constants = require('../../app/lib/constants');
 
 const NB_CORES_FOR_COMPUTATION = 1 // For simple tests. Can be changed to test multiple cores.
 
-let s1, s2, s3, i1, i2
+let s1:TestingServer, s2:TestingServer, s3:TestingServer, i1:TestUser, i2:TestUser
 
 describe("Continous proof-of-work", function() {
 
-  before(() => co(function*() {
+  before(async () => {
 
-    s1 = toolbox.server({
+    s1 = NewTestingServer({
       cpu: 1,
       nbCores: NB_CORES_FOR_COMPUTATION,
       powDelay: 100,
@@ -42,37 +40,37 @@ describe("Continous proof-of-work", function() {
     i1 = new TestUser('i1',   { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
     i2 = new TestUser('i2',   { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
 
-    yield s1.prepareForNetwork();
-    yield i1.createIdentity();
-    yield i2.createIdentity();
-    yield i1.cert(i2);
-    yield i2.cert(i1);
-    yield i1.join();
-    yield i2.join();
-    yield s1.commit();
-    yield s1.closeCluster();
-  }));
-
-  it('should automatically stop waiting if nothing happens', () => co(function*() {
+    await s1.prepareForNetwork();
+    await i1.createIdentity();
+    await i2.createIdentity();
+    await i1.cert(i2);
+    await i2.cert(i1);
+    await i1.join();
+    await i2.join();
+    await s1.commit();
+    await s1.closeCluster();
+  })
+
+  it('should automatically stop waiting if nothing happens', async () => {
     s1.conf.powSecurityRetryDelay = 10;
     let start = Date.now();
     s1.startBlockComputation();
     // s1.permaProver.should.have.property('loops').equal(0);
-    yield s1.until('block', 1);
+    await s1.until('block', 1);
     // s1.permaProver.should.have.property('loops').equal(1);
     (start - Date.now()).should.be.belowOrEqual(1000);
-    yield s1.stopBlockComputation();
-    yield new Promise((resolve) => setTimeout(resolve, 100));
+    await s1.stopBlockComputation();
+    await new Promise((resolve) => setTimeout(resolve, 100));
     // s1.permaProver.should.have.property('loops').equal(2);
     s1.conf.powSecurityRetryDelay = 10 * 60 * 1000;
-    yield s1.revert();
+    await s1.revert();
     s1.permaProver.loops = 0;
-    yield s1.stopBlockComputation();
-  }));
+    await s1.stopBlockComputation();
+  })
 
-  it('should be able to start generation and find a block', () => co(function*() {
+  it('should be able to start generation and find a block', async () => {
     s1.permaProver.should.have.property('loops').equal(0);
-    yield [
+    await [
       s1.startBlockComputation(),
       s1.until('block', 2)
     ];
@@ -81,48 +79,48 @@ describe("Continous proof-of-work", function() {
     // * 1 loop for making b#1
     // * 1 loop by waiting between b#1 and b#2
     // * 1 loop for making b#2
-    yield new Promise((resolve) => setTimeout(resolve, 100));
+    await new Promise((resolve) => setTimeout(resolve, 100));
     // s1.permaProver.should.have.property('loops').equal(4);
-    yield s1.stopBlockComputation();
+    await s1.stopBlockComputation();
 
     // If we wait a bit, the loop should be ended
-    yield new Promise((resolve) => setTimeout(resolve, 100));
+    await new Promise((resolve) => setTimeout(resolve, 100));
     // s1.permaProver.should.have.property('loops').equal(5);
-    yield s1.stopBlockComputation();
-  }));
+    await s1.stopBlockComputation();
+  })
 
-  it('should be able to cancel generation because of a blockchain switch', () => co(function*() {
+  it('should be able to cancel generation because of a blockchain switch', async () => {
     // s1.permaProver.should.have.property('loops').equal(5);
     s1.startBlockComputation();
-    yield s1.until('block', 1);
+    await s1.until('block', 1);
     // * 1 loop for making b#3
-    yield new Promise((resolve) => setTimeout(resolve, 100));
+    await new Promise((resolve) => setTimeout(resolve, 100));
     // s1.permaProver.should.have.property('loops').equal(6);
-    yield s1.permaProver.blockchainChanged();
-    yield new Promise((resolve) => setTimeout(resolve, 100));
+    await s1.permaProver.blockchainChanged();
+    await new Promise((resolve) => setTimeout(resolve, 100));
     // * 1 loop for waiting for b#4 but being interrupted
-    s1.permaProver.should.have.property('loops').greaterThanOrEqual(5);
-    yield s1.stopBlockComputation();
+    s1.permaProver.should.have.property('loops').greaterThanOrEqual(4);
+    await s1.stopBlockComputation();
 
     // If we wait a bit, the loop should be ended
-    yield new Promise((resolve) => setTimeout(resolve, 100));
-    s1.permaProver.should.have.property('loops').greaterThanOrEqual(6);
-  }));
+    await new Promise((resolve) => setTimeout(resolve, 100));
+    s1.permaProver.should.have.property('loops').greaterThanOrEqual(5);
+  })
 
-  it('testing proof-of-work during a block pulling', () => co(function*() {
-    const res = yield toolbox.simpleNetworkOf2NodesAnd2Users({
+  it('testing proof-of-work during a block pulling', async () => {
+    const res = await simpleNetworkOf2NodesAnd2Users({
       nbCores: NB_CORES_FOR_COMPUTATION,
       powMin: 0
     }), s2 = res.s1, s3 = res.s2;
-    yield s2.commit();
+    await s2.commit();
     s2.conf.cpu = 1.0;
     s2.startBlockComputation();
-    yield s2.until('block', 15);
-    yield s2.stopBlockComputation();
-    yield [
-      require('../../app/modules/crawler').CrawlerDependency.duniter.methods.pullBlocks(s3),
+    await s2.until('block', 15);
+    await s2.stopBlockComputation();
+    await [
+      CrawlerDependency.duniter.methods.pullBlocks(s3._server),
       new Promise(res => {
-        s3.pipe(es.mapSync((e) => {
+        s3.pipe(es.mapSync((e:any) => {
           if (e.number === 15) {
             res()
           }
@@ -132,9 +130,9 @@ describe("Continous proof-of-work", function() {
       }),
       s3.startBlockComputation()
     ];
-    const current = yield s3.get('/blockchain/current')
-    yield s3.stopBlockComputation();
+    const current = await s3.get('/blockchain/current')
+    await s3.stopBlockComputation();
     current.number.should.be.aboveOrEqual(14)
-    yield s1.closeCluster()
-  }));
+    await s1.closeCluster()
+  })
 });
diff --git a/test/integration/proof-of-work.js b/test/integration/proof-of-work/proof-of-work.ts
similarity index 68%
rename from test/integration/proof-of-work.js
rename to test/integration/proof-of-work/proof-of-work.ts
index dd43486b2af277c2e10c37d989d08958810ab8e6..29b3a7306b386687d1f003ab8a2a3f5ac42be0df 100644
--- a/test/integration/proof-of-work.js
+++ b/test/integration/proof-of-work/proof-of-work.ts
@@ -11,14 +11,11 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {NewLogger} from "../../../app/lib/logger"
+import {BlockProver} from "../../../app/modules/prover/lib/blockProver"
 
-const co        = require('co');
 const should    = require('should');
-const toolbox   = require('./tools/toolbox');
-const constants = require('../../app/lib/constants');
-const logger = require('../../app/lib/logger').NewLogger();
-const BlockProver = require('../../app/modules/prover/lib/blockProver').BlockProver
+const logger = NewLogger();
 
 /***
 conf.medianTimeBlocks
@@ -28,11 +25,11 @@ conf.cpu
 keyring from Key
 ***/
 
-const intermediateProofs = [];
+const intermediateProofs:any[] = [];
 const NB_CORES_FOR_COMPUTATION = 1 // For simple tests. Can be changed to test multiple cores.
 
 const prover = new BlockProver({
-  push: (data) => intermediateProofs.push(data),
+  push: (data:any) => intermediateProofs.push(data),
   conf: {
     nbCores: NB_CORES_FOR_COMPUTATION,
     cpu: 1.0, // 80%,
@@ -42,7 +39,7 @@ const prover = new BlockProver({
     }
   },
   logger
-});
+} as any);
 
 const now = 1474382274 * 1000;
 const MUST_START_WITH_A_ZERO = 16;
@@ -50,8 +47,8 @@ const MUST_START_WITH_TWO_ZEROS = 32;
 
 describe("Proof-of-work", function() {
 
-  it('should be able to find an easy PoW', () => co(function*() {
-    let block = yield prover.prove({
+  it('should be able to find an easy PoW', async () => {
+    let block = await prover.prove({
       issuer: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
       number: 2
     }, MUST_START_WITH_TWO_ZEROS, now);
@@ -59,29 +56,29 @@ describe("Proof-of-work", function() {
     intermediateProofs.length.should.be.greaterThan(0);
     intermediateProofs[intermediateProofs.length - 1].pow.should.have.property('found').equal(true);
     intermediateProofs[intermediateProofs.length - 1].pow.should.have.property('hash').equal(block.hash);
-  }));
+  })
 
   // Too randomly successing test
   // it('should be able to cancel a proof-of-work on other PoW receival', () => co(function*() {
   //   const now = 1474464489;
-  //   const res = yield toolbox.simpleNetworkOf2NodesAnd2Users({
+  //   const res = await toolbox.simpleNetworkOf2NodesAnd2Users({
   //     powMin: 46
   //   }), s1 = res.s1, s2 = res.s2;
-  //   yield s1.commit({
+  //   await s1.commit({
   //     time: now // 38 hits to find the proof (known by test)
   //   });
-  //   yield s2.until('block', 1);
-  //   yield s1.expectJSON('/blockchain/current', { number: 0 });
-  //   yield s2.expectJSON('/blockchain/current', { number: 0 });
-  //   yield s1.commit({
+  //   await s2.until('block', 1);
+  //   await s1.expectJSON('/blockchain/current', { number: 0 });
+  //   await s2.expectJSON('/blockchain/current', { number: 0 });
+  //   await s1.commit({
   //     time: now + 13 // 521 hits to find the proof
   //   });
-  //   yield s2.until('block', 1);
-  //   yield s1.expectJSON('/blockchain/current', { number: 1 });
-  //   yield s2.expectJSON('/blockchain/current', { number: 1 });
+  //   await s2.until('block', 1);
+  //   await s1.expectJSON('/blockchain/current', { number: 1 });
+  //   await s2.expectJSON('/blockchain/current', { number: 1 });
   //   s1.conf.cpu = 1.0;
   //   s2.conf.cpu = 0.02;
-  //   yield Promise.all([
+  //   await Promise.all([
   //
   //     // Make a concurrent trial
   //     Promise.all([
@@ -90,7 +87,7 @@ describe("Proof-of-work", function() {
   //           let s2commit = s2.commit({ time: now + 14 }); // 7320 hits to be found: very high, that's good because we need time for s1 to find the proof *before* s2
   //           // A little handicap for s1 which will find the proof almost immediately
   //           setTimeout(() => s1.commit({ time: now + 10 }), 100);
-  //           yield s2commit;
+  //           await s2commit;
   //           throw 's2 server should not have found the proof before s1';
   //         } catch (e) {
   //           should.exist(e);
@@ -103,62 +100,62 @@ describe("Proof-of-work", function() {
   //     s1.until('block', 1),
   //     s2.until('block', 1)
   //   ]);
-  //   yield s1.expectJSON('/blockchain/current', { number: 2 });
-  //   yield s2.expectJSON('/blockchain/current', { number: 2 });
+  //   await s1.expectJSON('/blockchain/current', { number: 2 });
+  //   await s2.expectJSON('/blockchain/current', { number: 2 });
   //   // Both nodes should receive the same last block from s2
   //   s2.conf.cpu = 1.0;
-  //   yield [
+  //   await [
   //     s1.until('block', 1),
   //     s2.until('block', 1),
   //     s2.commit({ time: now + 10 })
   //   ];
-  //   yield s1.expectJSON('/blockchain/current', { number: 3 });
-  //   yield s2.expectJSON('/blockchain/current', { number: 3 });
+  //   await s1.expectJSON('/blockchain/current', { number: 3 });
+  //   await s2.expectJSON('/blockchain/current', { number: 3 });
   // }));
 
   // TODO: re-enable when algorithm is better
   // it('should be able to cancel a waiting on other PoW receival', () => co(function*() {
   //   const now = 1474464481;
-  //   const res = yield toolbox.simpleNetworkOf2NodesAnd2Users({
+  //   const res = await toolbox.simpleNetworkOf2NodesAnd2Users({
   //     powSecurityRetryDelay: 10 * 60 * 1000,
   //     powMaxHandicap: 8,
   //     percentRot: 1,
   //     powMin: 35
   //   }), s1 = res.s1, s2 = res.s2;
-  //   yield Promise.all([
+  //   await Promise.all([
   //     s1.commit({ time: now }),
   //     // We wait until both nodes received the new block
   //     s1.until('block', 1),
   //     s2.until('block', 1)
   //   ]);
-  //   yield s1.expectJSON('/blockchain/current', { number: 0 });
-  //   yield s2.expectJSON('/blockchain/current', { number: 0 });
-  //   yield Promise.all([
+  //   await s1.expectJSON('/blockchain/current', { number: 0 });
+  //   await s2.expectJSON('/blockchain/current', { number: 0 });
+  //   await Promise.all([
   //     s2.commit({ time: now }),
   //     // We wait until both nodes received the new block
   //     s1.until('block', 1),
   //     s2.until('block', 1)
   //   ]);
-  //   yield s1.expectJSON('/blockchain/current', { number: 1 });
-  //   yield s2.expectJSON('/blockchain/current', { number: 1 });
-  //   yield Promise.all([
+  //   await s1.expectJSON('/blockchain/current', { number: 1 });
+  //   await s2.expectJSON('/blockchain/current', { number: 1 });
+  //   await Promise.all([
   //     s1.commit({ time: now }),
   //     // We wait until both nodes received the new block
   //     s1.until('block', 1),
   //     s2.until('block', 1)
   //   ]);
-  //   yield s1.expectJSON('/blockchain/current', { number: 2, issuersCount: 1 });
-  //   yield s2.expectJSON('/blockchain/current', { number: 2, issuersCount: 1 });
-  //   yield Promise.all([
+  //   await s1.expectJSON('/blockchain/current', { number: 2, issuersCount: 1 });
+  //   await s2.expectJSON('/blockchain/current', { number: 2, issuersCount: 1 });
+  //   await Promise.all([
   //     s2.commit({ time: now }),
   //     // We wait until both nodes received the new block
   //     s1.until('block', 1),
   //     s2.until('block', 1)
   //   ]);
-  //   yield s1.expectJSON('/blockchain/current', { number: 3, issuersCount: 2 });
-  //   yield s2.expectJSON('/blockchain/current', { number: 3, issuersCount: 2 });
-  //   // yield s2.expectJSON('/blockchain/difficulties', { number: 3, issuersCount: 2 });
-  //   yield Promise.all([
+  //   await s1.expectJSON('/blockchain/current', { number: 3, issuersCount: 2 });
+  //   await s2.expectJSON('/blockchain/current', { number: 3, issuersCount: 2 });
+  //   // await s2.expectJSON('/blockchain/difficulties', { number: 3, issuersCount: 2 });
+  //   await Promise.all([
   //
   //     new Promise((resolve) => {
   //       s1.startBlockComputation();
@@ -170,7 +167,7 @@ describe("Proof-of-work", function() {
   //     s1.until('block', 2),
   //     s2.until('block', 2)
   //   ]);
-  //   yield s1.expectJSON('/blockchain/current', { number: 5 });
-  //   yield s2.expectJSON('/blockchain/current', { number: 5 });
+  //   await s1.expectJSON('/blockchain/current', { number: 5 });
+  //   await s2.expectJSON('/blockchain/current', { number: 5 });
   // }));
 });
diff --git a/test/integration/v0.4-times.js b/test/integration/protocol/v0.4-times.ts
similarity index 69%
rename from test/integration/v0.4-times.js
rename to test/integration/protocol/v0.4-times.ts
index e11ee84fe326da66da098feeb3c8550266cdc8c4..723367d00f5a7208ca033135fbb05f4d5e336885 100644
--- a/test/integration/v0.4-times.js
+++ b/test/integration/protocol/v0.4-times.ts
@@ -13,11 +13,9 @@
 
 "use strict";
 
-const co        = require('co');
+import {simpleNodeWith2Users, TestingServer} from "../tools/toolbox"
+
 const should    = require('should');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const commit    = require('./tools/commit');
-const toolbox   = require('./tools/toolbox');
 
 const conf = {
   avgGenTime: 5000,
@@ -25,15 +23,15 @@ const conf = {
 };
 
 const now = 1475069096;
-let s1;
+let s1:TestingServer
 
 describe("Protocol 0.4 Times", function() {
 
-  before(() => co(function*() {
-    const res = yield toolbox.simpleNodeWith2Users(conf);
+  before(async () => {
+    const res = await simpleNodeWith2Users(conf);
     s1 = res.s1;
-    yield s1.commit({ time: now }); // We must issue a normal root block, because always medianTime(0) == time(0)
-  }));
+    await s1.commit({ time: now }); // We must issue a normal root block, because always medianTime(0) == time(0)
+  })
 
   after(() => {
     return Promise.all([
@@ -41,16 +39,16 @@ describe("Protocol 0.4 Times", function() {
     ])
   })
 
-  it('a V4 block should not accept a time = medianTime + avgGenTime * 1.189', () => co(function*() {
-    yield s1.commit({ medianTime: now, time: Math.ceil(now + conf.avgGenTime * 1.189) });
-    yield s1.revert();
-  }));
+  it('a V4 block should not accept a time = medianTime + avgGenTime * 1.189', async () => {
+    await s1.commit({ medianTime: now, time: Math.ceil(now + conf.avgGenTime * 1.189) });
+    await s1.revert();
+  })
 
-  it('a V4 block should not accept a time > medianTime + avgGenTime * 1.189', () => co(function*() {
+  it('a V4 block should not accept a time > medianTime + avgGenTime * 1.189', async () => {
     try {
-      yield s1.commitExpectError({ medianTime: now, time: Math.ceil(now + conf.avgGenTime * 1.189) + 1 });
+      await s1.commitExpectError({ medianTime: now, time: Math.ceil(now + conf.avgGenTime * 1.189) + 1 });
     } catch (e) {
       e.should.have.property('message').equal('A block must have its Time between MedianTime and MedianTime + 5945');
     }
-  }));
+  })
 });
diff --git a/test/integration/v0.5-identity-blockstamp.js b/test/integration/protocol/v0.5-identity-blockstamp.ts
similarity index 58%
rename from test/integration/v0.5-identity-blockstamp.js
rename to test/integration/protocol/v0.5-identity-blockstamp.ts
index 9016e87ab79e8fecffecd13a44716d083c6cb858..28d3adde892ab850fc69482edc4f88ff174908af 100644
--- a/test/integration/v0.5-identity-blockstamp.js
+++ b/test/integration/protocol/v0.5-identity-blockstamp.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 {createUser, simpleNodeWith2otherUsers, simpleNodeWith2Users, TestingServer} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
 
-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 conf = {
   avgGenTime: 5000,
@@ -26,19 +23,19 @@ const conf = {
 
 const now = 1578540000;
 
-let s1, s2, tuc;
+let s1:TestingServer, s2:TestingServer, tuc:TestUser
 
 describe("Protocol 0.5 Identity blockstamp", function() {
 
-  before(() => co(function*() {
+  before(async () => {
 
-    const res1 = yield toolbox.simpleNodeWith2Users(conf);
-    const res2 = yield toolbox.simpleNodeWith2otherUsers(conf);
+    const res1 = await simpleNodeWith2Users(conf);
+    const res2 = await simpleNodeWith2otherUsers(conf);
     s1 = res1.s1;
     s2 = res2.s1;
 
-    tuc = yield toolbox.createUser('tuc', '3conGDUXdrTGbQPMQQhEC4Ubu1MCAnFrAYvUaewbUhtk', '5ks7qQ8Fpkin7ycXpxQSxxjVhs8VTzpM3vEBMqM7NfC1ZiFJ93uQryDcoM93Mj77T6hDAABdeHZJDFnkDb35bgiU', s1);
-  }));
+    tuc = await createUser('tuc', '3conGDUXdrTGbQPMQQhEC4Ubu1MCAnFrAYvUaewbUhtk', '5ks7qQ8Fpkin7ycXpxQSxxjVhs8VTzpM3vEBMqM7NfC1ZiFJ93uQryDcoM93Mj77T6hDAABdeHZJDFnkDb35bgiU', s1._server);
+  })
 
   after(() => {
     return Promise.all([
@@ -47,23 +44,23 @@ describe("Protocol 0.5 Identity blockstamp", function() {
     ])
   })
 
-  it('should be able to create tuc on s1', () => co(function*() {
-    yield s1.commit({ time: now });
-    yield s1.commit({ time: now });
-    yield s2.commit({ time: now });
-    yield s2.commit({ time: now });
-    yield tuc.createIdentity();
-  }));
+  it('should be able to create tuc on s1', async () => {
+    await s1.commit({ time: now });
+    await s1.commit({ time: now });
+    await s2.commit({ time: now });
+    await s2.commit({ time: now });
+    await tuc.createIdentity();
+  })
 
-  it('should not be able to create tuc on s2, using identity generated on s1', () => co(function*() {
+  it('should not be able to create tuc on s2, using identity generated on s1', async () => {
 
     try {
-      yield tuc.submitIdentity(tuc.getIdentityRaw(), s2);
+      await tuc.submitIdentity(tuc.getIdentityRaw(), s2);
       throw { message: 'Submitting wrong identity should have thrown an error' };
     } catch (e) {
       if (!(typeof e == "string") || e.match(/Submitting wrong identity should have thrown an error/)) {
         throw e;
       }
     }
-  }));
-});
+  })
+})
diff --git a/test/integration/v0.5-transactions.js b/test/integration/protocol/v0.5-transactions.ts
similarity index 65%
rename from test/integration/v0.5-transactions.js
rename to test/integration/protocol/v0.5-transactions.ts
index c7e546b0db62d57a2b1bb707dc6d7aec4882d4cf..63863a77f3fd8892ffa1bede279647a2cef5ee94 100644
--- a/test/integration/v0.5-transactions.js
+++ b/test/integration/protocol/v0.5-transactions.ts
@@ -11,13 +11,11 @@
 // 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 {BlockDTO} from "../../../app/lib/dto/BlockDTO"
 
-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 constants = require('../../../app/lib/constants');
 
 const conf = {
   dt: 30,
@@ -27,21 +25,21 @@ const conf = {
 
 const now = 1578540000;
 
-let s1;
+let s1:TestingServer
 
 describe("Protocol 0.5 Transaction version", function() {
 
-  before(() => co(function*() {
+  before(async () => {
 
-    const res1 = yield toolbox.simpleNodeWith2Users(conf);
+    const res1 = await simpleNodeWith2Users(conf);
     s1 = res1.s1;
     const cat = res1.cat;
     const tac = res1.tac;
-    yield s1.commit({ time: now });
-    yield s1.commit({ time: now + 100 });
-    yield s1.commit({ time: now + 100 });
-    yield cat.sendP(51, tac);
-  }));
+    await s1.commit({ time: now });
+    await s1.commit({ time: now + 100 });
+    await s1.commit({ time: now + 100 });
+    await cat.sendMoney(51, tac);
+  })
 
   after(() => {
     return Promise.all([
@@ -49,9 +47,9 @@ describe("Protocol 0.5 Transaction version", function() {
     ])
   })
 
-  it('should not have a block with v5 transaction, but v3', () => co(function*() {
-    const block = yield s1.commit({ time: now + 100 });
+  it('should not have a block with v5 transaction, but v3', async () => {
+    const block = (await s1.commit({ time: now + 100 })) as BlockDTO
     should.exists(block.transactions[0]);
     block.transactions[0].version.should.equal(constants.TRANSACTION_VERSION);
-  }));
-});
+  })
+})
diff --git a/test/integration/v0.6-difficulties.js b/test/integration/protocol/v0.6-difficulties.ts
similarity index 60%
rename from test/integration/v0.6-difficulties.js
rename to test/integration/protocol/v0.6-difficulties.ts
index 983a1224685449c8a649caa7684e65eb930a90e2..7b834dfaeb140e321a2644b7d947642cc83ab0aa 100644
--- a/test/integration/v0.6-difficulties.js
+++ b/test/integration/protocol/v0.6-difficulties.ts
@@ -11,11 +11,9 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {serverWaitBlock, simpleNetworkOf2NodesAnd2Users, TestingServer} from "../tools/toolbox"
 
-const co        = require('co');
 const should    = require('should');
-const toolbox   = require('./tools/toolbox');
 
 const conf = {
   avgGenTime: 5000,
@@ -24,20 +22,20 @@ const conf = {
 
 const now = 1480937906;
 
-let s1, s2;
+let s1:TestingServer, s2:TestingServer
 
 describe("Protocol 0.6 Difficulties", function() {
 
-  before(() => co(function*() {
+  before(async () => {
 
-    const res = yield toolbox.simpleNetworkOf2NodesAnd2Users(conf);
+    const res = await simpleNetworkOf2NodesAnd2Users(conf);
     s1 = res.s1;
     s2 = res.s2;
-    yield [
+    await Promise.all([
       s1.commit({ time: now }),
       s2.until('block', 1)
-    ];
-  }));
+    ])
+  })
 
   after(() => {
     return Promise.all([
@@ -46,69 +44,69 @@ describe("Protocol 0.6 Difficulties", function() {
     ])
   })
 
-  it('should be able to emit a block#1 by a different user', () => co(function*() {
-    yield [
+  it('should be able to emit a block#1 by a different user', async () => {
+    await Promise.all([
       s1.commit({ time: now }), // medianOfBlocksInFrame = MEDIAN([1]) = 1
-      toolbox.serverWaitBlock(s1, 1),
-      toolbox.serverWaitBlock(s2, 1)
-    ];
-    yield [
+      serverWaitBlock(s1._server, 1),
+      serverWaitBlock(s2._server, 1)
+    ])
+    await Promise.all([
       s2.commit({ time: now }), // medianOfBlocksInFrame = MEDIAN([1]) = 1
-      toolbox.serverWaitBlock(s1, 2),
-      toolbox.serverWaitBlock(s2, 2)
-    ];
-    yield s1.expectJSON('/blockchain/current', {
+      serverWaitBlock(s1._server, 2),
+      serverWaitBlock(s2._server, 2)
+    ])
+    await s1.expectJSON('/blockchain/current', {
       number: 2,
       issuer: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc'
     });
-    yield s1.expectJSON('/blockchain/block/0', {
+    await s1.expectJSON('/blockchain/block/0', {
       number: 0,
       issuer: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd'
     });
-    yield s1.expectJSON('/blockchain/hardship/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { level: 4 }); // medianOfBlocksInFrame = MEDIAN([1, 1]) = 1, personal_excess = 100%, level = 4
-    yield s1.expectJSON('/blockchain/hardship/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { level: 4 }); // medianOfBlocksInFrame = MEDIAN([1, 1]) = 1, personal_excess = 100%, level = 4
-    yield s1.commit({ time: now });
-    yield s1.expectJSON('/blockchain/hardship/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { level: 4 }); // medianOfBlocksInFrame = MEDIAN([1, 2]) = 1.5, personal_excess = 3/1.5 = 100%, level = 4
-    yield s1.expectJSON('/blockchain/hardship/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { level: 1 }); // medianOfBlocksInFrame = MEDIAN([1, 2]) = 1.5, personal_excess = 2/1.5 = 33%, level = 1
-    yield s1.commit({ time: now });
-    yield s1.expectJSON('/blockchain/hardship/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { level: 4 }); // medianOfBlocksInFrame = MEDIAN([1, 3]) = 2, personal_excess = 4/2 = 100%, level = 4
-    yield s1.expectJSON('/blockchain/hardship/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { level: 0 }); // medianOfBlocksInFrame = MEDIAN([1, 3]) = 2, personal_excess = 2/2 = 0%, level = 0
-    yield s1.commit({ time: now });
-    yield s1.expectJSON('/blockchain/hardship/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { level: 4 }); // medianOfBlocksInFrame = MEDIAN([1, 4]) = 2.5, personal_excess = 5/2.5 = 100%, level = 4
-    yield s1.expectJSON('/blockchain/hardship/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { level: 0 }); // medianOfBlocksInFrame = MEDIAN([1, 4]) = 2.5, personal_excess = 2/2.5 = 0%, level = 0
-    yield s1.commit({ time: now });
-    yield s1.expectJSON('/blockchain/hardship/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { level: 4 }); // ... [1, 5] ... = 4
-    yield s1.expectJSON('/blockchain/hardship/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { level: 0 }); // ... [1, 5] ... = 0
-    yield s1.commit({ time: now });
-    yield s1.expectJSON('/blockchain/hardship/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { level: 4 }); // ... [1, 6] ... = 4
-    yield s1.expectJSON('/blockchain/hardship/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { level: 0 }); // ... [1, 6] ... = 0
-    yield s1.commit({ time: now });
-    yield s1.expectJSON('/blockchain/hardship/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { level: 4 }); // ... [1, 7] ... = 4
-    yield s1.expectJSON('/blockchain/hardship/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { level: 0 }); // ... [1, 7] ... = 0
-    yield s1.commit({ time: now });
+    await s1.expectJSON('/blockchain/hardship/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { level: 4 }); // medianOfBlocksInFrame = MEDIAN([1, 1]) = 1, personal_excess = 100%, level = 4
+    await s1.expectJSON('/blockchain/hardship/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { level: 4 }); // medianOfBlocksInFrame = MEDIAN([1, 1]) = 1, personal_excess = 100%, level = 4
+    await s1.commit({ time: now });
+    await s1.expectJSON('/blockchain/hardship/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { level: 4 }); // medianOfBlocksInFrame = MEDIAN([1, 2]) = 1.5, personal_excess = 3/1.5 = 100%, level = 4
+    await s1.expectJSON('/blockchain/hardship/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { level: 1 }); // medianOfBlocksInFrame = MEDIAN([1, 2]) = 1.5, personal_excess = 2/1.5 = 33%, level = 1
+    await s1.commit({ time: now });
+    await s1.expectJSON('/blockchain/hardship/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { level: 4 }); // medianOfBlocksInFrame = MEDIAN([1, 3]) = 2, personal_excess = 4/2 = 100%, level = 4
+    await s1.expectJSON('/blockchain/hardship/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { level: 0 }); // medianOfBlocksInFrame = MEDIAN([1, 3]) = 2, personal_excess = 2/2 = 0%, level = 0
+    await s1.commit({ time: now });
+    await s1.expectJSON('/blockchain/hardship/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { level: 4 }); // medianOfBlocksInFrame = MEDIAN([1, 4]) = 2.5, personal_excess = 5/2.5 = 100%, level = 4
+    await s1.expectJSON('/blockchain/hardship/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { level: 0 }); // medianOfBlocksInFrame = MEDIAN([1, 4]) = 2.5, personal_excess = 2/2.5 = 0%, level = 0
+    await s1.commit({ time: now });
+    await s1.expectJSON('/blockchain/hardship/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { level: 4 }); // ... [1, 5] ... = 4
+    await s1.expectJSON('/blockchain/hardship/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { level: 0 }); // ... [1, 5] ... = 0
+    await s1.commit({ time: now });
+    await s1.expectJSON('/blockchain/hardship/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { level: 4 }); // ... [1, 6] ... = 4
+    await s1.expectJSON('/blockchain/hardship/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { level: 0 }); // ... [1, 6] ... = 0
+    await s1.commit({ time: now });
+    await s1.expectJSON('/blockchain/hardship/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { level: 4 }); // ... [1, 7] ... = 4
+    await s1.expectJSON('/blockchain/hardship/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { level: 0 }); // ... [1, 7] ... = 0
+    await s1.commit({ time: now });
 
     /*********************
      *  PowMin incremented
      ********************/
 
-    yield s1.expectJSON('/blockchain/hardship/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { level: 5 }); // medianOfBlocksInFrame = MEDIAN([1, 8]) = 4.5, personal_excess = 9/4.5 = 100%, level = 1 + 4
-    yield s1.expectJSON('/blockchain/hardship/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { level: 1 }); // medianOfBlocksInFrame = MEDIAN([1, 8]) = 4.5, personal_excess = 1/4.5 = 0%, level = 1 + 0
-    yield s1.commit({ time: now });
-    yield s1.expectJSON('/blockchain/hardship/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { level: 5 }); // ... [1, 9] ... = 5
-    yield s1.expectJSON('/blockchain/hardship/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { level: 1 }); // ... [1, 9] ... = 1
-    yield s1.commit({ time: now });
-    yield s1.expectJSON('/blockchain/hardship/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { level: 5 }); // ... [1, 10] ... = 5
-    yield s1.expectJSON('/blockchain/hardship/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { level: 1 }); // ... [1, 10] ... = 1
-    yield s1.commit({ time: now });
-    yield s1.expectJSON('/blockchain/hardship/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { level: 5 }); // ... [1, 11] ... = 5
-    yield s1.expectJSON('/blockchain/hardship/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { level: 1 }); // ... [1, 11] ... = 1
-    yield s1.commit({ time: now });
+    await s1.expectJSON('/blockchain/hardship/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { level: 5 }); // medianOfBlocksInFrame = MEDIAN([1, 8]) = 4.5, personal_excess = 9/4.5 = 100%, level = 1 + 4
+    await s1.expectJSON('/blockchain/hardship/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { level: 1 }); // medianOfBlocksInFrame = MEDIAN([1, 8]) = 4.5, personal_excess = 1/4.5 = 0%, level = 1 + 0
+    await s1.commit({ time: now });
+    await s1.expectJSON('/blockchain/hardship/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { level: 5 }); // ... [1, 9] ... = 5
+    await s1.expectJSON('/blockchain/hardship/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { level: 1 }); // ... [1, 9] ... = 1
+    await s1.commit({ time: now });
+    await s1.expectJSON('/blockchain/hardship/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { level: 5 }); // ... [1, 10] ... = 5
+    await s1.expectJSON('/blockchain/hardship/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { level: 1 }); // ... [1, 10] ... = 1
+    await s1.commit({ time: now });
+    await s1.expectJSON('/blockchain/hardship/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { level: 5 }); // ... [1, 11] ... = 5
+    await s1.expectJSON('/blockchain/hardship/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { level: 1 }); // ... [1, 11] ... = 1
+    await s1.commit({ time: now });
 
     /*********************
      *  Frame excluded `2LvDg21`
      ********************/
 
-    yield s1.expectJSON('/blockchain/hardship/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { level: 1 }); // medianOfBlocksInFrame = MEDIAN([11]) = 11, personal_excess = 12/11 = 9%, level = 1
-    yield s1.expectJSON('/blockchain/hardship/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { level: 1 }); // medianOfBlocksInFrame = MEDIAN([11]) = 11, personal_excess = 0/11 = 0%, level = 1
-  }));
-});
+    await s1.expectJSON('/blockchain/hardship/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', { level: 1 }); // medianOfBlocksInFrame = MEDIAN([11]) = 11, personal_excess = 12/11 = 9%, level = 1
+    await s1.expectJSON('/blockchain/hardship/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', { level: 1 }); // medianOfBlocksInFrame = MEDIAN([11]) = 11, personal_excess = 0/11 = 0%, level = 1
+  })
+})
diff --git a/test/integration/v1.0-double-dividend.js b/test/integration/protocol/v1.0-double-dividend.ts
similarity index 63%
rename from test/integration/v1.0-double-dividend.js
rename to test/integration/protocol/v1.0-double-dividend.ts
index da14d906630411f931fa9b2b8d1d792f174e1475..20c830c86205bbfa1744ddba2490c1384540c88b 100644
--- a/test/integration/v1.0-double-dividend.js
+++ b/test/integration/protocol/v1.0-double-dividend.ts
@@ -11,13 +11,11 @@
 // 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 {HttpBlock} from "../../../app/modules/bma/lib/dtos"
 
-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;
 
@@ -31,7 +29,7 @@ const conf = {
   medianTimeBlocks: 1 // The medianTime always equals previous block's medianTime
 };
 
-let s1, cat, tac;
+let s1:TestingServer, cat:TestUser, tac:TestUser
 
 describe("Protocol 1.0 Dividend Update", function() {
 
@@ -45,23 +43,23 @@ describe("Protocol 1.0 Dividend Update", function() {
    *   * effective dividend: this is the real dividend, which is a share of the theoretical one
    */
 
-  before(() => co(function*() {
+  before(async () => {
 
-    const res1 = yield toolbox.simpleNodeWith2Users(conf);
+    const res1 = await simpleNodeWith2Users(conf);
     s1 = res1.s1;
     cat = res1.cat; // HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd
     tac = res1.tac; // 2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc
-    yield s1.commit({ time: now });
-    yield s1.commit({ time: now + 3 });
-    yield s1.commit({ time: now + 4 });
-    yield s1.commit({ time: now + 5 });
-    yield s1.commit({ time: now + 6 });
-    yield s1.commit({ time: now + 8 });
-    yield s1.commit({ time: now + 10 });
-    yield s1.commit({ time: now + 12 });
-    yield s1.commit({ time: now + 14 });
-    yield s1.commit({ time: now + 16 });
-  }));
+    await s1.commit({ time: now });
+    await s1.commit({ time: now + 3 });
+    await s1.commit({ time: now + 4 });
+    await s1.commit({ time: now + 5 });
+    await s1.commit({ time: now + 6 });
+    await s1.commit({ time: now + 8 });
+    await s1.commit({ time: now + 10 });
+    await s1.commit({ time: now + 12 });
+    await s1.commit({ time: now + 14 });
+    await s1.commit({ time: now + 16 });
+  })
 
   after(() => {
     return Promise.all([
@@ -69,35 +67,35 @@ describe("Protocol 1.0 Dividend Update", function() {
     ])
   })
 
-  it('should have block#2 with no UD', () => s1.expectThat('/blockchain/block/2', (json) => {
+  it('should have block#2 with no UD', () => s1.expectThat('/blockchain/block/2', (json:HttpBlock) => {
     should.not.exist(json.dividend);
   }));
 
-  it('should have block#3 with UD 1000', () => s1.expectThat('/blockchain/block/3', (json) => {
-    json.dividend.should.equal(1000);
+  it('should have block#3 with UD 1000', () => s1.expectThat('/blockchain/block/3', (json:HttpBlock) => {
+    (json.dividend as any).should.equal(1000);
   }));
 
-  it('should have block#4 with no UD', () => s1.expectThat('/blockchain/block/4', (json) => {
+  it('should have block#4 with no UD', () => s1.expectThat('/blockchain/block/4', (json:HttpBlock) => {
     should.not.exist(json.dividend);
   }));
 
-  it('should have block#5 with UD 1000', () => s1.expectThat('/blockchain/block/5', (json) => {
-    json.dividend.should.equal(1000);
+  it('should have block#5 with UD 1000', () => s1.expectThat('/blockchain/block/5', (json:HttpBlock) => {
+    (json.dividend as any).should.equal(1000);
   }));
 
-  it('should have block#6 with UD 1000', () => s1.expectThat('/blockchain/block/6', (json) => {
-    json.dividend.should.equal(1000);
+  it('should have block#6 with UD 1000', () => s1.expectThat('/blockchain/block/6', (json:HttpBlock) => {
+    (json.dividend as any).should.equal(1000);
   }));
 
-  it('should have block#7 with UD 1000', () => s1.expectThat('/blockchain/block/7', (json) => {
-    json.dividend.should.equal(1000);
+  it('should have block#7 with UD 1000', () => s1.expectThat('/blockchain/block/7', (json:HttpBlock) => {
+    (json.dividend as any).should.equal(1000);
   }));
 
-  it('should have block#8 with UD 1000', () => s1.expectThat('/blockchain/block/8', (json) => {
-    json.dividend.should.equal(1000);
+  it('should have block#8 with UD 1000', () => s1.expectThat('/blockchain/block/8', (json:HttpBlock) => {
+    (json.dividend as any).should.equal(1000);
   }));
 
-  it('should have block#9 with UD 1000', () => s1.expectThat('/blockchain/block/9', (json) => {
-    json.dividend.should.equal(1000);
+  it('should have block#9 with UD 1000', () => s1.expectThat('/blockchain/block/9', (json:HttpBlock) => {
+    (json.dividend as any).should.equal(1000);
   }));
 });
diff --git a/test/integration/v1.0-g1-dividend-long-run.js b/test/integration/protocol/v1.0-g1-dividend-long-run.ts
similarity index 74%
rename from test/integration/v1.0-g1-dividend-long-run.js
rename to test/integration/protocol/v1.0-g1-dividend-long-run.ts
index 512ae506dbbb083319c4222fbddd1ebdf477532c..752f656b1216714ac6130e800567ea160a13d3e7 100644
--- a/test/integration/v1.0-g1-dividend-long-run.js
+++ b/test/integration/protocol/v1.0-g1-dividend-long-run.ts
@@ -11,13 +11,11 @@
 // 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 {HttpBlock} from "../../../app/modules/bma/lib/dtos"
 
-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 start = 1488985390; // 2016-03-08 16:03:10 UTC+0
 const delayToUD = 1489057200 - start; // Delay to 2016-03-09 12:00:00 UTC+0
@@ -39,7 +37,7 @@ const conf = {
   avgGenTime: 3600 * 24 // 1 bloc a day
 };
 
-let s1, cat, tac;
+let s1:TestingServer, cat:TestUser, tac:TestUser
 
 describe("Protocol 1.0 Äž1 Dividend - long run", function() {
 
@@ -50,19 +48,19 @@ describe("Protocol 1.0 Äž1 Dividend - long run", function() {
    * Simulates the real dividends that would occur in the currency (simulating N)
    */
 
-  before(() => co(function*() {
+  before(async () => {
 
-    const res1 = yield toolbox.simpleNodeWith2Users(conf);
+    const res1 = await simpleNodeWith2Users(conf);
     s1 = res1.s1;
     cat = res1.cat; // HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd
     tac = res1.tac; // 2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc
-    yield s1.commit({ time: start });
-    yield s1.commit({ time: start + 1 });
-    yield s1.commit({ time: start + delayToUD });
+    await s1.commit({ time: start });
+    await s1.commit({ time: start + 1 });
+    await s1.commit({ time: start + delayToUD });
     for (let i = 1; i < 20; i++) {
-      yield s1.commit({ time: (start + delayToUD) + aDay * i });
+      await s1.commit({ time: (start + delayToUD) + aDay * i });
     }
-  }));
+  })
 
   after(() => {
     return Promise.all([
@@ -70,38 +68,38 @@ describe("Protocol 1.0 Äž1 Dividend - long run", function() {
     ])
   })
 
-  it('should have block#0 has no UD', () => s1.expectThat('/blockchain/block/0', (json) => {
+  it('should have block#0 has no UD', () => s1.expectThat('/blockchain/block/0', (json:HttpBlock) => {
     should.not.exist(json.dividend);
     json.should.have.property('medianTime').equal(start); // 2016-03-08 16:03:10 UTC+0
   }));
 
-  it('should have block#1 has no UD', () => s1.expectThat('/blockchain/block/1', (json) => {
-    json.dividend.should.equal(1000);
+  it('should have block#1 has no UD', () => s1.expectThat('/blockchain/block/1', (json:HttpBlock) => {
+    (json.dividend as any).should.equal(1000);
     json.should.have.property('medianTime').equal(start); // 2016-03-08 16:03:10 UTC+0
   }));
 
-  it('should have block#2 with UD 1000', () => s1.expectThat('/blockchain/block/2', (json) => {
+  it('should have block#2 with UD 1000', () => s1.expectThat('/blockchain/block/2', (json:HttpBlock) => {
     should.not.exist(json.dividend);
     json.should.have.property('medianTime').equal(start + 1); // 2016-03-08 16:03:11 UTC+0
   }));
 
-  it('should have block#3 with UD 1000', () => s1.expectThat('/blockchain/block/3', (json) => {
-    json.dividend.should.equal(1000);
+  it('should have block#3 with UD 1000', () => s1.expectThat('/blockchain/block/3', (json:HttpBlock) => {
+    (json.dividend as any).should.equal(1000);
     json.should.have.property('medianTime').equal(start + delayToUD); // 2016-03-09 12:00:00 UTC+0
   }));
 
-  it('should have block#4 with UD 1000', () => s1.expectThat('/blockchain/block/4', (json) => {
-    json.dividend.should.equal(1000);
+  it('should have block#4 with UD 1000', () => s1.expectThat('/blockchain/block/4', (json:HttpBlock) => {
+    (json.dividend as any).should.equal(1000);
     json.should.have.property('medianTime').equal((start + delayToUD) + aDay); // 2016-03-10 12:00:00 UTC+0
   }));
 
-  it('should have block#14 with UD 1000, even if dtReeval has been reached', () => s1.expectThat('/blockchain/block/15', (json) => {
-    json.dividend.should.equal(1000);
+  it('should have block#14 with UD 1000, even if dtReeval has been reached', () => s1.expectThat('/blockchain/block/15', (json:HttpBlock) => {
+    (json.dividend as any).should.equal(1000);
     json.should.have.property('medianTime').equal((start + delayToUD) + aDay * 12); // 2016-03-21 12:00:00 UTC+0
   }));
 
-  it('should have block#14 with UD 1000, even if dtReeval has been reached', () => s1.expectThat('/blockchain/block/16', (json) => {
-    json.dividend.should.equal(1000);
+  it('should have block#14 with UD 1000, even if dtReeval has been reached', () => s1.expectThat('/blockchain/block/16', (json:HttpBlock) => {
+    (json.dividend as any).should.equal(1000);
     json.should.have.property('medianTime').equal((start + delayToUD) + aDay * 13); // 2016-03-22 12:00:00 UTC+0
   }));
 });
diff --git a/test/integration/v1.0-g1-dividend.js b/test/integration/protocol/v1.0-g1-dividend.ts
similarity index 71%
rename from test/integration/v1.0-g1-dividend.js
rename to test/integration/protocol/v1.0-g1-dividend.ts
index 55991a1c71edc41e9c05ccd26194a4dd605cecfd..3a15bfb8e41dfb668fd96a4d7e579fcb754b2bec 100644
--- a/test/integration/v1.0-g1-dividend.js
+++ b/test/integration/protocol/v1.0-g1-dividend.ts
@@ -11,13 +11,11 @@
 // 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 {HttpBlock} from "../../../app/modules/bma/lib/dtos"
 
-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 start = 1488985390; // 2016-03-08 16:03:10 UTC+0
 const delayToUD = 1489057200 - start; // Delay to 2016-03-09 12:00:00 UTC+0
@@ -36,7 +34,7 @@ const conf = {
   avgGenTime: 3600 * 24 // 1 bloc a day
 };
 
-let s1, cat, tac;
+let s1:TestingServer, cat:TestUser, tac:TestUser
 
 describe("Protocol 1.0 Äž1 Dividend", function() {
 
@@ -47,19 +45,19 @@ describe("Protocol 1.0 Äž1 Dividend", function() {
    * Simulates the real dividends that would occur in the currency (simulating N)
    */
 
-  before(() => co(function*() {
+  before(async () => {
 
-    const res1 = yield toolbox.simpleNodeWith2Users(conf);
+    const res1 = await simpleNodeWith2Users(conf);
     s1 = res1.s1;
     cat = res1.cat; // HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd
     tac = res1.tac; // 2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc
-    yield s1.commit({ time: start });
-    yield s1.commit({ time: start + 1 });
-    yield s1.commit({ time: start + delayToUD });
+    await s1.commit({ time: start });
+    await s1.commit({ time: start + 1 });
+    await s1.commit({ time: start + delayToUD });
     for (let i = 1; i < 15; i++) {
-      yield s1.commit({ time: (start + delayToUD) + aDay * i });
+      await s1.commit({ time: (start + delayToUD) + aDay * i });
     }
-  }));
+  })
 
   after(() => {
     return Promise.all([
@@ -67,70 +65,70 @@ describe("Protocol 1.0 Äž1 Dividend", function() {
     ])
   })
 
-  it('should have block#0 has no UD', () => s1.expectThat('/blockchain/block/0', (json) => {
+  it('should have block#0 has no UD', () => s1.expectThat('/blockchain/block/0', (json:HttpBlock) => {
     should.not.exist(json.dividend);
     json.should.have.property('medianTime').equal(start); // 2016-03-08 16:03:10 UTC+0
   }));
 
-  it('should have block#1 has no UD', () => s1.expectThat('/blockchain/block/1', (json) => {
-    json.dividend.should.equal(1000);
+  it('should have block#1 has no UD', () => s1.expectThat('/blockchain/block/1', (json:HttpBlock) => {
+    (json.dividend as any).should.equal(1000);
     json.should.have.property('medianTime').equal(start); // 2016-03-08 16:03:10 UTC+0
   }));
 
-  it('should have block#2 with UD 1000', () => s1.expectThat('/blockchain/block/2', (json) => {
+  it('should have block#2 with UD 1000', () => s1.expectThat('/blockchain/block/2', (json:HttpBlock) => {
     should.not.exist(json.dividend);
     json.should.have.property('medianTime').equal(start + 1); // 2016-03-08 16:03:11 UTC+0
   }));
 
-  it('should have block#3 with UD 1000', () => s1.expectThat('/blockchain/block/3', (json) => {
-    json.dividend.should.equal(1000);
+  it('should have block#3 with UD 1000', () => s1.expectThat('/blockchain/block/3', (json:HttpBlock) => {
+    (json.dividend as any).should.equal(1000);
     json.should.have.property('medianTime').equal(start + delayToUD); // 2016-03-09 12:00:00 UTC+0
   }));
 
-  it('should have block#4 with UD 1000', () => s1.expectThat('/blockchain/block/4', (json) => {
-    json.dividend.should.equal(1000);
+  it('should have block#4 with UD 1000', () => s1.expectThat('/blockchain/block/4', (json:HttpBlock) => {
+    (json.dividend as any).should.equal(1000);
     json.should.have.property('medianTime').equal((start + delayToUD) + aDay); // 2016-03-10 12:00:00 UTC+0
   }));
 
-  it('should have block#4 with UD 1000', () => s1.expectThat('/blockchain/block/5', (json) => {
-    json.dividend.should.equal(1000);
+  it('should have block#4 with UD 1000', () => s1.expectThat('/blockchain/block/5', (json:HttpBlock) => {
+    (json.dividend as any).should.equal(1000);
     json.should.have.property('medianTime').equal((start + delayToUD) + aDay * 2); // 2016-03-11 12:00:00 UTC+0
   }));
 
-  it('should have block#4 with UD 1000', () => s1.expectThat('/blockchain/block/6', (json) => {
-    json.dividend.should.equal(1000);
+  it('should have block#4 with UD 1000', () => s1.expectThat('/blockchain/block/6', (json:HttpBlock) => {
+    (json.dividend as any).should.equal(1000);
     json.should.have.property('medianTime').equal((start + delayToUD) + aDay * 3); // 2016-03-12 12:00:00 UTC+0
   }));
 
   // ... skip some blocks ...
 
-  it('should have block#11 with UD 1000', () => s1.expectThat('/blockchain/block/11', (json) => {
-    json.dividend.should.equal(1000);
+  it('should have block#11 with UD 1000', () => s1.expectThat('/blockchain/block/11', (json:HttpBlock) => {
+    (json.dividend as any).should.equal(1000);
     json.should.have.property('medianTime').equal((start + delayToUD) + aDay * 8); // 2016-03-17 12:00:00 UTC+0
   }));
 
-  it('should have block#12 with UD 1000', () => s1.expectThat('/blockchain/block/12', (json) => {
-    json.dividend.should.equal(1000);
+  it('should have block#12 with UD 1000', () => s1.expectThat('/blockchain/block/12', (json:HttpBlock) => {
+    (json.dividend as any).should.equal(1000);
     json.should.have.property('medianTime').equal((start + delayToUD) + aDay * 9); // 2016-03-18 12:00:00 UTC+0
   }));
 
-  it('should have block#13 with UD 1000', () => s1.expectThat('/blockchain/block/13', (json) => {
-    json.dividend.should.equal(1000);
+  it('should have block#13 with UD 1000', () => s1.expectThat('/blockchain/block/13', (json:HttpBlock) => {
+    (json.dividend as any).should.equal(1000);
     json.should.have.property('medianTime').equal((start + delayToUD) + aDay * 10); // 2016-03-19 12:00:00 UTC+0
   }));
 
-  it('should have block#14 with UD 1000', () => s1.expectThat('/blockchain/block/14', (json) => {
-    json.dividend.should.equal(1000);
+  it('should have block#14 with UD 1000', () => s1.expectThat('/blockchain/block/14', (json:HttpBlock) => {
+    (json.dividend as any).should.equal(1000);
     json.should.have.property('medianTime').equal((start + delayToUD) + aDay * 11); // 2016-03-20 12:00:00 UTC+0
   }));
 
-  it('should have block#14 with UD 1000, even if dtReeval has been reached', () => s1.expectThat('/blockchain/block/15', (json) => {
-    json.dividend.should.equal(1000);
+  it('should have block#14 with UD 1000, even if dtReeval has been reached', () => s1.expectThat('/blockchain/block/15', (json:HttpBlock) => {
+    (json.dividend as any).should.equal(1000);
     json.should.have.property('medianTime').equal((start + delayToUD) + aDay * 12); // 2016-03-21 12:00:00 UTC+0
   }));
 
-  it('should have block#14 with UD 1000, even if dtReeval has been reached', () => s1.expectThat('/blockchain/block/16', (json) => {
-    json.dividend.should.equal(1000);
+  it('should have block#14 with UD 1000, even if dtReeval has been reached', () => s1.expectThat('/blockchain/block/16', (json:HttpBlock) => {
+    (json.dividend as any).should.equal(1000);
     json.should.have.property('medianTime').equal((start + delayToUD) + aDay * 13); // 2016-03-22 12:00:00 UTC+0
   }));
 });
diff --git a/test/integration/v1.0-modules-api.js b/test/integration/protocol/v1.0-modules-api.ts
similarity index 70%
rename from test/integration/v1.0-modules-api.js
rename to test/integration/protocol/v1.0-modules-api.ts
index 9c6b3b76bbde6431aef9c29f4bb3129d680273b8..28c2798a45768c4d91af68d462c4650ad996fe5a 100644
--- a/test/integration/v1.0-modules-api.js
+++ b/test/integration/protocol/v1.0-modules-api.ts
@@ -11,29 +11,30 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import * as stream from "stream"
+import {parsers} from "../../../app/lib/common-libs/parsers/index"
+import {Server} from "../../../server"
+import {ConfDTO} from "../../../app/lib/dto/ConfDTO"
+import {KeypairDependency} from "../../../app/modules/keypair/index"
+import {BmaDependency} from "../../../app/modules/bma/index"
 
-const co      = require('co');
-const _       = require('underscore');
 const should  = require('should');
 const util    = require('util');
 const path    = require('path');
-const stream  = require('stream');
-const duniter = require('../../index');
-const parsers = require('../../app/lib/common-libs/parsers').parsers
+const duniter = require('../../../index');
 const querablep = require('querablep');
 
 describe("v1.0 Module API", () => {
 
-  it('should be able to execute `hello` command with quickRun', () => co(function*() {
+  it('should be able to execute `hello` command with quickRun', async () => {
     duniter.statics.setOnRunDone(() => { /* Do not exit the process */ })
-    const absolutePath = path.join(__dirname, './scenarios/hello-plugin.js')
-    process.argv = ['', absolutePath, 'hello-world']
-    const res = yield duniter.statics.quickRun(absolutePath)
+    const absolutePath = path.join(__dirname, '../scenarios/hello-plugin.js')
+    process.argv = ['', absolutePath, 'hello-world', '--memory']
+    const res = await duniter.statics.quickRun(absolutePath)
     res.should.equal('Hello world! from within Duniter.')
-  }))
+  })
 
-  it('should be able to execute `hello` command', () => co(function*() {
+  it('should be able to execute `hello` command', async () => {
 
     const sStack = duniter.statics.simpleStack();
     const aStack = duniter.statics.autoStack();
@@ -47,21 +48,21 @@ describe("v1.0 Module API", () => {
         cli: [{
           name: 'hello',
           desc: 'Returns an "Hello, world" string after configuration phase.',
-          onConfiguredExecute: (server, conf, program, params) => co(function*(){
+          onConfiguredExecute: async (server:Server, conf:ConfDTO, program:any, params:any) => {
             return "Hello, " + params[0] + ". You successfully sent arg '" + params[1] + "' along with opt1 = " + program.opt1 + " and option2 = " + program.option2 + ".";
-          })
+          }
         }]
       }
     };
 
     sStack.registerDependency(helloDependency, 'duniter-hello');
     sStack.registerDependency(helloDependency, 'duniter-hello'); // Try to load it 2 times, should not throw an error
-    sStack.registerDependency(require('../../app/modules/keypair').KeypairDependency, 'duniter-keypair');
+    sStack.registerDependency(KeypairDependency, 'duniter-keypair');
     aStack.registerDependency(helloDependency, 'duniter-hello');
 
-    (yield sStack.executeStack(['node', 'index.js', '--memory', 'hello', 'World', 'TEST', '--opt1', '--option2', '5'])).should.equal('Hello, World. You successfully sent arg \'TEST\' along with opt1 = true and option2 = 5.');
-    (yield aStack.executeStack(['node', 'index.js', '--memory', 'hello', 'Zorld', 'ESSE', '--option2', 'd'])).should.equal('Hello, Zorld. You successfully sent arg \'ESSE\' along with opt1 = undefined and option2 = NaN.');
-  }));
+    (await sStack.executeStack(['node', 'index.js', '--memory', 'hello', 'World', 'TEST', '--opt1', '--option2', '5'])).should.equal('Hello, World. You successfully sent arg \'TEST\' along with opt1 = true and option2 = 5.');
+    (await aStack.executeStack(['node', 'index.js', '--memory', 'hello', 'Zorld', 'ESSE', '--option2', 'd'])).should.equal('Hello, Zorld. You successfully sent arg \'ESSE\' along with opt1 = undefined and option2 = NaN.');
+  })
 
   /***********************
    * CONFIGURATION HOOKS
@@ -69,13 +70,12 @@ describe("v1.0 Module API", () => {
 
   describe("Configuration hooks", () => {
 
-    let stack;
-    function run() {
-      const args = Array.from(arguments);
+    let stack:any
+    function run(...args:string[]) {
       return stack.executeStack(['node', 'index.js', '--mdb', 'modules_api_tests'].concat(args));
     }
 
-    before(() => co(function*() {
+    before(async () => {
 
       stack = duniter.statics.simpleStack();
       const configurationDependency = {
@@ -85,7 +85,7 @@ describe("v1.0 Module API", () => {
             { value: '--superpasswd <passwd>', desc: 'A crypto password.' }
           ],
           config: {
-            onLoading: (conf, program) => co(function*(){
+            onLoading: async (conf:any, program:any) => {
 
               // Always adds a parameter named "superkey"
               conf.superkey = { pub: 'publicPart', sec: 'secretPart' };
@@ -97,12 +97,11 @@ describe("v1.0 Module API", () => {
               if (program.superpasswd) {
                 conf.superpasswd = program.superpasswd;
               }
-            }),
-            beforeSave: (conf, program) => co(function*(){
-
+            },
+            beforeSave: async (conf:any) => {
               // We never want to store "superpasswd"
               delete conf.superpasswd;
-            })
+            }
           }
         }
       };
@@ -111,52 +110,52 @@ describe("v1.0 Module API", () => {
           cli: [{
             name: 'gimme-conf',
             desc: 'Returns the configuration object.',
-            onDatabaseExecute: (server, conf, program, params, startServices, stopServices) => co(function*() {
+            onConfiguredExecute: async (server:Server, conf:any) => {
               // Gimme the conf!
               return conf;
-            })
+            }
           }]
         }
       };
 
-      stack.registerDependency(require('../../app/modules/keypair').KeypairDependency, 'duniter-keypair');
+      stack.registerDependency(KeypairDependency, 'duniter-keypair');
       stack.registerDependency(configurationDependency, 'duniter-configuration');
       stack.registerDependency(returnConfDependency, 'duniter-gimme-conf');
-    }));
+    })
 
-    it('verify that we get the CLI options', () => co(function*() {
-      const conf = yield run('gimme-conf', '--supersalt', 'NaCl');
+    it('verify that we get the CLI options', async () => {
+      const conf = await run('gimme-conf', '--supersalt', 'NaCl');
       conf.should.have.property('supersalt').equal('NaCl');
-    }));
+    })
 
-    it('verify that we get the saved options', () => co(function*() {
+    it('verify that we get the saved options', async () => {
       let conf;
 
       // We make an initial reset
-      yield run('reset', 'config');
-      conf = yield run('gimme-conf');
+      await run('reset', 'config');
+      conf = await run('gimme-conf');
       conf.should.have.property('superkey'); // Always loaded
       conf.should.not.have.property('supersalt');
 
       // Nothing should have changed
-      conf = yield run('gimme-conf');
+      conf = await run('gimme-conf');
       conf.should.have.property('superkey'); // Always loaded
       conf.should.not.have.property('supersalt');
 
       // Now we try to save the parameters
-      yield run('config', '--supersalt', 'NaCl2', '--superpasswd', 'megapasswd');
-      conf = yield run('gimme-conf');
+      await run('config', '--supersalt', 'NaCl2', '--superpasswd', 'megapasswd');
+      conf = await run('gimme-conf');
       conf.should.have.property('superkey'); // Always loaded
       conf.should.have.property('supersalt').equal('NaCl2');
       conf.should.not.have.property('superpasswd');
 
       // Yet we can have all options by giving them explicitely using options
-      conf = yield run('gimme-conf', '--superpasswd', 'megapasswd2');
+      conf = await run('gimme-conf', '--superpasswd', 'megapasswd2');
       conf.should.have.property('superkey');
       conf.should.have.property('supersalt').equal('NaCl2');
       conf.should.have.property('superpasswd').equal('megapasswd2');
-    }));
-  });
+    })
+  })
 
   /***********************
    *  SERVICE START/STOP
@@ -164,32 +163,31 @@ describe("v1.0 Module API", () => {
 
   describe("Service triggers", () => {
 
-    let stack;
-    let fakeI;
-    let fakeP;
-    let fakeO;
+    let stack:any
+    let fakeI:FakeStream
+    let fakeP:FakeStream
+    let fakeO:FakeStream
 
-    function run() {
-      const args = Array.from(arguments);
+    function run(...args:string[]) {
       return stack.executeStack(['node', 'index.js', '--memory', '--ws2p-noupnp'].concat(args));
     }
 
-    before(() => co(function*() {
+    before(async () => {
 
       stack = duniter.statics.simpleStack();
-      fakeI = new FakeStream((that, data) => {
+      fakeI = new FakeStream((that:any, data:any) => {
         // Note: we never pass here
         if (typeof data == "string") {
           that.push(data);
         }
       });
-      fakeP = new FakeStream((that, data) => {
+      fakeP = new FakeStream((that:any, data:any) => {
         if (typeof data == "object" && data.type == "transaction") {
           const tx = parsers.parseTransaction.syncWrite(data.doc);
           that.push(tx);
         }
       });
-      fakeO = new FakeStream((that, data, enc, done) => {
+      fakeO = new FakeStream((that:any, data:any, enc:any, done:any) => {
         if (data.issuers) {
           that.resolveData();
         }
@@ -202,8 +200,8 @@ describe("v1.0 Module API", () => {
           cli: [{
             name: 'hello-service',
             desc: 'Says hello to the world, at service phase. And feed INPUT with a transaction.',
-            onDatabaseExecute: (duniterServer, conf, program, programArgs, startServices, stopServices) => co(function*(){
-              yield startServices();
+            onDatabaseExecute: async (duniterServer:Server, conf:any, program:any, programArgs:any, startServices:any) => {
+              await startServices();
               fakeI.push("Version: 10\n" +
                 "Type: Transaction\n" +
                 "Currency: test_net\n" +
@@ -220,9 +218,9 @@ describe("v1.0 Module API", () => {
                 "99000:0:SIG(HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk)\n" +
                 "Comment: reessai\n" +
                 "P6MxJ/2SdkvNDyIyWuOkTz3MUwsgsfo70j+rpWeQWcm6GdvKQsbplB8482Ar1HMz2q0h5V3tfMqjCuAeWVQ+Ag==\n");
-              yield fakeO.outputed;
+              await fakeO.outputed;
               return fakeO.outputed;
-            })
+            }
           }],
           service: {
             input: () => fakeI,
@@ -236,10 +234,10 @@ describe("v1.0 Module API", () => {
           cli: [{
             name: 'bye-service',
             desc: 'Says goodbye to the world, at service phase.',
-            onDatabaseExecute: (duniterServer, conf, program, programArgs, startServices, stopServices) => co(function*(){
-              yield stopServices();
+            onDatabaseExecute: async (duniterServer:any, conf:any, program:any, programArgs:any, startServices:any, stopServices:any) => {
+              await stopServices();
               return Promise.resolve();
-            })
+            }
           }],
           service: {
             input: () => fakeI,
@@ -249,20 +247,20 @@ describe("v1.0 Module API", () => {
         }
       };
 
-      stack.registerDependency(require('../../app/modules/keypair').KeypairDependency, 'duniter-keypair');
-      stack.registerDependency(require('../../app/modules/bma').BmaDependency, 'duniter-bma');
+      stack.registerDependency(KeypairDependency, 'duniter-keypair');
+      stack.registerDependency(BmaDependency, 'duniter-bma');
       stack.registerDependency(dummyStartServiceDependency, 'duniter-dummy-start');
       stack.registerDependency(dummyStopServiceDependency, 'duniter-dummy-stop');
-    }));
+    })
 
-    it('verify that services are started', () => co(function*() {
+    it('verify that services are started', async () => {
       fakeI.started.isResolved().should.equal(false);
       fakeP.started.isResolved().should.equal(false);
       fakeO.started.isResolved().should.equal(false);
       fakeI.stopped.isResolved().should.equal(false);
       fakeP.stopped.isResolved().should.equal(false);
       fakeO.stopped.isResolved().should.equal(false);
-      yield run('hello-service');
+      await run('hello-service');
       fakeO.outputed.isResolved().should.equal(true); // The transaction has successfully gone through the whole stream
       fakeI.started.isResolved().should.equal(true);
       fakeP.started.isResolved().should.equal(true);
@@ -270,50 +268,57 @@ describe("v1.0 Module API", () => {
       fakeI.stopped.isResolved().should.equal(false);
       fakeP.stopped.isResolved().should.equal(false);
       fakeO.stopped.isResolved().should.equal(false);
-    }));
+    })
 
-    it('verify that services are stopped', () => co(function*() {
+    it('verify that services are stopped', async () => {
       fakeI.stopped.isResolved().should.equal(false);
       fakeP.stopped.isResolved().should.equal(false);
       fakeO.stopped.isResolved().should.equal(false);
       fakeI.started.isResolved().should.equal(true);
       fakeP.started.isResolved().should.equal(true);
       fakeO.started.isResolved().should.equal(true);
-      yield run('bye-service');
+      await run('bye-service');
       fakeI.started.isResolved().should.equal(false);
       fakeP.started.isResolved().should.equal(false);
       fakeO.started.isResolved().should.equal(false);
       fakeI.stopped.isResolved().should.equal(true);
       fakeP.stopped.isResolved().should.equal(true);
       fakeO.stopped.isResolved().should.equal(true);
-    }));
-  });
+    })
+  })
 
-});
+})
 
 
-function FakeStream(onWrite) {
+class FakeStream extends stream.Transform {
 
-  const that = this;
-  stream.Transform.call(this, { objectMode: true });
+  private resolveStart:any = () => null;
+  private resolveStop:any  = () => null;
+  public resolveData:any
+  public started:any
+  public stopped:any
+  public outputed:any
 
-  let resolveStart = () => null;
-  let resolveStop  = () => null;
+  constructor(private onWrite:any) {
+    super({ objectMode: true })
 
-  this._write = onWrite.bind(this, that);
+    this.started = querablep(new Promise(res => this.resolveStart = res));
+    this.stopped = querablep(new Promise(res => this.resolveStop  = res));
+  }
 
-  this.started = querablep(new Promise(res => resolveStart = res));
-  this.stopped = querablep(new Promise(res => resolveStop  = res));
+  _write(obj:any, enc:any, done:any) {
+    this.onWrite(this, obj, enc, done)
+  }
 
-  this.startService = () => co(function*() {
-    resolveStart();
-    that.stopped = querablep(new Promise(res => resolveStop = res));
-  });
+  async startService() {
+    this.resolveStart();
+    this.stopped = querablep(new Promise(res => this.resolveStop = res));
+  }
 
-  this.stopService = () => co(function*() {
-    resolveStop();
-    that.started = querablep(new Promise(res => resolveStart = res));
-  });
+  async stopService() {
+    this.resolveStop();
+    this.started = querablep(new Promise(res => this.resolveStart = res));
+  }
 }
 
 util.inherits(FakeStream, stream.Transform);
diff --git a/test/integration/v1.1-dividend.js b/test/integration/protocol/v1.1-dividend.ts
similarity index 76%
rename from test/integration/v1.1-dividend.js
rename to test/integration/protocol/v1.1-dividend.ts
index 475593909345ea6809697947e79c3a14b66ba977..c4a6add28bb050488afd933d8f6d4db804e8afef 100644
--- a/test/integration/v1.1-dividend.js
+++ b/test/integration/protocol/v1.1-dividend.ts
@@ -11,25 +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 {HttpSources, HttpTxHistory} from "../../../app/modules/bma/lib/dtos"
 
-const co        = require('co');
 const should    = require('should');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const TestUser  = require('./tools/TestUser').TestUser
-const commit    = require('./tools/commit');
-const toolbox   = require('./tools/toolbox');
 
 const now = 1484000000;
 
-let s1, cat, tac, tic
+let s1:TestingServer, cat:TestUser, tac:TestUser, tic:TestUser
 
 
 describe("Protocol 1.1 Dividend", function() {
 
-  before(() => co(function*() {
+  before(async () => {
 
-    s1 = toolbox.server({
+    s1 = NewTestingServer({
       c: 0.1,
       dt: 10,
       dtReeval: 10,
@@ -47,26 +44,26 @@ describe("Protocol 1.1 Dividend", function() {
     tac = new TestUser('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
     tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
 
-    yield s1.initDalBmaConnections();
+    await 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 + 10 });
-    yield s1.commit({ time: now + 10 * 2 });
-    yield s1.commit({ time: now + 10 * 3 });
+    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 + 10 });
+    await s1.commit({ time: now + 10 * 2 });
+    await s1.commit({ time: now + 10 * 3 });
 
     // tic joins
-    yield tic.createIdentity();
-    yield cat.cert(tic);
-    yield tic.join();
-    yield s1.commit({ time: now + 10 + 10 * 4 });
-    yield s1.commit({ time: now + 10 + 10 * 5 });
-  }));
+    await tic.createIdentity();
+    await cat.cert(tic);
+    await tic.join();
+    await s1.commit({ time: now + 10 + 10 * 4 });
+    await s1.commit({ time: now + 10 + 10 * 5 });
+  })
 
   after(() => {
     return Promise.all([
@@ -74,7 +71,7 @@ describe("Protocol 1.1 Dividend", function() {
     ])
   })
 
-  it('should exit 2 dividends for cat', () => s1.expect('/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', (res) => {
+  it('should exit 2 dividends for cat', () => s1.expect('/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', (res:HttpSources) => {
     res.should.have.property('pubkey').equal('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
     res.should.have.property('sources').length(4);
     res.sources[0].should.have.property('amount').equal(100); // UD(0) = ud0 => M(0) = 0
@@ -83,12 +80,12 @@ describe("Protocol 1.1 Dividend", function() {
     res.sources[3].should.have.property('amount').equal(103); // t = 3, M(t-1) = 402, N(t) = 3, UD(t) = UD(t-1) + c²*M(t-1)/N(t) = 101 + 0.01*400/3 = 103 (ceiled) => M(3) = M(2)+N(t-1)*DU(t-1) = 400+3*101 = 703
     res.sources[0].should.have.property('base').equal(0);
     res.sources[1].should.have.property('base').equal(0);
-  }));
+  }))
 
-  it('should be able to send 300 units', () => co(function *() {
-    yield cat.send(105, tac);
-    yield s1.commit();
-    yield s1.expect('/tx/sources/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', (res) => {
+  it('should be able to send 300 units', async () => {
+    await cat.sendMoney(105, tac);
+    await s1.commit();
+    await s1.expect('/tx/sources/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', (res:HttpSources) => {
       res.should.have.property('pubkey').equal('2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc');
       res.should.have.property('sources').length(6);
       res.sources[0].should.have.property('amount').equal(100);
@@ -104,10 +101,10 @@ describe("Protocol 1.1 Dividend", function() {
       res.sources[4].should.have.property('type').equal('D');
       res.sources[5].should.have.property('type').equal('T');
     })
-  }));
+  })
 
-  it('should have a correct history', () => s1.expect('/tx/history/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', (res) => {
+  it('should have a correct history', () => s1.expect('/tx/history/2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', (res:HttpTxHistory) => {
     res.history.received[0].should.have.property('blockstamp').not.equal(null).not.equal('');
     res.history.received[0].should.have.property('blockstampTime').not.equal(null).greaterThan(0);
-  }));
-});
+  }))
+})
diff --git a/test/integration/revoked_pubkey_replay.ts b/test/integration/revoked_pubkey_replay.ts
index e0a32f2ede9aa57a05c157262f1762e894cb39a2..cb94affdafcd173587d27cd53743df6b30589359 100644
--- a/test/integration/revoked_pubkey_replay.ts
+++ b/test/integration/revoked_pubkey_replay.ts
@@ -12,14 +12,13 @@
 // 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() {
 
   const now = 1500000000
-  const DONT_WAIT_FOR_BLOCKCHAIN_CHANGE = true
   let s1:TestingServer, cat:any, tic:any
 
   const conf = { nbCores: 1, sigQty: 1 }
@@ -47,7 +46,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 +62,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)
     })
   })
@@ -71,7 +70,7 @@ describe("Revoked pubkey replay", function() {
   it('should not try to include tic2 in a new block', async () => {
     await s1.commit()
     await tic.join()
-    const block = await s1.commit(null, DONT_WAIT_FOR_BLOCKCHAIN_CHANGE)
+    const block = await s1.justCommit()
     block.should.have.property('joiners').length(0)
   })
 
diff --git a/test/integration/server-sandbox.js b/test/integration/sandbox/server-sandbox.ts
similarity index 53%
rename from test/integration/server-sandbox.js
rename to test/integration/sandbox/server-sandbox.ts
index 732087dca6336194a40da5ccbf2670753d999256..1bef58893d32dd9e8a0e55a2d2af2e5231c02302 100644
--- a/test/integration/server-sandbox.js
+++ b/test/integration/sandbox/server-sandbox.ts
@@ -11,26 +11,22 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {CommonConstants} from "../../../app/lib/common-libs/constants"
+import {NewTestingServer, TestingServer} from "../tools/toolbox"
+import {TestUser} from "../tools/TestUser"
 
-const co        = require('co');
 const should    = require('should');
-const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const TestUser  = require('./tools/TestUser').TestUser
-const commit    = require('./tools/commit');
-const toolbox   = require('./tools/toolbox');
-const constants = require('../../app/lib/constants');
-const CommonConstants = require('../../app/lib/common-libs/constants').CommonConstants
+const constants = require('../../../app/lib/constants');
 
 const now = 1482300000;
 
-let s1, s2, s3, i1, i2, i3, i4, i5, i6, i7, i7onS2, i8, i9, i10, i11, i12, i13, i14, i15, i16
+let s1:TestingServer, s2:TestingServer, s3:TestingServer, i1:TestUser, i2:TestUser, i3:TestUser, i4:TestUser, i5:TestUser, i6:TestUser, i7:TestUser, i7onS2:TestUser, i8:TestUser, i9:TestUser, i10:TestUser, i11:TestUser, i12:TestUser, i13:TestUser, i14:TestUser
 
 describe("Sandboxes", function() {
+  
+  before(async () => {
 
-  before(() => co(function*() {
-
-    s1 = toolbox.server({
+    s1 = NewTestingServer({
       idtyWindow: 10,
       sigWindow: 10,
       msWindow: 10,
@@ -42,14 +38,14 @@ describe("Sandboxes", function() {
       }
     });
 
-    s2 = toolbox.server({
+    s2 = NewTestingServer({
       pair: {
         pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV',
         sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'
       }
     });
 
-    s3 = toolbox.server({
+    s3 = NewTestingServer({
       pair: {
         pub: 'H9dtBFmJohAwMNXSbfoL6xfRtmrqMw8WZnjXMHr4vEHX',
         sec: '2ANWb1qjjYRtT2TPFv1rBWA4EVfY7pqE4WqFUuzEgWG4vzcuvyUxMtyeBSf93M4V3g4MeEkELaj6NjA72jxnb4yF'
@@ -74,15 +70,15 @@ describe("Sandboxes", function() {
 // i15 = new TestUser('i15', { pub: '8cHWEmVrdT249w8vJdiBms9mbu6CguQgXx2gRVE8gfnT', sec: '5Fy9GXiLMyhvRLCpoFf35XXNj24WXX29wM6xeCQiy5Uk7ggNhRcZjjp8GcpjRyE94oNR2jRNK4eAGiYUFnvbEnGB' }, { server: s1 });
 // i16 = new TestUser('i16', { pub: 'vi8hUTxss825cFCQE4SzmqBaAwLS236NmtrTQZBAAhG',  sec: '5dVvAdWKcndQSaR9pzjEriRhGkCjef74HzecqKnydBVHdxXDewpAu3mcSU72PRKcCkTYTJPpgWmwuCyZubDKmoy4' }, { server: s1 });
 
-    yield s1.initDalBmaConnections();
-    yield s2.initDalBmaConnections();
-    yield s3.initDalBmaConnections();
+    await s1.initDalBmaConnections();
+    await s2.initDalBmaConnections();
+    await s3.initDalBmaConnections();
     s1.dal.idtyDAL.setSandboxSize(3);
     s1.dal.msDAL.setSandboxSize(2);
     s1.dal.txsDAL.setSandboxSize(2);
     s2.dal.idtyDAL.setSandboxSize(10);
     s3.dal.idtyDAL.setSandboxSize(3);
-  }));
+  })
 
   after(() => {
     return Promise.all([
@@ -95,108 +91,108 @@ describe("Sandboxes", function() {
   describe('Identities', () => {
 
 
-    it('should i1, i2, i3', () => co(function *() {
-      (yield s1.dal.idtyDAL.getSandboxRoom()).should.equal(3);
-      yield i1.createIdentity();
-      yield i2.createIdentity();
-      yield i3.createIdentity();
-      (yield s1.dal.idtyDAL.getSandboxRoom()).should.equal(0);
-    }));
-
-    it('should reject i4', () => shouldThrow(co(function *() {
-      (yield s1.dal.idtyDAL.getSandboxRoom()).should.equal(0);
-      yield i4.createIdentity();
-    })));
-
-    it('should create i4 by i1->i4', () => co(function *() {
-      yield i4.createIdentity(null, s2);
-      yield i1.cert(i4, s2);
-    }));
-
-    it('should accept i1 (already here) by i4->i1', () => co(function *() {
-      yield i4.cert(i1);
-    }));
-
-    it('should commit & make room for sandbox, and commit again', () => co(function *() {
-      yield i1.join();
-      yield i4.join();
-      (yield s1.dal.idtyDAL.getSandboxRoom()).should.equal(0);
-      yield s1.commit({ time: now });
-      (yield s1.dal.idtyDAL.getSandboxRoom()).should.equal(3); // i2, i3 were removed for too old identities (based on virtual root block)
-      yield i2.createIdentity();
-      yield i3.createIdentity();
-      (yield s1.dal.idtyDAL.getSandboxRoom()).should.equal(1);
-      yield s1.commit({ time: now });
-      yield s2.syncFrom(s1, 0, 1);
-      yield s3.syncFrom(s1, 0, 1);
-    }));
-
-    it('should create i5(1)', () => co(function *() {
-      yield i5.createIdentity();
-      (yield s1.dal.idtyDAL.getSandboxRoom()).should.equal(0);
-    }));
+    it('should i1, i2, i3', async () => {
+      (await s1.dal.idtyDAL.getSandboxRoom()).should.equal(3);
+      await i1.createIdentity();
+      await i2.createIdentity();
+      await i3.createIdentity();
+      (await s1.dal.idtyDAL.getSandboxRoom()).should.equal(0);
+    })
+
+    it('should reject i4', () => shouldThrow((async () => {
+      (await s1.dal.idtyDAL.getSandboxRoom()).should.equal(0);
+      await i4.createIdentity();
+    })()))
+
+    it('should create i4 by i1->i4', async () => {
+      await i4.createIdentity(null, s2);
+      await i1.cert(i4, s2);
+    })
+
+    it('should accept i1 (already here) by i4->i1', async () => {
+      await i4.cert(i1);
+    })
+
+    it('should commit & make room for sandbox, and commit again', async () => {
+      await i1.join();
+      await i4.join();
+      (await s1.dal.idtyDAL.getSandboxRoom()).should.equal(0);
+      await s1.commit({ time: now });
+      (await s1.dal.idtyDAL.getSandboxRoom()).should.equal(3); // i2, i3 were removed for too old identities (based on virtual root block)
+      await i2.createIdentity();
+      await i3.createIdentity();
+      (await s1.dal.idtyDAL.getSandboxRoom()).should.equal(1);
+      await s1.commit({ time: now });
+      await s2.syncFrom(s1._server, 0, 1);
+      await s3.syncFrom(s1._server, 0, 1);
+    })
+
+    it('should create i5(1)', async () => {
+      await i5.createIdentity();
+      (await s1.dal.idtyDAL.getSandboxRoom()).should.equal(0);
+    })
 
     it('should reject i7(1)', () => shouldThrow(i7.createIdentity(true)));
 
-    it('should reject i7(1) by revocation', () => shouldThrow(co(function *() {
-      yield i7onS2.createIdentity(true);
-      const idty = yield i7onS2.lookup(i7onS2.pub);
-      yield i7.revoke(idty);
-    })));
-
-    it('should reject i1 -> i7 by revocation', () => shouldThrow(co(function *() {
-      yield i1.cert(i7, s2);
-    })));
-
-    it('should accept i7(1), i8(1), i9(1) by i1->i7(1), i1->i8(1), i1->i9(1)', () => co(function *() {
-      (yield s1.dal.idtyDAL.getSandboxRoom()).should.equal(0);
-      yield i8.createIdentity(null, s2);
-      yield i1.cert(i8, s2);
-      (yield s1.dal.idtyDAL.getSandboxRoom()).should.equal(0);
-      yield i9.createIdentity(null, s2);
-      yield i1.cert(i9, s2);
-      (yield s1.dal.idtyDAL.getSandboxRoom()).should.equal(0);
-    }));
-
-    it('should reject i10(1) by i1->i10(1)', () => shouldThrow(co(function *() {
-      (yield s1.dal.idtyDAL.getSandboxRoom()).should.equal(0);
-      yield i10.createIdentity(true, s2);
-      yield i1.cert(i10, s2);
-    })));
-
-    it('should accept i10(0) by i1->i10(0) because of an superior date compared to others in sandbox', () => co(function *() {
-      yield i10.createIdentity(null, s3);
-      yield i1.cert(i10, s3);
-    }));
-
-    it('should accept i11(0) and i12(0) for the same reason', () => co(function *() {
-      yield i11.createIdentity(null, s3);
-      yield i12.createIdentity(null, s3);
-    }));
-
-    it('should reject i13(0) because absolutely no more room is available', () => shouldThrow(co(function *() {
-      yield i13.createIdentity(true, s3);
-      yield i1.cert(i13, s3);
-    })));
-
-    it('should accept an identity with the same key as server, always', () => co(function *() {
-      (yield s3.dal.idtyDAL.getSandboxRoom()).should.equal(0);
-      yield i14.createIdentity(null, s3);
-    }));
-
-    it('should make room as identities get expired', () => co(function *() {
-      yield s1.commit({
+    it('should reject i7(1) by revocation', () => shouldThrow((async () => {
+      await i7onS2.createIdentity(true);
+      const idty = await i7onS2.lookup(i7onS2.pub);
+      await i7.revoke(idty);
+    })()))
+
+    it('should reject i1 -> i7 by revocation', () => shouldThrow((async () => {
+      await i1.cert(i7, s2);
+    })()))
+
+    it('should accept i7(1), i8(1), i9(1) by i1->i7(1), i1->i8(1), i1->i9(1)', async () => {
+      (await s1.dal.idtyDAL.getSandboxRoom()).should.equal(0);
+      await i8.createIdentity(null, s2);
+      await i1.cert(i8, s2);
+      (await s1.dal.idtyDAL.getSandboxRoom()).should.equal(0);
+      await i9.createIdentity(null, s2);
+      await i1.cert(i9, s2);
+      (await s1.dal.idtyDAL.getSandboxRoom()).should.equal(0);
+    })
+
+    it('should reject i10(1) by i1->i10(1)', () => shouldThrow((async () => {
+      (await s1.dal.idtyDAL.getSandboxRoom()).should.equal(0);
+      await i10.createIdentity(true, s2);
+      await i1.cert(i10, s2);
+    })()))
+
+    it('should accept i10(0) by i1->i10(0) because of an superior date compared to others in sandbox', async () => {
+      await i10.createIdentity(null, s3);
+      await i1.cert(i10, s3);
+    })
+
+    it('should accept i11(0) and i12(0) for the same reason', async () => {
+      await i11.createIdentity(null, s3);
+      await i12.createIdentity(null, s3);
+    })
+
+    it('should reject i13(0) because absolutely no more room is available', () => shouldThrow((async () => {
+      await i13.createIdentity(true, s3);
+      await i1.cert(i13, s3);
+    })()))
+
+    it('should accept an identity with the same key as server, always', async () => {
+      (await s3.dal.idtyDAL.getSandboxRoom()).should.equal(0);
+      await i14.createIdentity(null, s3);
+    })
+
+    it('should make room as identities get expired', async () => {
+      await s1.commit({
         time: now + 1000
       });
-      yield s1.commit({
+      await s1.commit({
         time: now + 1000
       });
-      yield s1.commit({
+      await s1.commit({
         time: now + 1000
       });
-      (yield s1.dal.idtyDAL.getSandboxRoom()).should.equal(3);
-    }));
-  });
+      (await s1.dal.idtyDAL.getSandboxRoom()).should.equal(3);
+    })
+  })
 
   describe('Certifications', () => {
 
@@ -207,34 +203,34 @@ describe("Sandboxes", function() {
       constants.SANDBOX_SIZE_CERTIFICATIONS = NEW_VALUE
     })
 
-    it('should accept i4->i7(0),i4->i8(0),i4->i9(0)', () => co(function *() {
-      yield i7.createIdentity();
-      yield i8.createIdentity();
-      yield i9.createIdentity();
-      (yield s1.dal.certDAL.getSandboxForKey('2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc').getSandboxRoom()).should.equal(3);
-      yield i4.cert(i7);
-      yield i4.cert(i8);
-      yield i4.cert(i9);
-      (yield s1.dal.certDAL.getSandboxForKey('2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc').getSandboxRoom()).should.equal(0);
-      (yield s1.dal.certDAL.getSandboxForKey('91dWdiyf7KaC4GAiKrwU7nGuue1vvmHqjCXbPziJFYtE').getSandboxRoom()).should.equal(3);
-    }));
-
-    it('should reject i4->i10(0)', () => shouldThrow(co(function *() {
-      (yield s1.dal.certDAL.getSandboxForKey('2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc').getSandboxRoom()).should.equal(0);
-      yield i4.cert(i10);
-    })));
-
-    it('should accept a certification from the same key as server, always', () => co(function *() {
-      (yield s1.dal.certDAL.getSandboxForKey('2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc').getSandboxRoom()).should.equal(0);
-      yield i1.cert(i8);
-    }));
-
-    it('should make room as certs get expired', () => co(function *() {
-      yield s1.commit({
+    it('should accept i4->i7(0),i4->i8(0),i4->i9(0)', async () => {
+      await i7.createIdentity();
+      await i8.createIdentity();
+      await i9.createIdentity();
+      (await s1.dal.certDAL.getSandboxForKey('2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc').getSandboxRoom()).should.equal(3);
+      await i4.cert(i7);
+      await i4.cert(i8);
+      await i4.cert(i9);
+      (await s1.dal.certDAL.getSandboxForKey('2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc').getSandboxRoom()).should.equal(0);
+      (await s1.dal.certDAL.getSandboxForKey('91dWdiyf7KaC4GAiKrwU7nGuue1vvmHqjCXbPziJFYtE').getSandboxRoom()).should.equal(3);
+    })
+
+    it('should reject i4->i10(0)', () => shouldThrow((async () => {
+      (await s1.dal.certDAL.getSandboxForKey('2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc').getSandboxRoom()).should.equal(0);
+      await i4.cert(i10);
+    })()))
+
+    it('should accept a certification from the same key as server, always', async () => {
+      (await s1.dal.certDAL.getSandboxForKey('2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc').getSandboxRoom()).should.equal(0);
+      await i1.cert(i8);
+    })
+
+    it('should make room as certs get expired', async () => {
+      await s1.commit({
         time: now + 1000
       });
-      (yield s1.dal.certDAL.getSandboxForKey('2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc').getSandboxRoom()).should.equal(3);
-    }));
+      (await s1.dal.certDAL.getSandboxForKey('2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc').getSandboxRoom()).should.equal(3);
+    })
 
     after(() => {
       constants.SANDBOX_SIZE_CERTIFICATIONS = OLD_VALUE
@@ -243,31 +239,31 @@ describe("Sandboxes", function() {
 
   describe('Memberships', () => {
 
-    it('should accept i8,i9', () => co(function *() {
-      yield i8.createIdentity(); // Identities have changed
-      yield i9.createIdentity();
-      (yield s1.dal.msDAL.getSandboxRoom()).should.equal(2);
-      yield i8.join();
-      yield i9.join();
-      (yield s1.dal.msDAL.getSandboxRoom()).should.equal(0);
-    }));
-
-    it('should reject i7', () => shouldThrow(co(function *() {
-      (yield s1.dal.msDAL.getSandboxRoom()).should.equal(0);
-      yield i7.join();
-    })));
-
-    it('should accept a membership from the same key as server, always', () => co(function *() {
-      (yield s1.dal.msDAL.getSandboxRoom()).should.equal(0);
-      yield i1.join();
-    }));
-
-    it('should make room as membership get expired', () => co(function *() {
-      yield s1.commit({
+    it('should accept i8,i9', async () => {
+      await i8.createIdentity(); // Identities have changed
+      await i9.createIdentity();
+      (await s1.dal.msDAL.getSandboxRoom()).should.equal(2);
+      await i8.join();
+      await i9.join();
+      (await s1.dal.msDAL.getSandboxRoom()).should.equal(0);
+    })
+
+    it('should reject i7', () => shouldThrow((async () => {
+      (await s1.dal.msDAL.getSandboxRoom()).should.equal(0);
+      await i7.join();
+    })()))
+
+    it('should accept a membership from the same key as server, always', async () => {
+      (await s1.dal.msDAL.getSandboxRoom()).should.equal(0);
+      await i1.join();
+    })
+
+    it('should make room as membership get expired', async () => {
+      await s1.commit({
         time: now + 1000
       });
-      (yield s1.dal.msDAL.getSandboxRoom()).should.equal(2);
-    }));
+      (await s1.dal.msDAL.getSandboxRoom()).should.equal(2);
+    })
   });
 
   describe('Transaction', () => {
@@ -278,29 +274,29 @@ describe("Sandboxes", function() {
       CommonConstants.TRANSACTION_MAX_TRIES = 2;
     })
 
-    it('should accept 2 transactions of 20, 30 units', () => co(function *() {
-      yield i4.send(20, i1);
-      yield i4.send(30, i1);
-      (yield s1.dal.txsDAL.getSandboxRoom()).should.equal(0);
-    }));
+    it('should accept 2 transactions of 20, 30 units', async () => {
+      await i4.sendMoney(20, i1);
+      await i4.sendMoney(30, i1);
+      (await s1.dal.txsDAL.getSandboxRoom()).should.equal(0);
+    })
 
-    it('should reject amount of 10', () => shouldThrow(co(function *() {
-      yield i4.send(10, i1);
-    })));
+    it('should reject amount of 10', () => shouldThrow((async () => {
+      await i4.sendMoney(10, i1);
+    })()))
 
-    it('should accept a transaction from the same key as server, always', () => co(function *() {
-      yield i1.send(10, i4);
-    }));
+    it('should accept a transaction from the same key as server, always', async () => {
+      await i1.sendMoney(10, i4);
+    })
 
-    it('should make room as transactions get commited', () => co(function *() {
-      yield s1.commit();
-      yield s1.commit();
-      (yield s1.dal.txsDAL.getSandboxRoom()).should.equal(2);
+    it('should make room as transactions get commited', async () => {
+      await s1.commit();
+      await s1.commit();
+      (await s1.dal.txsDAL.getSandboxRoom()).should.equal(2);
       CommonConstants.TRANSACTION_MAX_TRIES = tmp;
-    }));
-  });
-});
+    })
+  })
+})
 
-function shouldThrow(promise) {
+function shouldThrow<T>(promise:Promise<T>) {
   return promise.should.be.rejected();
 }
diff --git a/test/integration/scenarios/hello-plugin.js b/test/integration/scenarios/hello-plugin.js
index 2c0dcf2571397d3b890151130ac1963ea6a68f7c..c5b98105235fd1dbd6b2e106b8ce9467b49f6448 100644
--- a/test/integration/scenarios/hello-plugin.js
+++ b/test/integration/scenarios/hello-plugin.js
@@ -13,19 +13,17 @@
 
 "use strict"
 
-const co = require('co')
-
 module.exports = {
   duniter: {
     cli: [{
       name: 'hello-world',
       desc: 'Says hello from \`duniter\` command.',
       logs: false,
-      onDatabaseExecute: (server, conf, program, params) => co(function*() {
+      onDatabaseExecute: async (server, conf, program, params) => {
         const msg = 'Hello world! from within Duniter.'
         console.log(msg)
         return msg
-      })
+      }
     }]
   }
 }
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/sources_property.js b/test/integration/sources/sources-property.ts
similarity index 70%
rename from test/integration/sources_property.js
rename to test/integration/sources/sources-property.ts
index 89467dc86cb71f98c81b8b9b88288fad89bafddc..eab71ca03a0ff8611ebadc10c664d03c0cb8e206 100644
--- a/test/integration/sources_property.js
+++ b/test/integration/sources/sources-property.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 {HttpBlock, HttpSources} from "../../../app/modules/bma/lib/dtos"
 
-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("Sources property", function() {
 
-  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,17 +46,17 @@ describe("Sources property", 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:HttpBlock) => {
     should.exists(block);
     assert.equal(block.number, 1);
     assert.equal(block.dividend, 200);
   }));
 
-  it('it should exist sources for HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', () => s1.expect('/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', (res) => {
+  it('it should exist sources for HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', () => s1.expect('/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', (res:HttpSources) => {
     assert.equal(res.sources.length, 1)
   }));
 
-  it('it should NOT exist sources if we change one letter to uppercased version', () => s1.expect('/tx/sources/HGTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', (res) => {
+  it('it should NOT exist sources if we change one letter to uppercased version', () => s1.expect('/tx/sources/HGTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', (res:HttpSources) => {
     assert.equal(res.sources.length, 0)
   }));
 });
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/tests.js b/test/integration/tests.js
deleted file mode 100644
index 3632bfefb5776f5ecb6c96de65427e7c3c80e5d7..0000000000000000000000000000000000000000
--- a/test/integration/tests.js
+++ /dev/null
@@ -1,314 +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 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 rp        = require('request-promise');
-
-const expectAnswer   = httpTest.expectAnswer;
-const MEMORY_MODE = true;
-
-require('../../app/modules/bma').BmaDependency.duniter.methods.noLimit(); // Disables the HTTP limiter
-
-describe("Integration", function() {
-
-  describe("Node 1", function() {
-
-    const node1 = node('db1', { upnp: false, currency: 'bb', ipv4: 'localhost', port: 9999, remoteipv4: 'localhost', remoteport: 9999, httplogs: false,
-      rootoffset: 0,
-      sigQty: 1,
-      pair: {
-        pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
-        sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
-      }
-    });
-
-    const cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, node1);
-    const tac = new TestUser('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, node1);
-    const tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, node1);
-    const toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, node1);
-
-    before(function(done) {
-      node1.startTesting()
-        .then(function(){
-          node1.before([])(done);
-        });
-    });
-
-    describe("Testing technical API", function(){
-
-      before(function(done) {
-        node1.before([])(done);
-      });
-      after(node1.after());
-
-      it('/node/summary should give package.json version', node1.summary(function(summary, done){
-        should.exists(summary);
-        should.exists(summary.duniter);
-        should.exists(summary.duniter.software);
-        should.exists(summary.duniter.version);
-        assert.equal(summary.duniter.software, "duniter");
-        assert.equal(summary.duniter.version, jspckg.version);
-        done();
-      }));
-    });
-
-    describe("Testing malformed documents", function(){
-
-      before(function(done) {
-        node1.before(require('./scenarios/malformed-documents')(node1))(done);
-      });
-      after(node1.after());
-
-      it('should not have crashed because of wrong tx', function(){
-        assert.equal(true, true);
-      });
-    });
-
-    describe("Lookup on", function(){
-
-      before(function() {
-        return co(function *() {
-
-          // Self certifications
-          yield cat.createIdentity();
-          yield tac.createIdentity();
-          yield tic.createIdentity();
-          yield toc.createIdentity();
-          // Certifications
-          yield cat.cert(tac);
-        });
-      });
-      after(node1.after());
-
-      describe("identities collisions", () => {
-
-        it("sending same identity should fail", () => co(function *() {
-
-          // We send again the same
-          try {
-            yield 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 *() {
-
-          // We send again the same
-          try {
-            yield 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){
-          should.exists(res);
-          assert.equal(res.results.length, 1);
-          done();
-        }));
-
-        it('should have sent 1 signature', node1.lookup('cat', function(res, done){
-          should.exists(res);
-          assert.equal(res.results[0].signed.length, 1);
-          should.exists(res.results[0].signed[0].isMember);
-          should.exists(res.results[0].signed[0].wasMember);
-          assert.equal(res.results[0].signed[0].isMember, false);
-          assert.equal(res.results[0].signed[0].wasMember, false);
-          done();
-        }));
-      });
-
-      describe("user tac", function(){
-
-        it('should give only 1 result', node1.lookup('tac', function(res, done){
-          should.exists(res);
-          assert.equal(res.results.length, 1);
-          done();
-        }));
-
-        it('should have 1 signature', node1.lookup('tac', function(res, done){
-          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){
-          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){
-        should.exists(res);
-        assert.equal(res.results.length, 1);
-        done();
-      }));
-
-      it('tic should give only 1 result', node1.lookup('tic', function(res, done){
-        should.exists(res);
-        assert.equal(res.results.length, 1);
-        done();
-      }));
-    });
-  });
-
-  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'
-          }
-        });
-
-        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 });
-
-        yield node3.initWithDAL().then(bma).then((bmapi) => bmapi.openConnections());
-        const now = 1482220000;
-
-        // 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
-        });
-      });
-    });
-
-    after(() => {
-      return Promise.all([
-        shutDownEngine(node3)
-      ])
-    })
-
-    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) {
-      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) {
-      should.exists(res);
-      const uids = _.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'});
-      assert.equal(cat_signed.uid, "cat");
-      assert.equal(cat_signed.isMember, true);
-      assert.equal(cat_signed.wasMember, true);
-      assert.equal(tac_signed.uid, "tac");
-      assert.equal(tac_signed.isMember, true);
-      assert.equal(tac_signed.wasMember, true);
-      assert.equal(toc_signed.uid, "toc");
-      assert.equal(toc_signed.isMember, true);
-      assert.equal(toc_signed.wasMember, true);
-      assert.equal(res.results[0].uids[0].others.length, 3);
-      assert.equal(res.results[0].uids[0].others[0].uids.length, 1);
-      assert.equal(res.results[0].uids[0].others[0].isMember, true);
-      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) {
-      should.exists(block);
-      assert.equal(block.number, 2);
-      assert.equal(block.membersCount, 4);
-    }));
-
-    blockShouldHaveCerts(0, 8);
-    blockShouldHaveCerts(1, 0);
-    blockShouldHaveCerts(2, 0);
-    blockShouldHaveCerts(3, 1);
-    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) {
-        should.exists(block);
-        assert.equal(block.number, number);
-        assert.equal(block.certifications.length, certificationsCount);
-      }));
-    }
-  });
-});
diff --git a/test/integration/tools/TestUser.ts b/test/integration/tools/TestUser.ts
index edf7b8764d5dd0cd1b7538557e6bf1f0bdc4b126..ddd6e515a24eb91ac9807fe9c4584c7abbecc9d4 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
@@ -63,7 +64,7 @@ export class TestUser {
     }
   }
 
-  public async createIdentity(useRoot?:boolean, fromServer?:any) {
+  public async createIdentity(useRoot?:boolean|null, fromServer?:any) {
     if (!this.pub) {
       this.init(() => {})
     }
@@ -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,19 +184,6 @@ export class TestUser {
     })
   }
 
-  public send(amount:number, recipient:string, comment?:string) {
-    const that = this
-    return async function(done:(e?:any)=>void) {
-      try {
-        let raw = await that.prepareITX(amount, recipient, comment)
-        await that.sendTX(raw)
-        done()
-      } catch (e) {
-        done(e)
-      }
-    };
-  };
-
   public async sendMoney(amount:number, recipient:TestUser, comment?:string) {
     const raw = await this.prepareITX(amount, recipient, comment)
     await this.sendTX(raw)
@@ -351,7 +339,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,17 +388,8 @@ 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) {
-    return new Promise((res, rej) => {
-      this.send(amount, userid, comment)((err) => {
-        if (err) return rej(err)
-        res()
-      })
-    })
-  }
 }
diff --git a/test/integration/tools/commit.js b/test/integration/tools/commit.js
deleted file mode 100644
index bb5804a8ed22526cd12426261b7eb3cd94fe39a7..0000000000000000000000000000000000000000
--- a/test/integration/tools/commit.js
+++ /dev/null
@@ -1,69 +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";
-
-var _  = require('underscore');
-var co = require('co');
-var rp = require('request-promise');
-var logger = require('../../../app/lib/logger').NewLogger('test');
-const until = require('./until')
-const BlockProver = require('../../../app/modules/prover/lib/blockProver').BlockProver
-
-module.exports = function makeBlockAndPost(theServer, extraProps, noWait) {
-  return function(manualValues) {
-    if (extraProps) {
-      manualValues = manualValues || {};
-      manualValues = _.extend(manualValues, extraProps);
-    }
-    return co(function *() {
-      if (!theServer._utProver) {
-        theServer._utProver = new BlockProver(theServer)
-        theServer._utGenerator = require('../../../app/modules/prover').ProverDependency.duniter.methods.blockGenerator(theServer, theServer._utProver)
-      }
-      let proven = yield theServer._utGenerator.makeNextBlock(null, null, manualValues)
-      const numberToReach = proven.number
-      const block = yield postBlock(theServer)(proven)
-      yield new Promise((res) => {
-        if (noWait) {
-          return res(block)
-        }
-        const interval = setInterval(() => co(function*() {
-          const current = yield theServer.dal.getCurrentBlockOrNull()
-          if (current && current.number == numberToReach) {
-            res()
-            clearInterval(interval)
-          }
-        }), 1)
-      })
-      return block
-    });
-  };
-};
-
-function postBlock(server) {
-  return function(block) {
-    logger.trace(block.getRawSigned());
-    return post(server, '/blockchain/block')({
-      block: typeof block == 'string' ? block : block.getRawSigned()
-    });
-  };
-}
-
-function post(server, uri) {
-  return function(data) {
-    return rp.post('http://' + [server.conf.ipv4, server.conf.port].join(':') + uri, {
-      form: data
-    });
-  };
-}
diff --git a/test/integration/tools/http-expect.ts b/test/integration/tools/http-expect.ts
new file mode 100644
index 0000000000000000000000000000000000000000..19053cfbfea5f752d6f236e12bfbae503ab43681
--- /dev/null
+++ b/test/integration/tools/http-expect.ts
@@ -0,0 +1,83 @@
+// 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 {Underscore} from "../../../app/lib/common-libs/underscore"
+
+const should    = require('should');
+const assert    = require('assert');
+
+export async function expectHttpCode(code:number, message:any, promise?:any) {
+  if (arguments.length == 2) {
+    promise = arguments[1];
+    message = undefined;
+  }
+  try {
+    const res = await promise;
+    assert.equal(res.statusCode, code);
+  } catch (err) {
+    if (err.response) {
+      assert.equal(err.response.statusCode, code);
+      if (message) {
+        assert.equal(err.error || err.cause, message);
+      }
+    }
+    else throw err;
+  }
+}
+
+export async function expectError(code:number, message:any, promise?:any) {
+  if (arguments.length == 2) {
+    promise = arguments[1];
+    message = undefined;
+  }
+  try {
+    const res = await promise;
+    assert.equal(res.statusCode, code);
+  } catch (err) {
+    if (err.response) {
+      assert.equal(err.response.statusCode, code);
+      if (message) {
+        let errorObj = typeof err.error == "string" ? JSON.parse(err.error) : err.error;
+        assert.equal(errorObj.message, message);
+      }
+    }
+    else throw err;
+  }
+}
+
+export 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;
+  }
+}
+
+export async function expectAnswer<T>(promise:Promise<T>, testFunc:any) {
+  try {
+    const res = await promise;
+    return testFunc(res);
+  } catch (err) {
+    if (err.response) {
+      console.error(err.error);
+      assert.equal(err.response.statusCode, 200);
+    }
+    else throw err;
+  }
+}
diff --git a/test/integration/tools/http.js b/test/integration/tools/http.js
deleted file mode 100644
index fcc25dada6ab8e319eefd483d52ef0e2e1885b34..0000000000000000000000000000000000000000
--- a/test/integration/tools/http.js
+++ /dev/null
@@ -1,96 +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 assert    = require('assert');
-const _         = require('underscore');
-
-module.exports = {
-
-  expectHttpCode: function expectHttpCode(code, message, promise) {
-    if (arguments.length == 2) {
-      promise = arguments[1];
-      message = undefined;
-    }
-    return co(function*(){
-      try {
-        const res = yield promise;
-        assert.equal(res.statusCode, code);
-      } catch (err) {
-        if (err.response) {
-          assert.equal(err.response.statusCode, code);
-          if (message) {
-            assert.equal(err.error || err.cause, message);
-          }
-        }
-        else throw err;
-      }
-    });
-  },
-
-  expectError: function expectHttpCode(code, message, promise) {
-    if (arguments.length == 2) {
-      promise = arguments[1];
-      message = undefined;
-    }
-    return co(function*(){
-      try {
-        const res = yield promise;
-        assert.equal(res.statusCode, code);
-      } catch (err) {
-        if (err.response) {
-          assert.equal(err.response.statusCode, code);
-          if (message) {
-            let errorObj = typeof err.error == "string" ? JSON.parse(err.error) : err.error;
-            assert.equal(errorObj.message, message);
-          }
-        }
-        else throw err;
-      }
-    });
-  },
-
-  expectJSON: 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;
-      }
-    });
-  },
-
-  expectAnswer: function expectJSON(promise, testFunc) {
-    return co(function*(){
-      try {
-        const res = yield promise;
-        return testFunc(res);
-      } catch (err) {
-        if (err.response) {
-          console.error(err.error);
-          assert.equal(err.response.statusCode, 200);
-        }
-        else throw err;
-      }
-    });
-  }
-};
diff --git a/test/integration/tools/node.js b/test/integration/tools/node.js
deleted file mode 100644
index 57f696cd56ca7cc981e65d6eaf90ace83005d14c..0000000000000000000000000000000000000000
--- a/test/integration/tools/node.js
+++ /dev/null
@@ -1,335 +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";
-var co = require('co');
-var _ = require('underscore');
-var async  = require('async');
-var request  = require('request');
-var contacter = require('../../../app/modules/crawler').CrawlerDependency.duniter.methods.contacter;
-var duniter  = require('../../../index');
-var multicaster = require('../../../app/lib/streams/multicaster');
-var ConfDTO = require('../../../app/lib/dto/ConfDTO').ConfDTO
-var PeerDTO   = require('../../../app/lib/dto/PeerDTO').PeerDTO
-var http   = require('./http');
-const bma = require('../../../app/modules/bma').BmaDependency.duniter.methods.bma;
-
-module.exports = function (dbName, options) {
-  return new Node(dbName, options);
-};
-
-module.exports.statics = {
-};
-
-var UNTIL_TIMEOUT = 20000;
-
-function Node (dbName, options) {
-
-  var logger = require('../../../app/lib/logger').NewLogger(dbName);
-  var that = this;
-  var started = false;
-  that.server = null;
-  that.http = null;
-
-  /**
-   * To be executed before tests
-   * @param scenarios Scenarios to execute: a suite of operations over a node (identities, certs, tx, blocks, ...).
-   * @returns {Function} Callback executed by unit test framework.
-   */
-  this.before = function (scenarios) {
-    return function(done) {
-      async.waterfall([
-        function (next) {
-          that.http = contacter(options.remoteipv4, options.remoteport);
-          that.executes(scenarios, next);
-        }
-      ], done);
-    };
-  };
-
-  this.executes = function (scenarios, done) {
-    async.waterfall([
-      function(next) {
-        async.forEachSeries(scenarios, function(useCase, callback) {
-          useCase(callback);
-        }, next);
-      }
-    ], done);
-  };
-
-  /**
-   * To be exectued after unit tests. Here: clean the database (removal)
-   * @returns {Function} Callback executed by unit test framework.
-   */
-  this.after = function () {
-    return function (done) {
-      done();
-    };
-  };
-
-  /**
-   * Generates next block and submit it to local node.
-   * @returns {Function}
-   */
-  this.commit = function(params) {
-    return function(done) {
-      async.waterfall([
-        function(next) {
-          async.parallel({
-            block: function(callback){
-              co(function *() {
-                try {
-                  const block2 = yield require('../../../app/modules/prover').ProverDependency.duniter.methods.generateTheNextBlock(that.server, params);
-                  const trial2 = yield that.server.getBcContext().getIssuerPersonalizedDifficulty(that.server.keyPair.publicKey);
-                  const block = yield require('../../../app/modules/prover').ProverDependency.duniter.methods.generateAndProveTheNext(that.server, block2, trial2, params);
-                  callback(null, block);
-                } catch (e) {
-                  callback(e);
-                }
-              });
-            }
-          }, next);
-        },
-        function(res, next) {
-          var block = res.block;
-          logger.debug(block.getRawSigned());
-          post('/blockchain/block', {
-            "block": block.getRawSigned()
-          }, next);
-        }
-      ], function(err, res) {
-        done(err, res.body);
-      });
-    };
-  };
-
-  function post(uri, data, done) {
-    return new Promise((resolve, reject) => {
-      var postReq = request.post({
-        "uri": 'http://' + [that.server.conf.remoteipv4, that.server.conf.remoteport].join(':') + uri,
-        "timeout": 1000 * 10,
-        "json": true
-      }, function (err, res, body) {
-        if (err) {
-          reject(err)
-          done && done(err)
-        } else {
-          resolve(res, body)
-          done && done(err, res, body)
-        }
-      });
-      postReq.form(data);
-    })
-  }
-
-  this.startTesting = function(done) {
-    return new Promise(function(resolve, reject){
-      if (started) return done();
-      async.waterfall([
-        function(next) {
-          service(next)();
-        },
-        function (server, next){
-          // Launching server
-          that.server = server;
-          started = true;
-          server.PeeringService.generateSelfPeer(server.conf, 0)
-            .then(() => next())
-            .catch(next)
-        },
-        function (next) {
-          that.http = contacter(options.remoteipv4, options.remoteport);
-          next();
-        }
-      ], function(err) {
-        err ? reject(err) : resolve();
-        done && done(err);
-      });
-    });
-  };
-
-  function service(callback) {
-    return function () {
-      const stack = duniter.statics.simpleStack();
-      stack.registerDependency({
-        duniter: {
-          config: {
-            onLoading: (conf, program) => co(function*() {
-              const overConf = ConfDTO.complete(options);
-              _.extend(conf, overConf);
-            })
-          },
-          service: {
-            process: (server) => _.extend(server, {
-              startService: () => {
-                logger.debug('Server Servie Started!');
-              }
-            })
-          },
-          cli: [{
-            name: 'execute',
-            desc: 'Unit Test execution',
-            onDatabaseExecute: (server, conf, program, params, startServices) => co(function*() {
-              yield startServices();
-              callback(null, server);
-              yield Promise.resolve((res) => null); // Never ending
-            })
-          }]
-        }
-      }, 'duniter-automated-test');
-      options.port = options.port || 10901;
-      options.ipv4 = options.ipv4 || "127.0.0.1";
-      options.ipv6 = options.ipv6 || null;
-      options.remotehost = options.remotehost || null;
-      options.remoteipv4 = options.remoteipv4 || null;
-      options.remoteipv6 = options.remoteipv6 || null;
-      options.remoteport = options.remoteport || 10901;
-      const cliOptions = ['--ws2p-noupnp']
-      if (options.port) {
-        cliOptions.push('--port')
-        cliOptions.push(options.port)
-      }
-      if (options.ipv4) {
-        cliOptions.push('--ipv4')
-        cliOptions.push(options.ipv4)
-      }
-      if (options.ipv6) {
-        cliOptions.push('--ipv6')
-        cliOptions.push(options.ipv6)
-      }
-      if (options.remotehost) {
-        cliOptions.push('--remoteh')
-        cliOptions.push(options.remotehost)
-      }
-      if (options.remoteipv4) {
-        cliOptions.push('--remote4')
-        cliOptions.push(options.remoteipv4)
-      }
-      if (options.remoteipv6) {
-        cliOptions.push('--remote6')
-        cliOptions.push(options.remoteipv6)
-      }
-      if (options.remoteport) {
-        cliOptions.push('--remotep')
-        cliOptions.push(options.remoteport)
-      }
-
-      stack.registerDependency(require('../../../app/modules/keypair').KeypairDependency, 'duniter-keypair')
-      stack.registerDependency(require('../../../app/modules/bma').BmaDependency,         'duniter-bma')
-      stack.executeStack(['', '', '--mdb', dbName, '--memory', 'execute'].concat(cliOptions));
-    };
-  }
-
-  /************************
-   *    TEST UTILITIES
-   ************************/
-
-  this.lookup = function(search, callback) {
-    return function(done) {
-      co(function*(){
-        try {
-          const res = yield that.http.getLookup(search);
-          callback(res, done);
-        } catch (err) {
-          logger.error(err);
-          callback(null, done);
-        }
-      });
-    };
-  };
-
-  this.until = function (eventName, count) {
-    var counted = 0;
-    var max = count == undefined ? 1 : count;
-    return new Promise(function (resolve, reject) {
-      var finished = false;
-      that.server.on(eventName, function () {
-        counted++;
-        if (counted == max) {
-          if (!finished) {
-            finished = true;
-            resolve();
-          }
-        }
-      });
-      setTimeout(function() {
-        if (!finished) {
-          finished = true;
-          reject('Received ' + counted + '/' + count + ' ' + eventName + ' after ' + UNTIL_TIMEOUT + ' ms');
-        }
-      }, UNTIL_TIMEOUT);
-    });
-  };
-
-  this.block = function(number, callback) {
-    return function(done) {
-      co(function*(){
-        try {
-          const res = yield that.http.getBlock(number);
-          callback(res, done);
-        } catch (err) {
-          logger.error(err);
-          callback(null, done);
-        }
-      });
-    };
-  };
-
-  this.summary = function(callback) {
-    return function(done) {
-      co(function*(){
-        try {
-          const res = yield that.http.getSummary();
-          callback(res, done);
-        } catch (err) {
-          logger.error(err);
-          callback(null, done);
-        }
-      });
-    };
-  };
-
-  this.peering = function(done) {
-    co(function*(){
-      try {
-        const res = yield that.http.getPeer();
-        done(null, res);
-      } catch (err) {
-        logger.error(err);
-        done(err);
-      }
-    });
-  };
-
-  this.peeringP = () => that.http.getPeer();
-
-  this.submitPeer = function(peer, done) {
-    return post('/network/peering/peers', {
-      "peer": PeerDTO.fromJSONObject(peer).getRawSigned()
-    }, done);
-  };
-
-  this.submitPeerP = (peer) => new Promise((res, rej) => {
-    that.submitPeer(peer, (err, data) => {
-      if (err) return rej(err)
-      res(data)
-    })
-  })
-
-  this.commitP = (params) => new Promise((res, rej) => {
-    this.commit(params)((err, data) => {
-      if (err) return rej(err)
-      res(data)
-    })
-  })
-}
diff --git a/app/lib/blockchain/interfaces/IndexOperator.ts b/test/integration/tools/shutdown-engine.ts
similarity index 63%
rename from app/lib/blockchain/interfaces/IndexOperator.ts
rename to test/integration/tools/shutdown-engine.ts
index 57b475d630fa753a04713bd904b7d29b89bc8951..b58c37666761b1ab8f2cad94360f5c02f6224585 100644
--- a/app/lib/blockchain/interfaces/IndexOperator.ts
+++ b/test/integration/tools/shutdown-engine.ts
@@ -11,19 +11,11 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict"
+import {TestingServer} from "./toolbox"
 
-export interface IndexOperator {
-
-  initIndexer(pkFields: any): Promise<void>,
-
-  getSubIndexes(): Promise<string[]>,
-
-  findWhere(subIndex: string, criterias: {}): Promise<any[]>,
-
-  findTrimable(subIndex: string, numberField: string, maxNumber: number): Promise<any[]>,
-
-  removeWhere(subIndex: string, criterias: {}): Promise<void>,
-
-  recordIndex(index: any): Promise<void>
+export async function shutDownEngine(server:TestingServer) {
+  if ((server as any)._utProver) {
+    const farm = await (server as any)._utProver.getWorker()
+    return farm.shutDownEngine()
+  }
 }
diff --git a/test/integration/tools/test-framework.ts b/test/integration/tools/test-framework.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0f691805f034bb3e849c865330862ed081e9b665
--- /dev/null
+++ b/test/integration/tools/test-framework.ts
@@ -0,0 +1,39 @@
+import {catUser, NewTestingServer, tacUser, TestingServer} from "./toolbox"
+import {TestUser} from "./TestUser"
+import * as assert from 'assert'
+
+export function writeBasicTestWith2Users(writeTests: (test: (testTitle: string, fn: (server: TestingServer, cat: TestUser, tac: TestUser) => Promise<void>) => void) => void) {
+
+  let s1:TestingServer, cat:TestUser, tac:TestUser
+
+  before(async () => {
+    s1 = NewTestingServer({
+      medianTimeBlocks: 1,
+      pair: {
+        pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
+        sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
+      }
+    })
+    cat = catUser(s1)
+    tac = tacUser(s1)
+    await s1.prepareForNetwork()
+  })
+
+  writeTests((title, cb: (server: TestingServer, cat: TestUser, tac: TestUser) => Promise<void>) => {
+    it(title, async () => {
+      await cb(s1, cat, tac)
+    })
+  })
+}
+
+export function assertEqual(value: number, expected: number) {
+  assert.equal(value, expected)
+}
+
+export function assertTrue(expected: boolean) {
+  assert.equal(true, expected)
+}
+
+export function assertFalse(expected: boolean) {
+  assert.equal(false, expected)
+}
\ No newline at end of file
diff --git a/test/integration/tools/sync.js b/test/integration/tools/test-sync.ts
similarity index 63%
rename from test/integration/tools/sync.js
rename to test/integration/tools/test-sync.ts
index b453100665f011266382cd45bf2b33c1bd3192ed..5a3d13b744e800ffec99224ed0d85f7b5a08e372 100644
--- a/test/integration/tools/sync.js
+++ b/test/integration/tools/test-sync.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 {Server} from "../../../server"
 
-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) {
+export function sync(fromBlock:number, toBlock:number, fromServer:Server, toServer:Server) {
   // Sync blocks
-  return _.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)
-  }), Promise.resolve());
-};
+  return Underscore.range(fromBlock, toBlock + 1).reduce(async (p:Promise<any>, number:number) => {
+    await p;
+    const json = await rp('http://' + fromServer.conf.ipv4 + ':' + fromServer.conf.port + '/blockchain/block/' + number, { json: true });
+    await toServer.writeBlock(json)
+  }, Promise.resolve())
+}
diff --git a/test/integration/tools/until.js b/test/integration/tools/test-until.ts
similarity index 79%
rename from test/integration/tools/until.js
rename to test/integration/tools/test-until.ts
index 3d45be8f4540d6990279c009938c6b9f05084215..4c05899eab0e5f7599930e6489edf6d440059642 100644
--- a/test/integration/tools/until.js
+++ b/test/integration/tools/test-until.ts
@@ -11,16 +11,16 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-"use strict";
+import {TestingServer} from "./toolbox"
 
-var UNTIL_TIMEOUT = 115000;
+const UNTIL_TIMEOUT = 115000;
 
-module.exports = function (server, eventName, count) {
-  var counted = 0;
-  var max = count == undefined ? 1 : count;
+export function until(server:TestingServer, eventName:string, count:number) {
+  let counted = 0;
+  const max = count == undefined ? 1 : count;
   return new Promise(function (resolve, reject) {
-    var finished = false;
-    server.on(eventName, function () {
+    let finished = false;
+    server._server.on(eventName, function () {
       counted++;
       if (counted == max) {
         if (!finished) {
@@ -36,4 +36,4 @@ module.exports = function (server, eventName, count) {
       }
     }, UNTIL_TIMEOUT);
   });
-};
+}
diff --git a/test/integration/tools/toolbox.ts b/test/integration/tools/toolbox.ts
index d9261a036fc2195f5dce2a73b890efe56dfdca71..677c3b2a86ee976c3ca8406f5613c3d73be95f74 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"
@@ -37,18 +37,24 @@ import {WS2PServer} from "../../../app/modules/ws2p/lib/WS2PServer"
 import {WS2PServerMessageHandler} from "../../../app/modules/ws2p/lib/interface/WS2PServerMessageHandler"
 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 {DBBlock} from "../../../app/lib/db/DBBlock"
+import {DBPeer} from "../../../app/lib/db/DBPeer"
+import {Underscore} from "../../../app/lib/common-libs/underscore"
+import {BmaDependency} from "../../../app/modules/bma/index"
+import {NewLogger} from "../../../app/lib/logger"
+import {BlockProver} from "../../../app/modules/prover/lib/blockProver"
+import {DataErrors} from "../../../app/lib/common-libs/errors"
+import {until} from "./test-until"
+import {sync} from "./test-sync"
+import {expectAnswer, expectError, expectJSON} from "./http-expect"
+import {WebSocketServer} from "../../../app/lib/common-libs/websocket"
 
 const assert      = require('assert');
-const _           = require('underscore');
 const rp          = require('request-promise');
 const es          = require('event-stream');
-const WebSocketServer = require('ws').Server
-const httpTest    = require('../tools/http');
-const sync        = require('../tools/sync');
-const commit      = require('../tools/commit');
-const until       = require('../tools/until');
-const bma         = require('../../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const logger      = require('../../../app/lib/logger').NewLogger('toolbox');
+const logger      = NewLogger();
 
 require('../../../app/modules/bma').BmaDependency.duniter.methods.noLimit(); // Disables the HTTP limiter
 
@@ -61,30 +67,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 });
 }
@@ -93,8 +75,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 });
@@ -125,7 +107,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 });
@@ -147,7 +129,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 });
@@ -258,7 +240,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)
 }
@@ -331,13 +313,15 @@ export const waitForHeads = async (server:Server, nbHeads:number) => {
 export class TestingServer {
 
   private prover:Prover
-  private permaProver:PermanentProver
-  private bma:any
+  public permaProver:PermanentProver
+  public bma:BmaApi
 
   constructor(
     private port:number,
     private server:Server) {
 
+    ProverDependency.duniter.methods.hookServer(server)
+
     server.addEndpointsDefinitions(async () => {
       return require('../../../app/modules/bma').BmaDependency.duniter.methods.getMainEndpoint(server.conf)
     })
@@ -371,7 +355,11 @@ export class TestingServer {
     return this.server.home
   }
 
-  revert() {
+  initWithDAL() {
+    return this.server.initWithDAL()
+  }
+
+  revert(): Promise<DBBlock> {
     return this.server.revert()
   }
 
@@ -383,7 +371,7 @@ export class TestingServer {
     return this.server.on(event, f)
   }
 
-  recomputeSelfPeer() {
+  recomputeSelfPeer(): Promise<DBPeer | null> {
     return this.server.recomputeSelfPeer()
   }
 
@@ -445,7 +433,7 @@ export class TestingServer {
 
   async initDalBmaConnections() {
     await this.server.initWithDAL()
-    const bmapi = await bma(this.server)
+    const bmapi = await BmaDependency.duniter.methods.bma(this.server)
     this.bma = bmapi
     const res = await bmapi.openConnections()
     return res
@@ -465,34 +453,61 @@ export class TestingServer {
 
 
   expect(uri:string, expectations:any) {
-    return typeof expectations == 'function' ? httpTest.expectAnswer(rp(this.url(uri), { json: true }), expectations) : httpTest.expectJSON(rp(this.url(uri), { json: true }), expectations);
+    return typeof expectations == 'function' ? expectAnswer(rp(this.url(uri), { json: true }), expectations) : expectJSON(rp(this.url(uri), { json: true }), expectations);
   }
 
   expectThat(uri:string, expectations:any) {
-    return httpTest.expectAnswer(rp(this.url(uri), { json: true }), expectations);
+    return expectAnswer(rp(this.url(uri), { json: true }), expectations);
   }
 
   expectJSON(uri:string, expectations:any) {
-    return httpTest.expectJSON(rp(this.url(uri), { json: true }), expectations);
+    return expectJSON(rp(this.url(uri), { json: true }), expectations);
   }
 
-  expectError(uri:string, code:number, message:string) {
-    return httpTest.expectError(code, message, rp(this.url(uri), { json: true }));
+  expectError(uri:string, code:number, message = '') {
+    return expectError(code, message, rp(this.url(uri), { json: true }));
   }
 
-
   syncFrom(otherServer:Server, fromIncuded:number, toIncluded:number) {
     return sync(fromIncuded, toIncluded, otherServer, this.server);
   }
 
-
   until(type:string, count:number) {
-    return until(this.server, type, count);
+    return until(this, type, count);
   }
 
-  async commit(options:any = null, noWait = false) {
-    const raw = await commit(this.server, null, noWait)(options);
-    return JSON.parse(raw);
+  async justCommit(options:any = null) {
+    const proven = await this.generateNext(options)
+    await this.server.writeBlock(proven, true, false)
+    return proven
+  }
+
+  async commit(options:any = null) {
+    const proven = await this.generateNext(options)
+    await this.server.writeBlock(proven, true, true) // The resolution is done manually
+    const blocksResolved = await this.server.BlockchainService.blockResolution()
+    if (!blocksResolved) {
+      throw Error(DataErrors[DataErrors.BLOCK_WASNT_COMMITTED])
+    }
+    return blocksResolved
+  }
+
+  async resolveExistingBlock(max = 0) {
+    const blocksResolved = await this.server.BlockchainService.blockResolution(max)
+    if (!blocksResolved) {
+      throw Error(DataErrors[DataErrors.BLOCK_WASNT_COMMITTED])
+    }
+    return blocksResolved
+  }
+
+  private generateNext(options:any) {
+    const server = this.server as any
+    // Brings a priver to the server
+    if (!server._utProver) {
+      server._utProver = new BlockProver(server)
+      server._utGenerator = ProverDependency.duniter.methods.blockGenerator(server, server._utProver)
+    }
+    return server._utGenerator.makeNextBlock(null, null, options)
   }
 
   async commitWaitError(options:any, expectedError:string) {
@@ -505,8 +520,8 @@ export class TestingServer {
         }))
       }),
       (async () => {
-        const raw = await commit(this.server, null, true)(options);
-        return JSON.parse(raw);
+        const proven = await this.generateNext(options)
+        await this.server.writeBlock(proven, false)
       })()
     ])
     return results[1]
@@ -514,8 +529,7 @@ export class TestingServer {
 
   async commitExpectError(options:any) {
     try {
-      const raw = await commit(this.server)(options);
-      JSON.parse(raw);
+      await this.commit(options)
       throw { message: 'Commit operation should have thrown an error' };
     } catch (e) {
       if (e.statusCode) {
@@ -612,7 +626,7 @@ export class TestingServer {
 
   async prepareForNetwork() {
     await this.server.initWithDAL();
-    const bmaAPI = await bma(this.server);
+    const bmaAPI = await BmaDependency.duniter.methods.bma(this.server);
     await bmaAPI.openConnections();
     this.bma = bmaAPI;
     RouterDependency.duniter.methods.routeToNetwork(this.server)
@@ -658,10 +672,10 @@ export async function newWS2PBidirectionnalConnection(currency:string, k1:Key, k
       switch (i) {
         case 1:
           s1 = WS2PConnection.newConnectionFromWebSocketServer(ws, serverHandler, new WS2PPubkeyLocalAuth(currency, k1, ""), new WS2PPubkeyRemoteAuth(currency, k1), {
-            connectionTimeout: 100,
-            requestTimeout: 100
+            connectionTimeout: 1000,
+            requestTimeout: 1000
           });
-          s1.connect().catch((e:any) => console.error('WS2P: newConnectionFromWebSocketServer connection error'))
+          s1.connect().catch((e:any) => console.error('WS2P: newConnectionFromWebSocketServer connection error:', e))
           break;
       }
       resolveBefore({
@@ -681,7 +695,7 @@ export async function newWS2PBidirectionnalConnection(currency:string, k1:Key, k
   })
 }
 
-export const simpleWS2PNetwork: (s1: TestingServer, s2: TestingServer) => Promise<{ w1: WS2PConnection; ws2pc: WS2PConnection; wss: WS2PServer, cluster1:WS2PCluster, cluster2:WS2PCluster }> = async (s1: TestingServer, s2: TestingServer) => {
+export const simpleWS2PNetwork: (s1: TestingServer, s2: TestingServer) => Promise<{ w1: WS2PConnection; ws2pc: WS2PClient; wss: WS2PServer, cluster1:WS2PCluster, cluster2:WS2PCluster }> = async (s1: TestingServer, s2: TestingServer) => {
   let port = getNewTestingPort()
   const clientPub = s2.conf.pair.pub
   let w1: WS2PConnection | null
@@ -719,4 +733,22 @@ export function simpleTestingConf(now = 1500000000, pair:{ pub:string, sec:strin
     sigQty: 1,
     medianTimeBlocks: 1 // The medianTime always equals previous block's medianTime
   }
+}
+
+export function catUser(server: TestingServer) {
+  return new TestUser('cat', {
+    pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
+    sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'},
+    {
+      server
+    })
+}
+
+export function tacUser(server: TestingServer) {
+  return new TestUser('tac', {
+    pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc',
+    sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'},
+    {
+      server
+    })
 }
\ No newline at end of file
diff --git a/test/integration/tools/unit.js b/test/integration/tools/unit.js
deleted file mode 100644
index f92646ce2d132c11bc3733f24346eace76e09f08..0000000000000000000000000000000000000000
--- a/test/integration/tools/unit.js
+++ /dev/null
@@ -1,41 +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";
-
-var should = require('should');
-var co = require('co');
-
-module.exports = {
-
-  shouldFail: (promise, message) => co(function *() {
-    try {
-      yield promise;
-      throw { "message": '{ "message": "Should have thrown an error" }' };
-    } catch(e) {
-      e.should.have.property('message').equal(message);
-    }
-  }),
-
-  shouldNotFail: (promise) => co(function *() {
-    try {
-      yield promise;
-    } catch(e) {
-      let err = e;
-      if (typeof e === 'string') {
-        err = JSON.parse(e.message);
-      }
-      should.not.exist(err);
-    }
-  })
-};
diff --git a/test/integration/transactions-chaining.ts b/test/integration/transactions-chaining.ts
index 7b1142b2ba91f1a5fcd1c064fd234afabc90dc1a..3511ddfd208e6c06bc5ec033b9a5565d1acd88ea 100644
--- a/test/integration/transactions-chaining.ts
+++ b/test/integration/transactions-chaining.ts
@@ -14,11 +14,11 @@
 import {CommonConstants} from "../../app/lib/common-libs/constants"
 import {TestUser} from "./tools/TestUser"
 import {TestingServer} from "./tools/toolbox"
+import {shouldNotFail} from "../unit-tools"
 
 const should = require('should');
 const assert = require('assert');
 const toolbox   = require('./tools/toolbox');
-const unit   = require('./tools/unit');
 
 describe("Transaction chaining", () => {
 
@@ -81,8 +81,8 @@ describe("Transaction chaining", () => {
       });
       const tmp = CommonConstants.TRANSACTION_MAX_TRIES;
       CommonConstants.TRANSACTION_MAX_TRIES = 2;
-      await unit.shouldNotFail(toc.sendTX(tx1));
-      await unit.shouldNotFail(toc.sendTX(tx2));
+      await shouldNotFail(toc.sendTX(tx1));
+      await shouldNotFail(toc.sendTX(tx2));
       (await s1.get('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo')).should.have.property('sources').length(1); // 1200
       (await s1.get('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV')).should.have.property('sources').length(1); // 1200
       await s1.commit({ time: now + 7210 }); // TX1 commited only
@@ -110,13 +110,13 @@ describe("Transaction chaining", () => {
       let tx7 = await tic.prepareUTX(tx6, ['SIG(0)'], [{ qty: 1200, base: 0, lock: 'SIG(' + toc.pub + ')' }], { blockstamp, comment: "PING-PONG TX7" });
       const tmp = CommonConstants.TRANSACTION_MAX_TRIES;
       CommonConstants.TRANSACTION_MAX_TRIES = 2;
-      await unit.shouldNotFail(toc.sendTX(tx1));
-      await unit.shouldNotFail(toc.sendTX(tx2));
-      await unit.shouldNotFail(toc.sendTX(tx3));
-      await unit.shouldNotFail(toc.sendTX(tx4));
-      await unit.shouldNotFail(toc.sendTX(tx5));
-      await unit.shouldNotFail(toc.sendTX(tx6));
-      await unit.shouldNotFail(toc.sendTX(tx7));
+      await shouldNotFail(toc.sendTX(tx1));
+      await shouldNotFail(toc.sendTX(tx2));
+      await shouldNotFail(toc.sendTX(tx3));
+      await shouldNotFail(toc.sendTX(tx4));
+      await shouldNotFail(toc.sendTX(tx5));
+      await shouldNotFail(toc.sendTX(tx6));
+      await shouldNotFail(toc.sendTX(tx7));
       await s1.commitWaitError({ dontCareAboutChaining: true }, 'The maximum transaction chaining length per block is 5')
       CommonConstants.TRANSACTION_MAX_TRIES = tmp;
     })
diff --git a/test/integration/transactions-csv-cltv-sig.ts b/test/integration/transactions-csv-cltv-sig.ts
index 57e4ac69ad930b588302bd1a39b431bee5c175c2..a9ada96076f240df4f03089549f6f4b657d579a3 100644
--- a/test/integration/transactions-csv-cltv-sig.ts
+++ b/test/integration/transactions-csv-cltv-sig.ts
@@ -18,7 +18,6 @@ import {Buid} from "../../app/lib/common-libs/buid"
 describe("Transaction: CSV+CLTV+1of2SIG", function() {
 
   const now = 1500000000
-  const DONT_WAIT_FOR_BLOCKCHAIN_CHANGE = true
   let s1:TestingServer
   let cat:any
   let tac:any
@@ -59,7 +58,7 @@ describe("Transaction: CSV+CLTV+1of2SIG", function() {
     })
     txHash = hashf(tx)
     await cat.sendTX(tx)
-    const block = await s1.commit({ time: now }, DONT_WAIT_FOR_BLOCKCHAIN_CHANGE)
+    const block = await s1.justCommit({ time: now })
     block.should.have.property('transactions').length(1)
     await s1.waitToHaveBlock(2)
   })
@@ -79,7 +78,7 @@ describe("Transaction: CSV+CLTV+1of2SIG", function() {
       blockstamp: Buid.format.buid(current)
     })
     await tac.sendTX(tx)
-    const block = await s1.commit(null, DONT_WAIT_FOR_BLOCKCHAIN_CHANGE)
+    const block = await s1.justCommit(null)
     block.should.have.property('transactions').length(1)
   })
 
diff --git a/test/integration/crosschain-test.js b/test/integration/transactions/transaction-crosschain.ts
similarity index 55%
rename from test/integration/crosschain-test.js
rename to test/integration/transactions/transaction-crosschain.ts
index 22c436238f7400100e78be9b5a5a9b7c082031cd..2ea332e92d61197a58bfac30e4e7ca4badcb1b2e 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"
+import {shouldFail, shouldNotFail} from "../../unit-tools"
+import {expectAnswer} from "../tools/http-expect"
 
-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');
 
 /**
  * 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 shouldFail(ticM.sendTX(mtx4), 'Locktime not elapsed yet');
+        await 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 shouldFail(tocB.sendTX(btx2), 'Source already consumed');
+        await 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 shouldFail(ticM.sendTX(mtx4), 'Locktime not elapsed yet');
+        await 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 shouldNotFail(ticM.sendTX(mtx4)); // tic can rollback early (24h in real case) if toc does not reveal X
+        await 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 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 shouldFail(tocB.sendTX(btx6), 'Source already consumed');
+        await 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 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-pruning.js b/test/integration/transactions/transactions-pruning.ts
similarity index 63%
rename from test/integration/transactions-pruning.js
rename to test/integration/transactions/transactions-pruning.ts
index 617d5c5491bcd224248fa2f6feef049d4f4d741c..c680ab8c97aa8c41fcb7b97819a0c23c7d964200 100644
--- a/test/integration/transactions-pruning.js
+++ b/test/integration/transactions/transactions-pruning.ts
@@ -11,23 +11,20 @@
 // 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 {CommonConstants} from "../../../app/lib/common-libs/constants"
+import {NewTestingServer, TestingServer} from "../tools/toolbox"
+import {HttpBlock, HttpTxHistory} from "../../../app/modules/bma/lib/dtos"
 
-const co        = require('co');
 const should    = require('should');
-const TestUser  = require('./tools/TestUser').TestUser
-const commit    = require('./tools/commit');
-const toolbox   = require('./tools/toolbox');
-const constants = require('../../app/lib/constants');
-const CommonConstants = require('../../app/lib/common-libs/constants').CommonConstants
 
-let s1, cat1, tac1
+let s1:TestingServer, cat1:TestUser, tac1:TestUser
 
 describe("Transactions pruning", function() {
 
-  before(() => co(function*() {
+  before(async () => {
 
-    s1 = toolbox.server({
+    s1 = NewTestingServer({
       currency: 'currency_one',
       dt: 600,
       pair: {
@@ -39,25 +36,25 @@ describe("Transactions pruning", function() {
     cat1 = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
     tac1 = new TestUser('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
 
-    yield s1.prepareForNetwork();
+    await s1.prepareForNetwork();
 
-    const now = parseInt(Date.now() / 1000);
+    const now = parseInt(String(Date.now() / 1000))
 
     // Publishing identities
-    yield cat1.createIdentity();
-    yield tac1.createIdentity();
-    yield cat1.cert(tac1);
-    yield tac1.cert(cat1);
-    yield cat1.join();
-    yield tac1.join();
-    yield s1.commit();
-    yield s1.commit({
+    await cat1.createIdentity();
+    await tac1.createIdentity();
+    await cat1.cert(tac1);
+    await tac1.cert(cat1);
+    await cat1.join();
+    await tac1.join();
+    await s1.commit();
+    await s1.commit({
       time: now + 1300
     });
-    yield s1.commit();
-    yield cat1.send(20, tac1);
-    yield cat1.send(100, tac1);
-  }));
+    await s1.commit();
+    await cat1.sendMoney(20, tac1)
+    await cat1.sendMoney(100, tac1)
+  })
 
   after(() => {
     return Promise.all([
@@ -65,27 +62,27 @@ describe("Transactions pruning", function() {
     ])
   })
 
-  it('double spending transactions should both exist first', () => s1.expect('/tx/history/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', (res) => {
+  it('double spending transactions should both exist first', () => s1.expect('/tx/history/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', (res:HttpTxHistory) => {
     res.history.should.have.property('sending').length(2);
   }));
 
-  it('should only commit 1 tx', () => co(function*() {
-    yield s1.commit();
-    yield s1.expect('/blockchain/block/2', (res) => {
+  it('should only commit 1 tx', async () => {
+    await s1.commit();
+    await s1.expect('/blockchain/block/2', (res:HttpBlock) => {
       res.should.have.property('transactions').length(0);
     });
-    yield s1.expect('/blockchain/block/3', (res) => {
+    await s1.expect('/blockchain/block/3', (res:HttpBlock) => {
       res.should.have.property('transactions').length(1);
     });
-  }));
+  })
 
-  it('double spending transaction should have been pruned', () => co(function*() {
+  it('double spending transaction should have been pruned', async () => {
     const tmp = CommonConstants.TRANSACTION_MAX_TRIES;
     CommonConstants.TRANSACTION_MAX_TRIES = 1;
-    yield s1.commit();
-    yield s1.expect('/tx/history/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', (res) => {
+    await s1.commit();
+    await s1.expect('/tx/history/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', (res:HttpTxHistory) => {
       res.history.should.have.property('sending').length(0);
     });
     CommonConstants.TRANSACTION_MAX_TRIES = tmp;
-  }));
-});
+  })
+})
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..3b04c54ea8d7105e90d210aabd97880fc2c677b6 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.sendMoney(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-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..4ace7d46a3d0cbc56d57d649262bec5b47e1be4f
--- /dev/null
+++ b/test/integration/wot/wotb.ts
@@ -0,0 +1,450 @@
+// 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 {NewTestingServer, 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"
+import {shutDownEngine} from "../tools/shutdown-engine"
+
+const should    = require('should');
+
+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 = NewTestingServer(
+        Underscore.extend({
+          name: 'bb11',
+          memory: MEMORY_MODE,
+          port: '9337',
+          pair: {
+            pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
+            sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
+          },
+          rootoffset: 10,
+          sigQty: 1, dt: 1, ud0: 120
+        }, commonConf));
+
+      s2 = NewTestingServer(
+        Underscore.extend({
+          name: 'bb41',
+          memory: MEMORY_MODE,
+          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 = NewTestingServer(
+        Underscore.extend({
+          name: 'bb11',
+          memory: MEMORY_MODE,
+          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 s1.commit({
+        time: now + 500
+      });
+      await s1.commit({
+        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 s1.commit();
+      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 s2.commit({
+        time: now
+      });
+      // Should make MS expire for toc2
+      await s2.commit({
+        time: now + 500
+      });
+      await s2.commit({
+        time: now + 600
+      });
+      await cat2.join(); // Renew for not to be kicked!
+      await tic2.join(); // Renew for not to be kicked!
+      await s2.commit({
+        time: now + 800
+      });
+      await s2.commit({
+        time: now + 800
+      });
+      // Members excluded
+      await s2.commit({
+        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 s2.commit();
+      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 s3.commit({ time: now });
+      await s3.commit({
+        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 s3.commit({
+        time: now + 2400
+      });
+      // MedianTime is now +500 for next certs
+      await toc3.createIdentity();
+      await toc3.join();
+      await tic3.cert(toc3);
+      await s3.commit({
+        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 s3.commit({
+        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 s3.commit({
+        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 s3.commit({
+        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 6c180b4a83ee20048172b8f584ff725b84a11bc0..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.getWrittenIdtyByUID("cat");
-        let itoc = yield s1.dal.getWrittenIdtyByUID("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.getWrittenIdtyByUID("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_client_limitations.ts b/test/integration/ws2p/ws2p_client_limitations.ts
similarity index 96%
rename from test/integration/ws2p_client_limitations.ts
rename to test/integration/ws2p/ws2p_client_limitations.ts
index 4b16d9f03890068aae9326d02a8683d25de71486..073d71f164f7d6718558ca57cda7f12aa7eed135 100644
--- a/test/integration/ws2p_client_limitations.ts
+++ b/test/integration/ws2p/ws2p_client_limitations.ts
@@ -19,9 +19,9 @@ import {
   TestingServer,
   waitForkWS2PConnection,
   waitForkWS2PDisconnection
-} from "./tools/toolbox"
-import {WS2PCluster} from "../../app/modules/ws2p/lib/WS2PCluster"
-import {WS2PConstants} from "../../app/modules/ws2p/lib/constants"
+} from "../tools/toolbox"
+import {WS2PCluster} from "../../../app/modules/ws2p/lib/WS2PCluster"
+import {WS2PConstants} from "../../../app/modules/ws2p/lib/constants"
 
 const assert = require('assert')
 
@@ -115,10 +115,10 @@ describe("WS2P client limitations", function() {
     const currentS2 = await s2.BlockchainService.current()
     const currentS3 = await s3.BlockchainService.current()
     const currentS4 = await s4.BlockchainService.current()
-    assert.equal(currentS1.number, 2)
-    assert.equal(currentS2.number, 2)
-    assert.equal(currentS3.number, 2)
-    assert.equal(currentS4.number, 2)
+    assert.equal(currentS1 && currentS1.number, 2)
+    assert.equal(currentS2 && currentS2.number, 2)
+    assert.equal(currentS3 && currentS3.number, 2)
+    assert.equal(currentS4 && currentS4.number, 2)
   })
 
   it('should be able to have a connected network on s2 start', async () => {
diff --git a/test/integration/ws2p_cluster.ts b/test/integration/ws2p/ws2p_cluster.ts
similarity index 94%
rename from test/integration/ws2p_cluster.ts
rename to test/integration/ws2p/ws2p_cluster.ts
index 13adbf4ed14c6aa38bfb387995fa2398db018738..34a30d159ce8cdf1c1e0018134d31a98af22d0f1 100644
--- a/test/integration/ws2p_cluster.ts
+++ b/test/integration/ws2p/ws2p_cluster.ts
@@ -18,10 +18,10 @@ import {
   simpleUser,
   TestingServer,
   waitForkWS2PConnection
-} from "./tools/toolbox"
-import {WS2PCluster} from "../../app/modules/ws2p/lib/WS2PCluster"
-import {WS2PConstants} from "../../app/modules/ws2p/lib/constants"
-import { TestUser } from './tools/TestUser';
+} from "../tools/toolbox"
+import {WS2PCluster} from "../../../app/modules/ws2p/lib/WS2PCluster"
+import {WS2PConstants} from "../../../app/modules/ws2p/lib/constants"
+import {TestUser} from '../tools/TestUser';
 
 const assert = require('assert')
 
@@ -94,9 +94,9 @@ describe("WS2P cluster", function() {
     const currentS1 = await s1.BlockchainService.current()
     const currentS2 = await s2.BlockchainService.current()
     const currentS3 = await s3.BlockchainService.current()
-    assert.equal(currentS1.number, 2)
-    assert.equal(currentS2.number, 2)
-    assert.equal(currentS3.number, 2)
+    assert.equal(currentS1 && currentS1.number, 2)
+    assert.equal(currentS2 && currentS2.number, 2)
+    assert.equal(currentS3 && currentS3.number, 2)
   })
 
   it('should be able to have a connected network on s2 start', async () => {
diff --git a/test/integration/ws2p_connection.ts b/test/integration/ws2p/ws2p_connection.ts
similarity index 97%
rename from test/integration/ws2p_connection.ts
rename to test/integration/ws2p/ws2p_connection.ts
index f252d3407b46bd49b45b77e0b8fe36af8ebe9cd4..84defd19e0329e87f6105976ea04209f323d3862 100644
--- a/test/integration/ws2p_connection.ts
+++ b/test/integration/ws2p/ws2p_connection.ts
@@ -17,15 +17,18 @@ import {
   WS2PPubkeyLocalAuth,
   WS2PPubkeyRemoteAuth,
   WS2PRemoteAuth
-} from "../../app/modules/ws2p/lib/WS2PConnection"
-import {Key, verify} from "../../app/lib/common-libs/crypto/keyring"
-import {assertThrows, 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"
+} from "../../../app/modules/ws2p/lib/WS2PConnection"
+import {Key, verify} from "../../../app/lib/common-libs/crypto/keyring"
+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"
+import {NewLogger} from "../../../app/lib/logger"
+import {WebSocketServer} from "../../../app/lib/common-libs/websocket"
+
 const assert = require('assert');
-const WebSocketServer = require('ws').Server
-const logger = require('../../app/lib/logger').NewLogger('ws2p')
+const logger = NewLogger()
 const gtest = "gtest"
 
 describe('WS2P', () => {
diff --git a/test/integration/ws2p_doc_sharing.ts b/test/integration/ws2p/ws2p_doc_sharing.ts
similarity index 86%
rename from test/integration/ws2p_doc_sharing.ts
rename to test/integration/ws2p/ws2p_doc_sharing.ts
index b001ef00194768846f24827fb5667de44222abe4..0de1ee131577d8f61133e922781a450d9a4a70ad 100644
--- a/test/integration/ws2p_doc_sharing.ts
+++ b/test/integration/ws2p/ws2p_doc_sharing.ts
@@ -11,9 +11,9 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-import { TestUser } from './tools/TestUser';
-import {simpleTestingConf, simpleTestingServer, simpleUser, simpleWS2PNetwork, TestingServer} from "./tools/toolbox"
-import {WS2PConstants} from "../../app/modules/ws2p/lib/constants"
+import {TestUser} from '../tools/TestUser';
+import {simpleTestingConf, simpleTestingServer, simpleUser, simpleWS2PNetwork, TestingServer} from "../tools/toolbox"
+import {WS2PConstants} from "../../../app/modules/ws2p/lib/constants"
 
 const assert = require('assert')
 
@@ -72,9 +72,9 @@ describe("WS2P doc sharing", function() {
     await s2.waitToHaveBlock(1)
     const b1s1 = await s1.BlockchainService.current()
     const b1s2 = await s2.BlockchainService.current()
-    assert.equal(b1s1.number, 1)
-    assert.equal(b1s2.number, 1)
-    assert.equal(b1s1.hash, b1s2.hash)
+    assert.equal(b1s1 && b1s1.number, 1)
+    assert.equal(b1s2 && b1s2.number, 1)
+    assert.equal(b1s1 && b1s1.hash, b1s2 && b1s2.hash)
   })
 
   it('should see the identity, certs and memberships in the docpool', async () => {
@@ -90,10 +90,10 @@ describe("WS2P doc sharing", function() {
     await s2.waitToHaveBlock(2)
     const b2s1 = await s1.BlockchainService.current()
     const b2s2 = await s2.BlockchainService.current()
-    assert.equal(b2s1.number, 2)
-    assert.equal(b2s2.number, 2)
-    assert.equal(b2s1.hash, b2s2.hash)
-    assert.equal(b2s2.joiners.length, 1)
+    assert.equal(b2s1 && b2s1.number, 2)
+    assert.equal(b2s2 && b2s2.number, 2)
+    assert.equal(b2s1 && b2s1.hash, b2s2 && b2s2.hash)
+    assert.equal(b2s2 && b2s2.joiners.length, 1)
   })
 
   it('should see the transactions pending', async () => {
@@ -110,10 +110,10 @@ describe("WS2P doc sharing", function() {
     await s2.waitToHaveBlock(3)
     const b3s1 = await s1.BlockchainService.current()
     const b3s2 = await s2.BlockchainService.current()
-    assert.equal(b3s1.number, 3)
-    assert.equal(b3s2.number, 3)
-    assert.equal(b3s1.hash, b3s2.hash)
-    assert.equal(b3s2.transactions.length, 1)
+    assert.equal(b3s1 && b3s1.number, 3)
+    assert.equal(b3s2 && b3s2.number, 3)
+    assert.equal(b3s1 && b3s1.hash, b3s2 && b3s2.hash)
+    assert.equal(b3s2 && b3s2.transactions.length, 1)
   })
 
   it('should see the peer documents', async () => {
diff --git a/test/integration/ws2p_docpool.ts b/test/integration/ws2p/ws2p_docpool.ts
similarity index 87%
rename from test/integration/ws2p_docpool.ts
rename to test/integration/ws2p/ws2p_docpool.ts
index fabc209d205ec34a6b4781a0bee393cf427d1b65..1e7c5dde7891b2ccf7c786f53c3b0875c2e2a9d2 100644
--- a/test/integration/ws2p_docpool.ts
+++ b/test/integration/ws2p/ws2p_docpool.ts
@@ -11,10 +11,10 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-import {simpleTestingConf, simpleTestingServer, simpleUser, simpleWS2PNetwork, TestingServer} from "./tools/toolbox"
-import {WS2PCluster} from "../../app/modules/ws2p/lib/WS2PCluster"
-import {ProverDependency} from "../../app/modules/prover/index"
-import {WS2PConstants} from "../../app/modules/ws2p/lib/constants"
+import {simpleTestingConf, simpleTestingServer, simpleUser, simpleWS2PNetwork, TestingServer} from "../tools/toolbox"
+import {WS2PCluster} from "../../../app/modules/ws2p/lib/WS2PCluster"
+import {ProverDependency} from "../../../app/modules/prover/index"
+import {WS2PConstants} from "../../../app/modules/ws2p/lib/constants"
 
 const assert = require('assert')
 
@@ -66,8 +66,8 @@ describe("WS2P docpool pulling", function() {
   it('should have b#2 on s1 and s2', async () => {
     const currentS1 = await s1.BlockchainService.current()
     const currentS2 = await s2.BlockchainService.current()
-    assert.equal(currentS1.number, 2)
-    assert.equal(currentS2.number, 2)
+    assert.equal(currentS1 && currentS1.number, 2)
+    assert.equal(currentS2 && currentS2.number, 2)
   })
 
   it('should be able to pull the docpool', async () => {
@@ -85,7 +85,7 @@ describe("WS2P docpool pulling", function() {
     })
     const currentS1 = await s1.BlockchainService.current()
     const currentS2 = await s2.BlockchainService.current()
-    assert.equal(currentS1.number, 2)
-    assert.equal(currentS2.number, 2)
+    assert.equal(currentS1 && currentS1.number, 2)
+    assert.equal(currentS2 && currentS2.number, 2)
   })
 })
diff --git a/test/integration/ws2p_exchange.ts b/test/integration/ws2p/ws2p_exchange.ts
similarity index 81%
rename from test/integration/ws2p_exchange.ts
rename to test/integration/ws2p/ws2p_exchange.ts
index 90b43facbabcec943d57b446b7c948828a9b66b1..b5600948c4c8394b4cf7f0f3577dda8778864d6d 100644
--- a/test/integration/ws2p_exchange.ts
+++ b/test/integration/ws2p/ws2p_exchange.ts
@@ -11,14 +11,15 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-import {WS2PConnection} from "../../app/modules/ws2p/lib/WS2PConnection"
-import {Key} from "../../app/lib/common-libs/crypto/keyring"
-import {newWS2PBidirectionnalConnection} from "./tools/toolbox"
-import {WS2PRequester} from "../../app/modules/ws2p/lib/WS2PRequester"
-import {BlockDTO} from "../../app/lib/dto/BlockDTO"
-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 {WS2PConnection} from "../../../app/modules/ws2p/lib/WS2PConnection"
+import {Key} from "../../../app/lib/common-libs/crypto/keyring"
+import {newWS2PBidirectionnalConnection} from "../tools/toolbox"
+import {WS2PRequester} from "../../../app/modules/ws2p/lib/WS2PRequester"
+import {BlockDTO} from "../../../app/lib/dto/BlockDTO"
+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"
+
 const assert = require('assert');
 
 describe('WS2P exchange', () => {
diff --git a/test/integration/ws2p_heads.ts b/test/integration/ws2p/ws2p_heads.ts
similarity index 94%
rename from test/integration/ws2p_heads.ts
rename to test/integration/ws2p/ws2p_heads.ts
index a97f7ec425a679c5c17720ba5dc878b95ee31d88..07fbd8e1c982c543c5717bcbb2900158089a4d64 100644
--- a/test/integration/ws2p_heads.ts
+++ b/test/integration/ws2p/ws2p_heads.ts
@@ -11,9 +11,9 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-import {getNewTestingPort, simpleTestingConf, simpleTestingServer, simpleUser, TestingServer} from "./tools/toolbox"
-import {WS2PCluster} from "../../app/modules/ws2p/lib/WS2PCluster"
-import {WS2PConstants} from "../../app/modules/ws2p/lib/constants"
+import {getNewTestingPort, simpleTestingConf, simpleTestingServer, simpleUser, TestingServer} from "../tools/toolbox"
+import {WS2PCluster} from "../../../app/modules/ws2p/lib/WS2PCluster"
+import {WS2PConstants} from "../../../app/modules/ws2p/lib/constants"
 
 const assert = require('assert')
 const should = require('should')
@@ -72,8 +72,8 @@ describe("WS2P heads propagation", function() {
   it('should have b#2 on s1, s2 and s3', async () => {
     const currentS1 = await s1.BlockchainService.current()
     const currentS2 = await s2.BlockchainService.current()
-    assert.equal(currentS1.number, 2)
-    assert.equal(currentS2.number, 2)
+    assert.equal(currentS1 && currentS1.number, 2)
+    assert.equal(currentS2 && currentS2.number, 2)
   })
 
   it('should be able to have a connected network on s2 start', async () => {
diff --git a/test/integration/ws2p_network.ts b/test/integration/ws2p/ws2p_network.ts
similarity index 93%
rename from test/integration/ws2p_network.ts
rename to test/integration/ws2p/ws2p_network.ts
index e241db09378c52f196d1b15b8b9d8a9d52bea48b..cd3163ec1efe192666cbcf8348c2e44737f979a5 100644
--- a/test/integration/ws2p_network.ts
+++ b/test/integration/ws2p/ws2p_network.ts
@@ -11,9 +11,9 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-import {getNewTestingPort, simpleTestingConf, simpleTestingServer, simpleUser, TestingServer} from "./tools/toolbox"
-import {WS2PCluster} from "../../app/modules/ws2p/lib/WS2PCluster"
-import {WS2PConstants} from "../../app/modules/ws2p/lib/constants"
+import {getNewTestingPort, simpleTestingConf, simpleTestingServer, simpleUser, TestingServer} from "../tools/toolbox"
+import {WS2PCluster} from "../../../app/modules/ws2p/lib/WS2PCluster"
+import {WS2PConstants} from "../../../app/modules/ws2p/lib/constants"
 
 const assert = require('assert')
 
@@ -85,8 +85,8 @@ describe("WS2P network", function() {
   it('should have b#2 on s1 and s2', async () => {
     const currentS1 = await s1.BlockchainService.current()
     const currentS2 = await s2.BlockchainService.current()
-    assert.equal(currentS1.number, 2)
-    assert.equal(currentS2.number, 2)
+    assert.equal(currentS1 && currentS1.number, 2)
+    assert.equal(currentS2 && currentS2.number, 2)
   })
 
   it('should be able to have a connected network on s2 start', async () => {
diff --git a/test/integration/ws2p_pulling.ts b/test/integration/ws2p/ws2p_pulling.ts
similarity index 64%
rename from test/integration/ws2p_pulling.ts
rename to test/integration/ws2p/ws2p_pulling.ts
index 3f6064c0bdb77a6e843be3fd04ece994dcce4f5e..52f7aaaf448e026d850a17eace500ac704cae3e2 100644
--- a/test/integration/ws2p_pulling.ts
+++ b/test/integration/ws2p/ws2p_pulling.ts
@@ -11,9 +11,11 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-import {simpleTestingConf, simpleTestingServer, simpleUser, simpleWS2PNetwork, TestingServer} from "./tools/toolbox"
-import {WS2PCluster} from "../../app/modules/ws2p/lib/WS2PCluster"
-import {WS2PConstants} from "../../app/modules/ws2p/lib/constants"
+import {simpleTestingConf, simpleTestingServer, simpleUser, simpleWS2PNetwork, TestingServer} from "../tools/toolbox"
+import {WS2PCluster} from "../../../app/modules/ws2p/lib/WS2PCluster"
+import {WS2PConstants} from "../../../app/modules/ws2p/lib/constants"
+import {WS2PClient} from "../../../app/modules/ws2p/lib/WS2PClient"
+import {TestUser} from "../tools/TestUser"
 
 const assert = require('assert')
 
@@ -24,10 +26,13 @@ describe("WS2P block pulling", function() {
 
   const now = 1500000000
   let s1:TestingServer, s2:TestingServer, wss:any
+  let ws2pc:WS2PClient
+  let cluster1:WS2PCluster
   let cluster2:WS2PCluster
-  let cat:any, tac:any
+  let cat:TestUser, tac:TestUser, toc:TestUser
   const catKeyring = { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}
   const tacKeyring = { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}
+  const tocKeyring = { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}
 
   let b0, b1, b2
 
@@ -38,6 +43,7 @@ describe("WS2P block pulling", function() {
     s2 = simpleTestingServer(conf2)
     cat = simpleUser('cat', catKeyring, s1)
     tac = simpleUser('tac', tacKeyring, s1)
+    toc = simpleUser('toc', tocKeyring, s2) // On S2
     await s1.initDalBmaConnections()
     await s2.initDalBmaConnections()
 
@@ -63,6 +69,8 @@ describe("WS2P block pulling", function() {
 
     const network = await simpleWS2PNetwork(s1, s2)
     wss = network.wss
+    ws2pc = network.ws2pc
+    cluster1 = network.cluster1
     cluster2 = network.cluster2
   })
 
@@ -71,15 +79,29 @@ describe("WS2P block pulling", function() {
   it('should have b#6 on s1, b#2 on s2', async () => {
     const currentS1 = await s1.BlockchainService.current()
     const currentS2 = await s2.BlockchainService.current()
-    assert.equal(currentS1.number, 6)
-    assert.equal(currentS2.number, 2)
+    assert.equal(currentS1 && currentS1.number, 6)
+    assert.equal(currentS2 && currentS2.number, 2)
   })
 
   it('should be able to pull and have the same current block as a result', async () => {
     await cluster2.pullBlocks()
     const currentS1 = await s1.BlockchainService.current()
     const currentS2 = await s2.BlockchainService.current()
-    assert.equal(currentS1.number, 6)
-    assert.equal(currentS2.number, 6)
+    assert.equal(currentS1 && currentS1.number, 6)
+    assert.equal(currentS2 && currentS2.number, 6)
+  })
+
+  it('should be able to pull pending identities', async () => {
+    assert.equal((await s1.dal.idtyDAL.getPendingIdentities()).length, 0)
+    assert.equal((await s2.dal.idtyDAL.getPendingIdentities()).length, 0)
+    // Toc is on S2 by default: we disable the stream s2 => s1 so we can test the pulling
+    await ws2pc.disableStream()
+    await toc.createIdentity();
+    await toc.join();
+    await cat.cert(toc, s2, s2);
+    await tac.cert(toc, s2, s2);
+    await cluster1.pullDocpool()
+    assert.equal((await s1.dal.idtyDAL.getPendingIdentities()).length, 1)
+    assert.equal((await s2.dal.idtyDAL.getPendingIdentities()).length, 1)
   })
 })
diff --git a/test/integration/ws2p_server_limitations.ts b/test/integration/ws2p/ws2p_server_limitations.ts
similarity index 96%
rename from test/integration/ws2p_server_limitations.ts
rename to test/integration/ws2p/ws2p_server_limitations.ts
index 691345d6301374c78cc35419dbb28c6c10484082..36520b9c1874ad683481f0265e03245cf1ea1878 100644
--- a/test/integration/ws2p_server_limitations.ts
+++ b/test/integration/ws2p/ws2p_server_limitations.ts
@@ -19,9 +19,9 @@ import {
   TestingServer,
   waitForkWS2PConnection,
   waitForkWS2PDisconnection
-} from "./tools/toolbox"
-import {WS2PCluster} from "../../app/modules/ws2p/lib/WS2PCluster"
-import {WS2PConstants} from "../../app/modules/ws2p/lib/constants"
+} from "../tools/toolbox"
+import {WS2PCluster} from "../../../app/modules/ws2p/lib/WS2PCluster"
+import {WS2PConstants} from "../../../app/modules/ws2p/lib/constants"
 
 const assert = require('assert')
 
@@ -118,10 +118,10 @@ describe("WS2P server limitations", function() {
     const currentS2 = await s2.BlockchainService.current()
     const currentS3 = await s3.BlockchainService.current()
     const currentS4 = await s4.BlockchainService.current()
-    assert.equal(currentS1.number, 2)
-    assert.equal(currentS2.number, 2)
-    assert.equal(currentS3.number, 2)
-    assert.equal(currentS4.number, 2)
+    assert.equal(currentS1 && currentS1.number, 2)
+    assert.equal(currentS2 && currentS2.number, 2)
+    assert.equal(currentS3 && currentS3.number, 2)
+    assert.equal(currentS4 && currentS4.number, 2)
   })
 
   it('should be able to have a connected network on s2 start', async () => {
diff --git a/test/mocha.opts b/test/mocha.opts
index 13ee986171fa0dccd4c248679eb3e32bcb7f3517..1d4de1ea87731d261283162bba5ff826bebd5ff4 100644
--- a/test/mocha.opts
+++ b/test/mocha.opts
@@ -2,7 +2,7 @@
 --require source-map-support/register
 --full-trace
 --growl
---timeout 20000
+--timeout 30000
 --recursive
 -R spec
 test/
diff --git a/test/unit-tools.ts b/test/unit-tools.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3c85da7e52f1106f53c323128b1c7636e0eb3ce1
--- /dev/null
+++ b/test/unit-tools.ts
@@ -0,0 +1,62 @@
+// 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 * as assert from 'assert'
+
+export async function shouldThrow(promise:Promise<any>) {
+  let error = false
+  try {
+    await promise
+  } catch (e) {
+    error = true
+  }
+  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)
+  }
+}
diff --git a/tsconfig.json b/tsconfig.json
index 0d50c5895ccac504389e3c7489b2006394b331ac..82e16bc8d077bb80f4b440041d75c5aa8eecb323 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -8,7 +8,8 @@
     "strictNullChecks": true,
     "noImplicitThis": true,
     "noImplicitAny": true,
-    "noImplicitReturns": true
+    "noImplicitReturns": true,
+    "experimentalDecorators": true
   },
   "include": [
     "server.ts",
diff --git a/yarn.lock b/yarn.lock
index 27b57764e92f118d2b9267a7f057a165ee4f1760..f2fb840018295aeeb0105b0b57a85800d0ebe0e9 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,18 +2,78 @@
 # yarn lockfile v1
 
 
+"@types/events@*":
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/@types/events/-/events-1.2.0.tgz#81a6731ce4df43619e5c8c945383b3e62a89ea86"
+
+"@types/fs-extra@5.0.1":
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-5.0.1.tgz#cd856fbbdd6af2c11f26f8928fd8644c9e9616c9"
+  dependencies:
+    "@types/node" "*"
+
+"@types/glob@*":
+  version "5.0.35"
+  resolved "https://registry.yarnpkg.com/@types/glob/-/glob-5.0.35.tgz#1ae151c802cece940443b5ac246925c85189f32a"
+  dependencies:
+    "@types/events" "*"
+    "@types/minimatch" "*"
+    "@types/node" "*"
+
+"@types/handlebars@4.0.36":
+  version "4.0.36"
+  resolved "https://registry.yarnpkg.com/@types/handlebars/-/handlebars-4.0.36.tgz#ff57c77fa1ab6713bb446534ddc4d979707a3a79"
+
+"@types/highlight.js@9.12.2":
+  version "9.12.2"
+  resolved "https://registry.yarnpkg.com/@types/highlight.js/-/highlight.js-9.12.2.tgz#6ee7cd395effe5ec80b515d3ff1699068cd0cd1d"
+
+"@types/lodash@4.14.104":
+  version "4.14.104"
+  resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.104.tgz#53ee2357fa2e6e68379341d92eb2ecea4b11bb80"
+
+"@types/lokijs@^1.5.2":
+  version "1.5.2"
+  resolved "https://registry.yarnpkg.com/@types/lokijs/-/lokijs-1.5.2.tgz#ed228f080033ce1fb16eff4acde65cb9ae0f1bf2"
+
+"@types/marked@0.3.0":
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/@types/marked/-/marked-0.3.0.tgz#583c223dd33385a1dda01aaf77b0cd0411c4b524"
+
+"@types/minimatch@*", "@types/minimatch@3.0.3":
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
+
 "@types/mocha@^2.2.41":
   version "2.2.44"
   resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.44.tgz#1d4a798e53f35212fd5ad4d04050620171cd5b5e"
 
+"@types/node@*":
+  version "10.3.1"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-10.3.1.tgz#51092fbacaed768a122a293814474fbf6e5e8b6d"
+
 "@types/node@^8.0.9":
   version "8.0.53"
   resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.53.tgz#396b35af826fa66aad472c8cb7b8d5e277f4e6d8"
 
+"@types/shelljs@0.7.8":
+  version "0.7.8"
+  resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.7.8.tgz#4b4d6ee7926e58d7bca448a50ba442fd9f6715bd"
+  dependencies:
+    "@types/glob" "*"
+    "@types/node" "*"
+
 "@types/should@^8.3.0":
   version "8.3.0"
   resolved "https://registry.yarnpkg.com/@types/should/-/should-8.3.0.tgz#e2b460243685dbe377182f39ef38d37f4d157ada"
 
+"@types/ws@^5.1.2":
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/@types/ws/-/ws-5.1.2.tgz#f02d3b1cd46db7686734f3ce83bdf46c49decd64"
+  dependencies:
+    "@types/events" "*"
+    "@types/node" "*"
+
 JSONSelect@0.4.0:
   version "0.4.0"
   resolved "https://registry.yarnpkg.com/JSONSelect/-/JSONSelect-0.4.0.tgz#a08edcc67eb3fcbe99ed630855344a0cf282bb8d"
@@ -606,6 +666,12 @@ cli-cursor@^2.1.0:
   dependencies:
     restore-cursor "^2.0.0"
 
+cli-table@^0.3.1:
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23"
+  dependencies:
+    colors "1.0.3"
+
 cli-width@^1.0.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-1.1.1.tgz#a4d293ef67ebb7b88d4a4d42c0ccf00c4d1e366d"
@@ -630,7 +696,7 @@ cliui@^3.2.0:
     strip-ansi "^3.0.1"
     wrap-ansi "^2.0.0"
 
-co@4.6.0, co@^4.6.0:
+co@^4.6.0:
   version "4.6.0"
   resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
 
@@ -658,7 +724,7 @@ colors@0.5.x:
   version "0.5.1"
   resolved "https://registry.yarnpkg.com/colors/-/colors-0.5.1.tgz#7d0023eaeb154e8ee9fce75dcb923d0ed1667774"
 
-colors@1.0.x:
+colors@1.0.3, colors@1.0.x:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
 
@@ -1523,6 +1589,14 @@ fs-extra@^0.22.1:
     jsonfile "^2.1.0"
     rimraf "^2.2.8"
 
+fs-extra@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd"
+  dependencies:
+    graceful-fs "^4.1.2"
+    jsonfile "^4.0.0"
+    universalify "^0.1.0"
+
 fs.realpath@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
@@ -1682,7 +1756,7 @@ growl@1.9.2:
   version "1.9.2"
   resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f"
 
-handlebars@^4.0.3:
+handlebars@^4.0.3, handlebars@^4.0.6:
   version "4.0.11"
   resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc"
   dependencies:
@@ -1773,6 +1847,10 @@ he@1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
 
+highlight.js@^9.0.0:
+  version "9.12.0"
+  resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.12.0.tgz#e6d9dbe57cbefe60751f02af336195870c90c01e"
+
 hoek@0.9.x:
   version "0.9.1"
   resolved "https://registry.yarnpkg.com/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505"
@@ -2205,6 +2283,12 @@ jsonfile@^2.1.0:
   optionalDependencies:
     graceful-fs "^4.1.6"
 
+jsonfile@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
+  optionalDependencies:
+    graceful-fs "^4.1.6"
+
 jsonify@~0.0.0:
   version "0.0.0"
   resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
@@ -2363,10 +2447,18 @@ lodash@^4.0.0, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.17.4, lodash@^4.3.0, lo
   version "4.17.4"
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
 
+lodash@^4.17.5:
+  version "4.17.10"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
+
 log-driver@1.2.4:
   version "1.2.4"
   resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.4.tgz#2d62d7faef45d8a71341961a04b0761eca99cfa3"
 
+lokijs@^1.5.3:
+  version "1.5.3"
+  resolved "https://registry.yarnpkg.com/lokijs/-/lokijs-1.5.3.tgz#6952722ffa3049a55a5e1c10ee4a0947a3e5e19b"
+
 longest@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
@@ -2392,6 +2484,10 @@ map-stream@~0.1.0:
   version "0.1.0"
   resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194"
 
+marked@^0.3.17:
+  version "0.3.19"
+  resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.19.tgz#5d47f709c4c9fc3c216b6d46127280f40b39d790"
+
 "match-stream@>= 0.0.2 < 1", match-stream@~0.0.2:
   version "0.0.2"
   resolved "https://registry.yarnpkg.com/match-stream/-/match-stream-0.0.2.tgz#99eb050093b34dffade421b9ac0b410a9cfa17cf"
@@ -3035,6 +3131,10 @@ progress@^1.1.8:
   version "1.1.8"
   resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be"
 
+progress@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f"
+
 proxy-addr@~1.1.3:
   version "1.1.5"
   resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.5.tgz#71c0ee3b102de3f202f3b64f608d173fcba1a918"
@@ -3059,15 +3159,15 @@ punycode@^1.4.1:
   version "1.4.1"
   resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
 
-q-io@1.13.2:
-  version "1.13.2"
-  resolved "https://registry.yarnpkg.com/q-io/-/q-io-1.13.2.tgz#eea130d481ddb5e1aa1bc5a66855f7391d06f003"
+q-io@^1.13.5:
+  version "1.13.5"
+  resolved "https://registry.yarnpkg.com/q-io/-/q-io-1.13.5.tgz#6ac39deb5cfe0dc68436e6f8c33d0d7c3f471bb2"
   dependencies:
     collections "^0.2.0"
     mime "^1.2.11"
     mimeparse "^0.1.4"
     q "^1.0.1"
-    qs "^1.2.1"
+    qs "^6.4.0"
     url2 "^0.0.0"
 
 q@^1.0.1:
@@ -3078,11 +3178,7 @@ qs@6.4.0, qs@~6.4.0:
   version "6.4.0"
   resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
 
-qs@^1.2.1:
-  version "1.2.2"
-  resolved "https://registry.yarnpkg.com/qs/-/qs-1.2.2.tgz#19b57ff24dc2a99ce1f8bdf6afcda59f8ef61f88"
-
-qs@^6.5.1, qs@~6.5.1:
+qs@^6.4.0, qs@^6.5.1, qs@~6.5.1:
   version "6.5.1"
   resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
 
@@ -3518,6 +3614,14 @@ shelljs@^0.7.5:
     interpret "^1.0.0"
     rechoir "^0.6.2"
 
+shelljs@^0.8.1:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.2.tgz#345b7df7763f4c2340d584abb532c5f752ca9e35"
+  dependencies:
+    glob "^7.0.0"
+    interpret "^1.0.0"
+    rechoir "^0.6.2"
+
 should-equal@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/should-equal/-/should-equal-2.0.0.tgz#6072cf83047360867e68e98b09d71143d04ee0c3"
@@ -4023,9 +4127,43 @@ typedarray@^0.0.6:
   version "0.0.6"
   resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
 
-typescript@^2.4.1:
-  version "2.6.2"
-  resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4"
+typedoc-default-themes@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/typedoc-default-themes/-/typedoc-default-themes-0.5.0.tgz#6dc2433e78ed8bea8e887a3acde2f31785bd6227"
+
+typedoc-plugin-sourcefile-url@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/typedoc-plugin-sourcefile-url/-/typedoc-plugin-sourcefile-url-1.0.3.tgz#fbbcc4b71bd92d2f794d1c169a480042296b1fe6"
+
+typedoc@^0.11.1:
+  version "0.11.1"
+  resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.11.1.tgz#9f033887fd2218c769e1045feb88a1efed9f12c9"
+  dependencies:
+    "@types/fs-extra" "5.0.1"
+    "@types/handlebars" "4.0.36"
+    "@types/highlight.js" "9.12.2"
+    "@types/lodash" "4.14.104"
+    "@types/marked" "0.3.0"
+    "@types/minimatch" "3.0.3"
+    "@types/shelljs" "0.7.8"
+    fs-extra "^5.0.0"
+    handlebars "^4.0.6"
+    highlight.js "^9.0.0"
+    lodash "^4.17.5"
+    marked "^0.3.17"
+    minimatch "^3.0.0"
+    progress "^2.0.0"
+    shelljs "^0.8.1"
+    typedoc-default-themes "^0.5.0"
+    typescript "2.7.2"
+
+typescript@2.7.2:
+  version "2.7.2"
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.7.2.tgz#2d615a1ef4aee4f574425cdff7026edf81919836"
+
+typescript@~2.8.1:
+  version "2.8.4"
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.8.4.tgz#0b1db68e6bdfb0b767fa2ab642136a35b059b199"
 
 uglify-js@^2.6:
   version "2.8.29"
@@ -4068,6 +4206,10 @@ underscore@~1.7.0:
   version "1.7.0"
   resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.7.0.tgz#6bbaf0877500d36be34ecaa584e0db9fef035209"
 
+universalify@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7"
+
 unpipe@1.0.0, unpipe@~1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"