diff --git a/.gitignore b/.gitignore
index db4b1103dc073aa1e6fd9793e34fb2b069435465..0fdf9f4d60fe86d44c161a39da1f7b8d1484dd74 100644
--- a/.gitignore
+++ b/.gitignore
@@ -52,6 +52,8 @@ 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/fast/modules/crawler/block_pulling.js*
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 697be36e2117594d59d43860d8e8f83a726e0fda..ddd9044a720e14011a188719c8798117bf76649a 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,7 +1,52 @@
+stages:
+    - github-sync
+    - test
+
 before_script:
     - export NVM_DIR="$HOME/.nvm"
     - . "$NVM_DIR/nvm.sh"
 
+push_to_github:
+    stage: github-sync
+    variables:
+        GIT_STRATEGY: none
+    tags:
+        - github
+    before_script:
+        - ''
+    script:
+        - rm -rf ./*
+        - rm -rf .git
+        - git clone --mirror $CI_REPOSITORY_URL .
+        - git remote add github $GITHUB_URL_AND_KEY
+        - git config --global user.email "contact@duniter.org"
+        - git config --global user.name "Duniter"
+        # Job would fail if we don't remove refs about pull requests
+        - bash -c "cat packed-refs | grep -v 'refs/pull' > packed-refs-new; echo 'Removed pull refs.'"
+        - mv packed-refs-new packed-refs
+        - bash -c "git push --force --mirror github 2>&1 | grep -v duniter-gitlab; echo $?"
+
+enforce_readme:
+    stage: github-sync
+    variables:
+        GIT_STRATEGY: none
+    tags:
+        - github
+    before_script:
+        - ''
+    script:
+      - rm -rf ./*
+      - rm -rf .git
+      - git clone $GITHUB_URL_AND_KEY .
+      - git config --global user.email "contact@duniter.org"
+      - git config --global user.name "Duniter"
+      - git checkout master
+      - cat .github/github_disclaimer.md > README.md.new
+      - cat README.md >> README.md.new
+      - mv README.md.new README.md
+      - git commit -am "Enforce github readme"
+      - git push origin master
+
 test:
   stage: test
   tags:
diff --git a/app/ProcessCpuProfiler.ts b/app/ProcessCpuProfiler.ts
new file mode 100644
index 0000000000000000000000000000000000000000..31bbf45117b8a38b3b5a6e447f1896025738a2a2
--- /dev/null
+++ b/app/ProcessCpuProfiler.ts
@@ -0,0 +1,72 @@
+const SAMPLING_PERIOD = 150 // milliseconds
+const MAX_SAMPLES_DISTANCE = 20 * 1000000 // seconds
+
+function getMicrosecondsTime() {
+  const [ seconds, nanoseconds ] = process.hrtime()
+  return seconds * 1000000 + nanoseconds / 1000
+}
+
+interface CpuUsage {
+  user: number
+  system:number
+}
+
+interface CpuUsageAt {
+  usage:number
+  at:number // microseconds timestamp
+  elapsed:number // microseconds elapsed for this result
+}
+
+export class ProcessCpuProfiler {
+
+  private cumulatedUsage: CpuUsage
+  private startedAt:number // microseconds timestamp
+  private samples:CpuUsageAt[] = []
+
+  constructor(samplingPeriod = SAMPLING_PERIOD) {
+    // Initial state
+    const start = getMicrosecondsTime()
+    this.startedAt = start
+    this.cumulatedUsage = process.cpuUsage()
+    this.samples.push({ usage: 0, at: start, elapsed: 1 })
+    // Periodic sample
+    setInterval(() => {
+      const newSampleAt = getMicrosecondsTime()
+      const newUsage:CpuUsage = process.cpuUsage()
+      const elapsed = newSampleAt - this.lastSampleAt
+      const userDiff = newUsage.user - this.cumulatedUsage.user
+      const usagePercent = userDiff / elapsed // The percent of time consumed by the process since last sample
+      this.samples.push({ usage: usagePercent, at: newSampleAt, elapsed })
+      while(this.samplesDistance > MAX_SAMPLES_DISTANCE) {
+        this.samples.shift()
+      }
+      this.cumulatedUsage = newUsage
+      // console.log('Time elapsed: %s microseconds, = %s %CPU', elapsed, (usagePercent*100).toFixed(2))
+    }, samplingPeriod)
+  }
+
+  private get lastSampleAt() {
+    return this.samples[this.samples.length - 1].at
+  }
+
+  private get samplesDistance() {
+    return this.samples[this.samples.length - 1].at - this.samples[0].at
+  }
+
+  cpuUsageOverLastMilliseconds(elapsedMilliseconds:number) {
+    return this.cpuUsageOverLastX(elapsedMilliseconds * 1000)
+  }
+
+  private cpuUsageOverLastX(nbMicrosecondsElapsed:number) {
+    return this.getSamplesResult(getMicrosecondsTime() - nbMicrosecondsElapsed)
+  }
+
+  private getSamplesResult(minTimestamp:number) {
+    const matchingSamples = this.samples.filter(s => s.at >= minTimestamp - SAMPLING_PERIOD * 1000)
+    const cumulativeElapsed = matchingSamples.reduce((sum, s) => sum + s.elapsed, 0)
+    return matchingSamples.reduce((cumulated, percent) => {
+      const weight = percent.elapsed / cumulativeElapsed
+      return cumulated + percent.usage * weight
+    }, 0)
+  }
+}
\ No newline at end of file
diff --git a/app/cli.ts b/app/cli.ts
index 26accf24f158facb605808a72bfaec2dfc9f2abd..887724f418e72399566968f7c645c14fb0c2598d 100644
--- a/app/cli.ts
+++ b/app/cli.ts
@@ -1,7 +1,7 @@
 const Command = require('commander').Command;
 const pjson = require('../package.json');
 const duniter = require('../index');
-
+ 
 export const ExecuteCommand = () => {
 
   const options:any = [];
@@ -42,6 +42,7 @@ export const ExecuteCommand = () => {
         .option('--remep <endpoint>', 'With `config` command, remove given endpoint to the list of endpoints of this node')
 
         .option('--cpu <percent>', 'Percent of CPU usage for proof-of-work computation', parsePercent)
+        .option('--nb-cores <number>', 'Number of cores uses for proof-of-work computation', parseInt)
         .option('--prefix <nodeId>', 'Prefix node id for the first character of nonce', parseInt)
 
         .option('-c, --currency <name>', 'Name of the currency managed by this node.')
diff --git a/app/lib/common-libs/buid.ts b/app/lib/common-libs/buid.ts
index a0cc71b9cb7e910ddbe7c6aeb0b5de26f2c42198..3e2be9cb63f26cb8026f7beecd972d6cf581c674 100644
--- a/app/lib/common-libs/buid.ts
+++ b/app/lib/common-libs/buid.ts
@@ -28,5 +28,9 @@ export const Buid = {
     },
 
     buid: buidFunctions
+  },
+
+  getBlockstamp: (block:{ number:number, hash:string }) => {
+    return [block.number, block.hash].join('-')
   }
 };
diff --git a/app/lib/common-libs/constants.ts b/app/lib/common-libs/constants.ts
index f49c1fb3f1af6c89f0c47bf04b4c586747b5705f..b34cb6278407c8679b19c508cc6b86ce7f5473f2 100644
--- a/app/lib/common-libs/constants.ts
+++ b/app/lib/common-libs/constants.ts
@@ -33,7 +33,9 @@ const CONDITIONS   = "(&&|\\|\\|| |[()]|(SIG\\(" + PUBKEY + "\\)|(XHX\\([A-F0-9]
 const BMA_REGEXP  = /^BASIC_MERKLED_API( ([a-z_][a-z0-9-_.]*))?( ([0-9.]+))?( ([0-9a-f:]+))?( ([0-9]+))$/
 const BMATOR_REGEXP = /^BMATOR( ([a-z0-9]{16})\.onion)( ([0-9.]+))?( ([0-9a-f:]+))?( ([0-9]+))$/
 const WS2P_REGEXP = /^WS2P (?:[1-9][0-9]* )?([a-f0-9]{8}) ([a-z_][a-z0-9-_.]*|[0-9.]+|[0-9a-f:]+) ([0-9]+)(?: (.+))?$/
+const WS2P_V2_REGEXP = /^WS2P ([1-9][0-9]*) ([a-f0-9]{8}) ([a-z_][a-z0-9-_.]*|[0-9.]+|[0-9a-f:]+) ([0-9]+)(?: (.+))?$/
 const WS2PTOR_REGEXP = /^WS2PTOR (?:[1-9][0-9]* )?([a-f0-9]{8}) ([a-z0-9-_.]*|[0-9.]+|[0-9a-f:]+.onion) ([0-9]+)(?: (.+))?$/
+const WS2PTOR_V2_REGEXP = /^WS2PTOR ([1-9][0-9]*) ([a-f0-9]{8}) ([a-z0-9-_.]*|[0-9.]+|[0-9a-f:]+.onion) ([0-9]+)(?: (.+))?$/
 const WS_FULL_ADDRESS_ONION_REGEX = /^(?:wss?:\/\/)(?:www\.)?([0-9a-z]{16}\.onion)(:[0-9]+)?$/
 const IPV4_REGEXP = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/;
 const IPV6_REGEXP = /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b).){3}(b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b))|(([0-9A-Fa-f]{1,4}:){0,5}:((b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b).){3}(b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b))|(::([0-9A-Fa-f]{1,4}:){0,5}((b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b).){3}(b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/;
@@ -81,7 +83,8 @@ export const CommonConstants = {
     SOFTWARE,
     SOFT_VERSION,
     POW_PREFIX,
-    ZERO_OR_POSITIVE_INT
+    ZERO_OR_POSITIVE_INT,
+    SIGNATURE
   },
 
   BLOCK_GENERATED_VERSION: 10,
@@ -95,7 +98,9 @@ export const CommonConstants = {
   BMA_REGEXP,
   BMATOR_REGEXP,
   WS2P_REGEXP,
+  WS2P_V2_REGEXP,
   WS2PTOR_REGEXP,
+  WS2PTOR_V2_REGEXP,
   WS_FULL_ADDRESS_ONION_REGEX,
   IPV4_REGEXP,
   IPV6_REGEXP,
diff --git a/app/lib/computation/QuickSync.ts b/app/lib/computation/QuickSync.ts
index ccdeac10a1f5955744d21a5359557d069fe722e1..db385418a5d7a2e52a6609cc4aa7da8b4de29607 100644
--- a/app/lib/computation/QuickSync.ts
+++ b/app/lib/computation/QuickSync.ts
@@ -126,8 +126,11 @@ export class QuickSynchronizer {
 
         // Remember expiration dates
         for (const entry of index) {
-          if (entry.expires_on || entry.revokes_on) {
-            sync_expires.push(entry.expires_on || entry.revokes_on);
+          if (entry.expires_on) {
+            sync_expires.push(entry.expires_on)
+          }
+          if (entry.revokes_on) {
+            sync_expires.push(entry.revokes_on)
           }
         }
         sync_expires = _.uniq(sync_expires);
@@ -151,8 +154,8 @@ export class QuickSynchronizer {
               i--;
             }
           }
-          let currentNextExpiring = sync_nextExpiring
-          sync_nextExpiring = sync_expires.reduce((max, value) => max ? Math.min(max, value) : value, sync_nextExpiring);
+          const currentNextExpiring = sync_nextExpiring
+          sync_nextExpiring = sync_expires.reduce((max, value) => max ? Math.min(max, value) : value, 9007199254740991); // Far far away date
           const nextExpiringChanged = currentNextExpiring !== sync_nextExpiring
 
           // Fills in correctly the SINDEX
diff --git a/app/lib/constants.ts b/app/lib/constants.ts
index 26180e81d5fb6efe6799f0096f9a914b0091d885..6de53d349a025efb22f3be7cc62ecb497e2a7385 100644
--- a/app/lib/constants.ts
+++ b/app/lib/constants.ts
@@ -1,6 +1,7 @@
 "use strict";
 import {CommonConstants} from "./common-libs/constants"
 import {OtherConstants} from "./other_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
@@ -114,7 +115,11 @@ module.exports = {
   },
   PROOF_OF_WORK: {
     EVALUATION: 1000,
-    UPPER_BOUND: CommonConstants.PROOF_OF_WORK.UPPER_BOUND.slice()
+    UPPER_BOUND: CommonConstants.PROOF_OF_WORK.UPPER_BOUND.slice(),
+    DEFAULT: {
+      CPU: ProverConstants.DEFAULT_CPU,
+      PREFIX: ProverConstants.DEFAULT_PEER_ID
+    }
   },
 
   DEFAULT_CURRENCY_NAME: "no_currency",
diff --git a/app/lib/dal/fileDAL.ts b/app/lib/dal/fileDAL.ts
index db28e72c5f3f3721e7247116a87a624fc6575974..e7f5794ead30ca5aae57501f89fd9a441f5b5e6c 100644
--- a/app/lib/dal/fileDAL.ts
+++ b/app/lib/dal/fileDAL.ts
@@ -503,13 +503,13 @@ export class FileDAL {
     return this.sindexDAL.getSource(identifier, pos)
   }
 
-  async isMember(pubkey:string) {
+  async isMember(pubkey:string):Promise<boolean> {
     try {
       const idty = await this.iindexDAL.getFromPubkey(pubkey);
-      if (!idty) {
+      if (idty === null) {
         return false
       }
-      return idty.member;
+      return true;
     } catch (err) {
       return false;
     }
@@ -759,7 +759,7 @@ export class FileDAL {
   }
 
   saveTransaction(tx:DBTx) {
-    return this.txsDAL.addPending(TransactionDTO.fromJSONObject(tx))
+    return this.txsDAL.addPending(tx)
   }
 
   async getTransactionsHistory(pubkey:string) {
diff --git a/app/lib/dal/sqliteDAL/CertDAL.ts b/app/lib/dal/sqliteDAL/CertDAL.ts
index d854ef16b44668efdd2fbefa75c4f676a2b2b122..d12774e5721706c8756f6e9c29a9101ac1cd9680 100644
--- a/app/lib/dal/sqliteDAL/CertDAL.ts
+++ b/app/lib/dal/sqliteDAL/CertDAL.ts
@@ -1,10 +1,11 @@
 import {SQLiteDriver} from "../drivers/SQLiteDriver"
 import {AbstractSQLite} from "./AbstractSQLite"
-import {SandBox} from "./SandBox"
+import { SandBox } from './SandBox';
+import { DBDocument } from './DocumentDAL';
 
 const constants = require('../../constants');
 
-export interface DBCert {
+export interface DBCert extends DBDocument {
   linked:boolean
   written:boolean
   written_block:null
diff --git a/app/lib/dal/sqliteDAL/DocumentDAL.ts b/app/lib/dal/sqliteDAL/DocumentDAL.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e5ce3c562c98d6f3830523d06a1b9fe67eb846b8
--- /dev/null
+++ b/app/lib/dal/sqliteDAL/DocumentDAL.ts
@@ -0,0 +1,3 @@
+export interface DBDocument {
+  issuers: string[]
+}
\ No newline at end of file
diff --git a/app/lib/dal/sqliteDAL/IdentityDAL.ts b/app/lib/dal/sqliteDAL/IdentityDAL.ts
index c23f6be99df73a7d0ba3a8efb07e283a2acd7cfb..364eb00cd1e822b82e0c590a491154a160641a11 100644
--- a/app/lib/dal/sqliteDAL/IdentityDAL.ts
+++ b/app/lib/dal/sqliteDAL/IdentityDAL.ts
@@ -1,8 +1,9 @@
 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';
 const constants = require('../../constants');
 
 export abstract class DBIdentity implements Cloneable {
@@ -143,7 +144,7 @@ export class ExistingDBIdentity extends DBIdentity {
   }
 }
 
-export interface DBSandboxIdentity extends DBIdentity {
+export interface DBSandboxIdentity extends DBIdentity,DBDocument {
   certsCount: number
   ref_block: number
 }
diff --git a/app/lib/dal/sqliteDAL/MembershipDAL.ts b/app/lib/dal/sqliteDAL/MembershipDAL.ts
index 61ce346e9f9580716d482edd346caf0e7bd3f864..110ed1429ef627d114a54b2937d09396d92c0416 100644
--- a/app/lib/dal/sqliteDAL/MembershipDAL.ts
+++ b/app/lib/dal/sqliteDAL/MembershipDAL.ts
@@ -1,10 +1,11 @@
 import {SQLiteDriver} from "../drivers/SQLiteDriver";
 import {AbstractSQLite} from "./AbstractSQLite";
-import {SandBox} from "./SandBox";
+import { SandBox } from './SandBox';
+import { DBDocument } from './DocumentDAL';
 const _ = require('underscore');
 const constants = require('../../constants');
 
-export interface DBMembership {
+export interface DBMembership extends DBDocument {
   membership: string
   issuer: string
   number: number
diff --git a/app/lib/dal/sqliteDAL/SandBox.ts b/app/lib/dal/sqliteDAL/SandBox.ts
index c84f9a87fdd1f78ec24ade5dde70d001a536dd84..d8e9f3d96c7fa07438baf8cca9b117a549f63232 100644
--- a/app/lib/dal/sqliteDAL/SandBox.ts
+++ b/app/lib/dal/sqliteDAL/SandBox.ts
@@ -1,4 +1,6 @@
-export class SandBox<T> {
+import {DBDocument} from './DocumentDAL';
+
+export class SandBox<T extends DBDocument> {
 
   maxSize:number
   
@@ -10,8 +12,9 @@ export class SandBox<T> {
     this.maxSize = maxSize || 10
   }
   
-  async acceptNewSandBoxEntry(element:any, pubkey:string) {
-    if (element.pubkey === pubkey) {
+  async acceptNewSandBoxEntry(element:T, pubkey:string) {
+    // Accept any document which has the exception pubkey (= the node pubkey)
+    if (element.issuers.indexOf(pubkey) !== -1) {
       return true;
     }
     const elements = await this.findElements()
diff --git a/app/lib/dal/sqliteDAL/TxsDAL.ts b/app/lib/dal/sqliteDAL/TxsDAL.ts
index b6330cb934f2f89f89554d6bca7443d0c7fa2bc3..dbc82ca99d71528ad6fb65580a21d12318ef574d 100644
--- a/app/lib/dal/sqliteDAL/TxsDAL.ts
+++ b/app/lib/dal/sqliteDAL/TxsDAL.ts
@@ -169,12 +169,10 @@ export class TxsDAL extends AbstractSQLite<DBTx> {
     return this.saveEntity(dbTx)
   }
 
-  addPending(tx:TransactionDTO) {
-    const dbTx = DBTx.fromTransactionDTO(tx)
+  addPending(dbTx:DBTx) {
     dbTx.received = moment().unix()
     dbTx.written = false
     dbTx.removed = false
-    dbTx.hash = tx.getHash()
     return this.saveEntity(dbTx)
   }
 
diff --git a/app/lib/dto/ConfDTO.ts b/app/lib/dto/ConfDTO.ts
index 2614318afcc81c1d2be8a4ce96929ac110932c34..2e77e92fc70336c82b99bbb7b908ee9251918d09 100644
--- a/app/lib/dto/ConfDTO.ts
+++ b/app/lib/dto/ConfDTO.ts
@@ -64,9 +64,9 @@ export interface NetworkConfDTO {
 
 export interface WS2PConfDTO {
   ws2p?: {
-    privateAccess: boolean
-    publicAccess: boolean
-    uuid: string
+    privateAccess?: boolean
+    publicAccess?: boolean
+    uuid?: string
     upnp?: boolean
     remotehost?: string|null
     remoteport?: number|null
@@ -131,6 +131,7 @@ export class ConfDTO implements CurrencyConfDTO, KeypairConfDTO, NetworkConfDTO,
     public remotehost: string|null,
     public remoteipv4: string|null,
     public remoteipv6: string|null,
+    public host: string,
     public port: number,
     public ipv4: string,
     public ipv6: string,
@@ -142,9 +143,9 @@ export class ConfDTO implements CurrencyConfDTO, KeypairConfDTO, NetworkConfDTO,
     public bmaWithCrawler: boolean,
     public proxiesConf: ProxiesConf|undefined,
     public ws2p?: {
-      privateAccess: boolean
-      publicAccess: boolean
-      uuid: string
+      privateAccess?: boolean
+      publicAccess?: boolean
+      uuid?: string
       upnp?: boolean
       remotehost?: string|null
       remoteport?: number|null
@@ -161,10 +162,11 @@ export class ConfDTO implements CurrencyConfDTO, KeypairConfDTO, NetworkConfDTO,
 ) {}
 
   static mock() {
-    return new ConfDTO("", "", [], [], 0, 0, 0.6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, 0, false, 0, 0, 0, 0, 0, { pub:'', sec:'' }, null, "", "", 0, "", "", "", 0, "", "", null, false, "", true, false, true, undefined)
+    return new ConfDTO("", "", [], [], 0, 3600 * 1000, constants.PROOF_OF_WORK.DEFAULT.CPU, 1, constants.PROOF_OF_WORK.DEFAULT.PREFIX, 0, 0, constants.CONTRACT.DEFAULT.C, constants.CONTRACT.DEFAULT.DT, constants.CONTRACT.DEFAULT.DT_REEVAL, 0, constants.CONTRACT.DEFAULT.UD0, 0, 0, constants.CONTRACT.DEFAULT.STEPMAX, constants.CONTRACT.DEFAULT.SIGPERIOD, 0, constants.CONTRACT.DEFAULT.SIGVALIDITY, constants.CONTRACT.DEFAULT.MSVALIDITY, constants.CONTRACT.DEFAULT.SIGQTY, constants.CONTRACT.DEFAULT.SIGSTOCK, constants.CONTRACT.DEFAULT.X_PERCENT, constants.CONTRACT.DEFAULT.PERCENTROT, constants.CONTRACT.DEFAULT.POWDELAY, constants.CONTRACT.DEFAULT.AVGGENTIME, constants.CONTRACT.DEFAULT.MEDIANTIMEBLOCKS, false, 3000, false, constants.BRANCHES.DEFAULT_WINDOW_SIZE, constants.CONTRACT.DEFAULT.IDTYWINDOW, constants.CONTRACT.DEFAULT.MSWINDOW, constants.CONTRACT.DEFAULT.SIGWINDOW, 0, { pub:'', sec:'' }, null, "", "", 0, "", "", "", "", 0, "", "", null, false, "", true, true, false, new ProxiesConf(), undefined)
   }
 
   static defaultConf() {
+    /*return new ConfDTO("", "", [], [], 0, 3600 * 1000, constants.PROOF_OF_WORK.DEFAULT.CPU, 1, constants.PROOF_OF_WORK.DEFAULT.PREFIX, 0, 0, constants.CONTRACT.DEFAULT.C, constants.CONTRACT.DEFAULT.DT, constants.CONTRACT.DEFAULT.DT_REEVAL, 0, constants.CONTRACT.DEFAULT.UD0, 0, 0, constants.CONTRACT.DEFAULT.STEPMAX, constants.CONTRACT.DEFAULT.SIGPERIOD, 0, constants.CONTRACT.DEFAULT.SIGVALIDITY, constants.CONTRACT.DEFAULT.MSVALIDITY, constants.CONTRACT.DEFAULT.SIGQTY, constants.CONTRACT.DEFAULT.SIGSTOCK, constants.CONTRACT.DEFAULT.X_PERCENT, constants.CONTRACT.DEFAULT.PERCENTROT, constants.CONTRACT.DEFAULT.POWDELAY, constants.CONTRACT.DEFAULT.AVGGENTIME, constants.CONTRACT.DEFAULT.MEDIANTIMEBLOCKS, false, 3000, false, constants.BRANCHES.DEFAULT_WINDOW_SIZE, constants.CONTRACT.DEFAULT.IDTYWINDOW, constants.CONTRACT.DEFAULT.MSWINDOW, constants.CONTRACT.DEFAULT.SIGWINDOW, 0, { pub:'', sec:'' }, null, "", "", 0, "", "", "", "", 0, "", "", null, false, "", true, true)*/
     return {
       "currency": null,
       "endpoints": [],
diff --git a/app/lib/dto/IdentityDTO.ts b/app/lib/dto/IdentityDTO.ts
index d185d0ccf4fcdb54d553cff1e95febd9b9055780..5bf4a81c6a3975b86dfee715fe28b3a70701bfcc 100644
--- a/app/lib/dto/IdentityDTO.ts
+++ b/app/lib/dto/IdentityDTO.ts
@@ -1,6 +1,7 @@
 import {RevocationDTO} from "./RevocationDTO"
 import {hashf} from "../common"
 import {DBIdentity, NewDBIdentity} from "../dal/sqliteDAL/IdentityDAL"
+
 const DEFAULT_DOCUMENT_VERSION = 10
 
 export interface HashableIdentity {
@@ -50,6 +51,10 @@ export class IdentityDTO {
     return raw
   }
 
+  getRawUnSigned() {
+    return this.rawWithoutSig()
+  }
+
   getRawSigned() {
     return this.rawWithoutSig() + this.sig + "\n"
   }
diff --git a/app/lib/dto/PeerDTO.ts b/app/lib/dto/PeerDTO.ts
index dc5754b6893349a0009b66e1cbb21c78d7b116a7..4b9555bfc617bb4ceff21c2c4ef2104f4ae97cb5 100644
--- a/app/lib/dto/PeerDTO.ts
+++ b/app/lib/dto/PeerDTO.ts
@@ -2,11 +2,14 @@ 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';
 
 export interface WS2PEndpoint {
+  version:number
   uuid:string
   host:string
   port:number
+  path:string
 }
 
 export class PeerDTO implements Cloneable {
@@ -94,29 +97,59 @@ export class PeerDTO implements Cloneable {
     return bma || {};
   }
 
-  getWS2P(canReachTorEp:boolean, canReachClearEp:boolean) {
-    let api:{ uuid:string, host:string, port:number, path:string }|null = null
-    const endpointRegexp = (canReachTorEp) ? CommonConstants.WS2PTOR_REGEXP:CommonConstants.WS2P_REGEXP
+  getOnceWS2PEndpoint(canReachTorEp:boolean, canReachClearEp:boolean, uuidExcluded:string[] = []) {
+    let api:WS2PEndpoint|null = null
+    let bestWS2PVersionAvailable:number = 0
+    let bestWS2PTORVersionAvailable:number = 0
     for (const ep of this.endpoints) {
       if (canReachTorEp) {
-        const matches:any = ep.match(CommonConstants.WS2PTOR_REGEXP)
-        if (matches) {
-          return {
-            uuid: matches[1],
-            host: matches[2] || '',
-            port: parseInt(matches[3]) || 0,
-            path: matches[4]
+        let matches:RegExpMatchArray | null = ep.match(CommonConstants.WS2PTOR_V2_REGEXP)
+        if (matches && parseInt(matches[1]) > bestWS2PTORVersionAvailable && (uuidExcluded.indexOf(matches[2]) === -1)) {
+          bestWS2PTORVersionAvailable = parseInt(matches[1])
+          api = {
+            version: parseInt(matches[1]),
+            uuid: matches[2],
+            host: matches[3] || '',
+            port: parseInt(matches[4]) || 0,
+            path: matches[5]
+          }
+        } else {
+          matches = ep.match(CommonConstants.WS2PTOR_REGEXP)
+          if (matches && bestWS2PTORVersionAvailable == 0 && (uuidExcluded.indexOf(matches[1]) === -1)) {
+            bestWS2PTORVersionAvailable = 1
+            api = {
+              version: 1,
+              uuid: matches[1],
+              host: matches[2] || '',
+              port: parseInt(matches[3]) || 0,
+              path: matches[4]
+            }
           }
         }
       }
-      if (canReachClearEp) {
-        const matches:any = !api && ep.match(CommonConstants.WS2P_REGEXP)
-        if (matches) {
+      // If can reach clear endpoint and not found tor endpoint
+      if (canReachClearEp && bestWS2PTORVersionAvailable == 0) {
+        let matches:any = ep.match(CommonConstants.WS2P_V2_REGEXP)
+        if (matches && parseInt(matches[1]) > bestWS2PVersionAvailable && (uuidExcluded.indexOf(matches[2]) === -1)) {
+          bestWS2PVersionAvailable = parseInt(matches[1])
           api = {
-            uuid: matches[1],
-            host: matches[2] || '',
-            port: parseInt(matches[3]) || 0,
-            path: matches[4]
+            version: parseInt(matches[1]),
+            uuid: matches[2],
+            host: matches[3] || '',
+            port: parseInt(matches[4]) || 0,
+            path: matches[5]
+          }
+        } else {
+          matches = ep.match(CommonConstants.WS2P_REGEXP)
+          if (matches && bestWS2PVersionAvailable == 0 && (uuidExcluded.indexOf(matches[1]) === -1)) {
+            bestWS2PVersionAvailable = 1
+            api = {
+              version: 1,
+              uuid: matches[1],
+              host: matches[2] || '',
+              port: parseInt(matches[3]) || 0,
+              path: matches[4]
+            }
           }
         }
       }
@@ -124,6 +157,18 @@ export class PeerDTO implements Cloneable {
     return api || null
   }
 
+  getAllWS2PEndpoints(canReachTorEp:boolean, canReachClearEp:boolean, myUUID:string) {
+    let apis:WS2PEndpoint[] = []
+    let uuidExcluded:string[] = [myUUID]
+    let api = this.getOnceWS2PEndpoint(canReachTorEp, canReachClearEp, uuidExcluded)
+    while (api !== null) {
+      uuidExcluded.push(api.uuid)
+      apis.push(api)
+      api = this.getOnceWS2PEndpoint(canReachTorEp, canReachClearEp, uuidExcluded)
+    }
+    return apis
+  }
+
   getDns() {
     const bma = this.getBMA();
     return bma.dns ? bma.dns : null;
diff --git a/app/lib/dto/RevocationDTO.ts b/app/lib/dto/RevocationDTO.ts
index ae8801e856119a790a2a721744d3ee9eb6b4ac92..f98d75b63f09c75ed5c383a4e28cdb8492cbf1dc 100644
--- a/app/lib/dto/RevocationDTO.ts
+++ b/app/lib/dto/RevocationDTO.ts
@@ -1,5 +1,6 @@
 import {Cloneable} from "./Cloneable";
 import {hashf} from "../common";
+
 const DEFAULT_DOCUMENT_VERSION = 10
 
 export interface ShortRevocation {
@@ -39,6 +40,10 @@ export class RevocationDTO implements ShortRevocation, Cloneable {
     return this.rawWithoutSig() + this.revocation + "\n"
   }
 
+  getRawUnsigned() {
+    return this.rawWithoutSig()
+  }
+
   // TODO: to remove when BMA has been merged in duniter/duniter repo
   json() {
     return {
diff --git a/app/modules/prover/index.ts b/app/modules/prover/index.ts
index 7bdd83464fbadb89784356ce724eb13ff643e0eb..856e1423761bde02af8b9da064ffb307c0b65d18 100644
--- a/app/modules/prover/index.ts
+++ b/app/modules/prover/index.ts
@@ -1,6 +1,6 @@
 import {ConfDTO} from "../../lib/dto/ConfDTO"
 import {BlockGenerator, BlockGeneratorWhichProves} from "./lib/blockGenerator"
-import {Constants} from "./lib/constants"
+import {ProverConstants} from "./lib/constants"
 import {BlockProver} from "./lib/blockProver"
 import {Prover} from "./lib/prover"
 import {Contacter} from "../crawler/lib/contacter"
@@ -19,13 +19,18 @@ export const ProverDependency = {
     config: {
       onLoading: async (conf:ConfDTO) => {
         if (conf.cpu === null || conf.cpu === undefined) {
-          conf.cpu = Constants.DEFAULT_CPU;
+          conf.cpu = ProverConstants.DEFAULT_CPU;
+        }
+        if (conf.nbCores === null || conf.nbCores === undefined) {
+          conf.nbCores = Math.min(ProverConstants.CORES_MAXIMUM_USE_IN_PARALLEL, require('os').cpus().length)
+        } else if (conf.nbCores <= 0) {
+          conf.nbCores = 1
         }
         if (conf.prefix === null || conf.prefix === undefined) {
-          conf.prefix = Constants.DEFAULT_PEER_ID;
+          conf.prefix = ProverConstants.DEFAULT_PEER_ID;
         }
-        conf.powSecurityRetryDelay = Constants.POW_SECURITY_RETRY_DELAY;
-        conf.powMaxHandicap = Constants.POW_MAXIMUM_ACCEPTABLE_HANDICAP;
+        conf.powSecurityRetryDelay = ProverConstants.POW_SECURITY_RETRY_DELAY;
+        conf.powMaxHandicap = ProverConstants.POW_MAXIMUM_ACCEPTABLE_HANDICAP;
       },
       beforeSave: async (conf:ConfDTO) => {
         delete conf.powSecurityRetryDelay;
diff --git a/app/modules/prover/lib/blockProver.ts b/app/modules/prover/lib/blockProver.ts
index 1c68518f7947d2fd0eb71c009488eec5250b02ae..9cd215d98d478a456857b52f9f5c5388e1afa153 100644
--- a/app/modules/prover/lib/blockProver.ts
+++ b/app/modules/prover/lib/blockProver.ts
@@ -1,4 +1,4 @@
-import {Constants} from "./constants"
+import {ProverConstants} from "./constants"
 import {Server} from "../../../../server"
 import {PowEngine} from "./engine"
 import {DBBlock} from "../../../lib/db/DBBlock"
@@ -165,7 +165,7 @@ export class BlockProver {
       // Start
       powFarm.setOnAlmostPoW((pow:any, matches:any, aBlock:any, found:boolean) => {
         this.powEvent(found, pow);
-        if (matches && matches[1].length >= Constants.MINIMAL_ZEROS_TO_SHOW_IN_LOGS) {
+        if (matches && matches[1].length >= ProverConstants.MINIMAL_ZEROS_TO_SHOW_IN_LOGS) {
           this.logger.info('Matched %s zeros %s with Nonce = %s for block#%s by %s', matches[1].length, pow, aBlock.nonce, aBlock.number, aBlock.issuer.slice(0,6));
         }
       });
diff --git a/app/modules/prover/lib/constants.ts b/app/modules/prover/lib/constants.ts
index 0602e7de87009833c41fccff032fd1c6b9d8e137..0a454d38fd9c85e58115c2f971bbb6cb1cea812e 100644
--- a/app/modules/prover/lib/constants.ts
+++ b/app/modules/prover/lib/constants.ts
@@ -1,4 +1,4 @@
-export const Constants = {
+export const ProverConstants = {
 
   CORES_MAXIMUM_USE_IN_PARALLEL: 8,
 
diff --git a/app/modules/prover/lib/engine.ts b/app/modules/prover/lib/engine.ts
index 12d2751d6c45f522027ce96c88de942cd9f0c62a..cc83f46822764786bf91c1c02156c597966cc299 100644
--- a/app/modules/prover/lib/engine.ts
+++ b/app/modules/prover/lib/engine.ts
@@ -1,4 +1,4 @@
-import {Constants} from "./constants"
+import {ProverConstants} from "./constants"
 import {Master as PowCluster} from "./powCluster"
 import {ConfDTO} from "../../../lib/dto/ConfDTO"
 
@@ -20,7 +20,7 @@ export class PowEngine {
   constructor(private conf:ConfDTO, logger:any) {
 
     // We use as much cores as available, but not more than CORES_MAXIMUM_USE_IN_PARALLEL
-    this.nbWorkers = (conf && conf.nbCores) || Math.min(Constants.CORES_MAXIMUM_USE_IN_PARALLEL, require('os').cpus().length)
+    this.nbWorkers = conf.nbCores
     this.cluster = new PowCluster(this.nbWorkers, logger)
     this.id = this.cluster.clusterId
   }
@@ -35,8 +35,10 @@ export class PowEngine {
       await this.cluster.cancelWork()
     }
 
-    if (os.arch().match(/arm/)) {
-      stuff.newPoW.conf.cpu /= 2; // Don't know exactly why is ARM so much saturated by PoW, so let's divide by 2
+    const cpus = os.cpus()
+
+    if (os.arch().match(/arm/) || cpus[0].model.match(/Atom/)) {
+      stuff.newPoW.conf.nbCores /= 2; // Make sure that only once each physical core is used (for Hyperthreading).
     }
     return await this.cluster.proveByWorkers(stuff)
   }
diff --git a/app/modules/prover/lib/powCluster.ts b/app/modules/prover/lib/powCluster.ts
index 1e1a6ad3d42afadf5c750a378426d8e7ab50df70..4d4820777cb9b279aebea2d09680d1be0b3aab1f 100644
--- a/app/modules/prover/lib/powCluster.ts
+++ b/app/modules/prover/lib/powCluster.ts
@@ -1,5 +1,5 @@
 import {ConfDTO} from "../../../lib/dto/ConfDTO"
-import {Constants} from "./constants"
+import {ProverConstants} from "./constants"
 
 const _ = require('underscore')
 const nuuid = require('node-uuid');
@@ -84,7 +84,7 @@ export class Master {
         })(),
 
         // Each worker has his own chunk of possible nonces
-        nonceBeginning: this.nbCores === 1 ? 0 : (index + 1) * Constants.NONCE_RANGE
+        nonceBeginning: this.nbCores === 1 ? 0 : (index + 1) * ProverConstants.NONCE_RANGE
       }
       return this.slavesMap[worker.id]
     })
diff --git a/app/modules/prover/lib/proof.ts b/app/modules/prover/lib/proof.ts
index cc60a584fec95dae212da94306d05c828ffcff1a..9b15c0be5aaff08b078c5dd495dbb0432be983ea 100644
--- a/app/modules/prover/lib/proof.ts
+++ b/app/modules/prover/lib/proof.ts
@@ -2,7 +2,7 @@ import {LOCAL_RULES_HELPERS} from "../../../lib/rules/local_rules"
 import {hashf} from "../../../lib/common"
 import {DBBlock} from "../../../lib/db/DBBlock"
 import {ConfDTO} from "../../../lib/dto/ConfDTO"
-import {Constants} from "./constants"
+import {ProverConstants} from "./constants"
 import {KeyGen} from "../../../lib/common-libs/crypto/keyring"
 import {dos2unix} from "../../../lib/common-libs/dos2unix"
 import {rawer} from "../../../lib/common-libs/index"
@@ -84,10 +84,10 @@ function beginNewProofOfWork(stuff:any) {
     const nbZeros = stuff.zeros;
     const pair = stuff.pair;
     const forcedTime = stuff.forcedTime;
-    currentCPU = conf.cpu || Constants.DEFAULT_CPU;
+    currentCPU = conf.cpu || ProverConstants.DEFAULT_CPU;
     prefix = parseInt(conf.prefix || prefix)
-    if (prefix && prefix < Constants.NONCE_RANGE) {
-      prefix *= 100 * Constants.NONCE_RANGE
+    if (prefix && prefix < ProverConstants.NONCE_RANGE) {
+      prefix *= 100 * ProverConstants.NONCE_RANGE
     }
     const highMark = stuff.highMark;
     const turnDuration = stuff.turnDuration || TURN_DURATION_IN_MILLISEC
@@ -184,7 +184,7 @@ function beginNewProofOfWork(stuff:any) {
             if (charOK) {
               found = !!(pow[nbZeros].match(new RegExp('[0-' + highMark + ']')))
             }
-            if (!found && nbZeros > 0 && j - 1 >= Constants.POW_MINIMAL_TO_SHOW) {
+            if (!found && nbZeros > 0 && j - 1 >= ProverConstants.POW_MINIMAL_TO_SHOW) {
               pSend({ pow: { pow: pow, block: block, nbZeros: nbZeros }});
             }
 
diff --git a/app/modules/ws2p/lib/WS2PClient.ts b/app/modules/ws2p/lib/WS2PClient.ts
index 569609f6e1c06bbdef4b7c8c9fadfcf48569972c..af885353d0a0afe5f573cd5322dcced2b2f1a638 100644
--- a/app/modules/ws2p/lib/WS2PClient.ts
+++ b/app/modules/ws2p/lib/WS2PClient.ts
@@ -13,19 +13,22 @@ export class WS2PClient {
 
   private constructor(public connection:WS2PConnection) {}
 
-  static async connectTo(server:Server, fullEndpointAddress:string, uuid:string, messageHandler:WS2PMessageHandler, expectedPub:string, allowKey:(pub:string)=>Promise<boolean> ) {
+  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)
+    const myWs2pId = (server.conf.ws2p && server.conf.ws2p.uuid) ? server.conf.ws2p.uuid:""
     const c = WS2PConnection.newConnectionToAddress(
+      Math.min(endpointVersion, WS2PConstants.WS2P_API_VERSION),
       fullEndpointAddress,
       messageHandler,
-      new WS2PPubkeyLocalAuth(server.conf.currency , k2, allowKey),
+      new WS2PPubkeyLocalAuth(server.conf.currency , k2, myWs2pId, allowKey),
       new WS2PPubkeyRemoteAuth(server.conf.currency, k2, allowKey),
       ProxiesConf.wsProxy(fullEndpointAddress, server.conf.proxiesConf),
       {
         connectionTimeout: WS2PConstants.REQUEST_TIMEOUT,
         requestTimeout: WS2PConstants.REQUEST_TIMEOUT
       },
-      expectedPub
+      expectedPub,
+      expectedWS2PUID
     )
     const singleWriteProtection = new WS2PSingleWriteStream()
     const streamer = new WS2PStreamer(c)
diff --git a/app/modules/ws2p/lib/WS2PCluster.ts b/app/modules/ws2p/lib/WS2PCluster.ts
index 0ce2fa0983f4b3ca873906ba718f1ebee3d11c61..bf5ac43a5574cb698c86c760e0b9c6d67c09ce8b 100644
--- a/app/modules/ws2p/lib/WS2PCluster.ts
+++ b/app/modules/ws2p/lib/WS2PCluster.ts
@@ -1,3 +1,4 @@
+import { DEFAULT_ENCODING } from 'crypto';
 import {WS2PServer} from "./WS2PServer"
 import {Server} from "../../../../server"
 import {WS2PClient} from "./WS2PClient"
@@ -7,7 +8,7 @@ import {CrawlerConstants} from "../../crawler/lib/constants"
 import {WS2PBlockPuller} from "./WS2PBlockPuller"
 import {WS2PDocpoolPuller} from "./WS2PDocpoolPuller"
 import {WS2PConstants} from "./constants"
-import {PeerDTO} from "../../../lib/dto/PeerDTO"
+import { PeerDTO, WS2PEndpoint } from '../../../lib/dto/PeerDTO';
 import {GlobalFifoPromise} from "../../../service/GlobalFifoPromise"
 import {OtherConstants} from "../../../lib/other_constants"
 import {Key, verify} from "../../../lib/common-libs/crypto/keyring"
@@ -15,7 +16,7 @@ import {WS2PServerMessageHandler} from "./interface/WS2PServerMessageHandler"
 import {WS2PMessageHandler} from "./impl/WS2PMessageHandler"
 import {CommonConstants} from '../../../lib/common-libs/constants';
 import {Package} from "../../../lib/common/package";
-import {Constants} from "../../prover/lib/constants";
+import {ProverConstants} from "../../prover/lib/constants";
 import {ProxiesConf} from '../../../lib/proxy';
 
 const es = require('event-stream')
@@ -25,6 +26,8 @@ const _ = require('underscore')
 export interface WS2PHead {
   message:string
   sig:string
+  messageV2?:string
+  sigV2?:string
   step?:number
 }
 
@@ -56,7 +59,7 @@ export class WS2PCluster {
   }
 
   private ws2pServer:WS2PServer|null = null
-  private ws2pClients:{[k:string]:WS2PClient} = {}
+  private ws2pClients:{[ws2puid:string]:WS2PClient} = {}
   private host:string|null = null
   private port:number|null = null
   private syncBlockInterval:NodeJS.Timer
@@ -98,116 +101,120 @@ export class WS2PCluster {
     const heads:WS2PHead[] = []
     const ws2pId = (this.server.conf.ws2p && this.server.conf.ws2p.uuid) || '000000'
     const localPub = this.server.conf.pair.pub
-    const fullId = [localPub, ws2pId].join('-')
-    if (!this.headsCache[fullId]) {
+    const myFullId = [localPub, ws2pId].join('-')
+    if (!this.headsCache[myFullId]) {
       const current = await this.server.dal.getCurrentBlockOrNull()
       if (current) {
-        const { sig, message } = this.sayHeadChangedTo(current.number, current.hash)
+        const myHead = await this.sayHeadChangedTo(current.number, current.hash)
         const blockstamp = [current.number, current.hash].join('-')
-        this.headsCache[fullId] = { blockstamp, message, sig }
+        this.headsCache[myFullId] = { blockstamp, message: myHead.message, sig: myHead.sig, messageV2: myHead.messageV2, sigV2: myHead.sigV2, step:myHead.step  }
+
       }
     }
     for (const ws2pFullId of Object.keys(this.headsCache)) {
       heads.push({
         message: this.headsCache[ws2pFullId].message,
-        sig: this.headsCache[ws2pFullId].sig
+        sig: this.headsCache[ws2pFullId].sig,
+        messageV2: this.headsCache[ws2pFullId].messageV2,
+        sigV2: this.headsCache[ws2pFullId].sigV2,
+        step: this.headsCache[ws2pFullId].step
       })
     }
     return heads
   }
 
   async headsReceived(heads:WS2PHead[]) {
-    const added:WS2PHead[] = []
     await Promise.all(heads.map(async (h:WS2PHead) => {
       try {
-        const step = (h.step !== undefined) ? h.step:undefined 
-        const message = h.message
-        const sig = h.sig
-        if (!message) {
-          throw "EMPTY_MESSAGE_FOR_HEAD"
-        }
-        if (message.match(WS2PConstants.HEAD_V0_REGEXP)) {
-          const [,, pub, blockstamp]:string[] = message.split(':')
-          const ws2pId = (this.server.conf.ws2p && this.server.conf.ws2p.uuid) || '000000'
-          const fullId = [pub, ws2pId].join('-')
-          const sigOK = verify(message, sig, pub)
-          if (sigOK) {
-            // Already known?
-            if (!this.headsCache[fullId] || this.headsCache[fullId].blockstamp !== blockstamp) {
-              // More recent?
-              if (!this.headsCache[fullId] || parseInt(this.headsCache[fullId].blockstamp) < parseInt(blockstamp)) {
-                // Check that issuer is a member and that the block exists
-                const isAllowed = pub === this.server.conf.pair.pub || this.isConnectedKey(pub) || (await this.isMemberKey(pub))
-                if (isAllowed) {
-                  const exists = await this.existsBlock(blockstamp)
-                  if (exists) {
-                    this.headsCache[fullId] = { blockstamp, message, sig }
-                    this.newHeads.push({message, sig})
-                    added.push({message, sig})
-                    // Cancel a pending "heads" to be spread
-                    if (this.headsTimeout) {
-                      clearTimeout(this.headsTimeout)
-                    }
-                    // Reprogram it a few moments later
-                    this.headsTimeout = setTimeout(async () => {
-                      const heads = this.newHeads.splice(0, this.newHeads.length)
-                      if (heads.length) {
-                        await this.spreadNewHeads(heads)
-                      }
-                    }, WS2PConstants.HEADS_SPREAD_TIMEOUT)
-                  }
-                }
-              }
-            }
-          } else {
+        // HEAD v2
+        if (h.messageV2 && h.messageV2.match(WS2PConstants.HEAD_V2_REGEXP)) {
+          if (!h.sigV2) {
             throw "HEAD_MESSAGE_WRONGLY_SIGNED"
+          } else {
+            const [,,, pub, blockstamp, ws2pId,,,,,]:string[] = h.messageV2.split(':')
+            this.headReceived(h, pub, [pub, ws2pId].join('-'), blockstamp)
           }
-        }
-        else if (message.match(WS2PConstants.HEAD_V1_REGEXP)) {
-          const [,,, pub, blockstamp, ws2pId, software, softVersion, prefix]:string[] = message.split(':')
-          const sigOK = verify(message, sig, pub)
-          const fullId = [pub, ws2pId].join('-')
-          if (sigOK) {
-            // Already known?
-            if (!this.headsCache[fullId] || this.headsCache[fullId].blockstamp !== blockstamp) {
-              // More recent?
-              if (!this.headsCache[fullId] || parseInt(this.headsCache[fullId].blockstamp) < parseInt(blockstamp)) {
-                // Check that issuer is a member and that the block exists
-                const isAllowed = pub === this.server.conf.pair.pub || this.isConnectedKey(pub) || (await this.isMemberKey(pub))
-                if (isAllowed) {
-                  const exists = await this.existsBlock(blockstamp)
-                  if (exists) {
-                    this.headsCache[fullId] = { blockstamp, message, sig }
-                    this.newHeads.push({message, sig})
-                    added.push({message, sig})
-                    // Cancel a pending "heads" to be spread
-                    if (this.headsTimeout) {
-                      clearTimeout(this.headsTimeout)
-                    }
-                    // Reprogram it a few moments later
-                    this.headsTimeout = setTimeout(async () => {
-                      const heads = this.newHeads.splice(0, this.newHeads.length)
-                      if (heads.length) {
-                        await this.spreadNewHeads(heads)
-                      }
-                    }, WS2PConstants.HEADS_SPREAD_TIMEOUT)
-                  }
-                }
-              }
-            }
+        } 
+        // HEAD v1 and HEAD v0
+        else if (h.message && h.sig) {
+          if (h.message.match(WS2PConstants.HEAD_V1_REGEXP)) {
+            const [,,, pub, blockstamp, ws2pId,,,]:string[] = h.message.split(':')
+            await this.headReceived(h, pub, [pub, ws2pId].join('-'), blockstamp)
+          } else if (h.message.match(WS2PConstants.HEAD_V0_REGEXP)) {
+            const [,,pub, blockstamp]:string[] = h.message.split(':')
+            await this.headReceived(h, pub, [pub, "00000000"].join('-'), blockstamp)
           } else {
-            throw "HEAD_MESSAGE_WRONGLY_SIGNED"
+            throw "HEAD_WRONG_FORMAT"
           }
         }
+        else if (!h.message) {
+          throw "EMPTY_MESSAGE_FOR_HEAD"
+        } else if (!h.sig) {
+          throw "HEAD_MESSAGE_WRONGLY_SIGNED"
+        } else {
+          throw "HEAD_WRONG_FORMAT"
+        }
       } catch (e) {
-        this.server.logger.trace(e)
+          this.server.logger.trace(e)
       }
     }))
+    // Cancel a pending "heads" to be spread
+    if (this.headsTimeout) {
+      clearTimeout(this.headsTimeout)
+    }
+    // Reprogram it a few moments later
+    this.headsTimeout = setTimeout(async () => {
+       const heads = this.newHeads.splice(0, this.newHeads.length)
+      if (heads.length) {
+        await this.spreadNewHeads(heads)
+      }
+    }, WS2PConstants.HEADS_SPREAD_TIMEOUT)
+    
     this.server.push({
       ws2p: 'heads',
-      added
+      added: this.newHeads
     })
-    return added
+  }
+
+  private async headReceived(h:WS2PHead, pub:string, fullId:string, blockstamp:string) {
+    try {
+      // Prevent fields injection
+      if ( (h.message.match(WS2PConstants.HEAD_V1_REGEXP) || h.message.match(WS2PConstants.HEAD_V0_REGEXP))
+      && h.sig.match(WS2PConstants.HEAD_SIG_REGEXP)
+      && (!h.messageV2 || h.messageV2.match(WS2PConstants.HEAD_V2_REGEXP))
+      && (!h.sigV2 || h.sigV2.match(WS2PConstants.HEAD_SIG_REGEXP))
+      && (!h.step || h.step.toFixed(0).match(/^[0-9]*$/))
+      ) {
+        const head:WS2PHead = { message: h.message, sig: h.sig, messageV2: h.messageV2, sigV2: h.sigV2, step: h.step }
+
+        const sigOK = verify(head.message, head.sig, pub)
+        const sigV2OK = (head.messageV2 !== undefined && head.sigV2 !== undefined) ? verify(head.messageV2, head.sigV2, pub):false
+        if ((sigV2OK && sigOK) || sigOK) {
+          // Already known or more recent or closer ?
+          const step = (this.headsCache[fullId]) ? this.headsCache[fullId].step || 0:0
+          if (!this.headsCache[fullId] // unknow head
+            || parseInt(this.headsCache[fullId].blockstamp) < parseInt(blockstamp) // more recent head
+            || (head.step !== undefined && head.step < step && this.headsCache[fullId].blockstamp === blockstamp) // closer head
+          ) {
+            // Check that issuer is a member and that the block exists
+            const isAllowed = pub === this.server.conf.pair.pub || this.isConnectedKey(pub) || (await this.isMemberKey(pub))
+            if (isAllowed) {
+              const exists = await this.existsBlock(blockstamp)
+              if (exists) {
+                this.headsCache[fullId] = { blockstamp, message: head.message, sig: head.sig, messageV2: head.messageV2, sigV2: head.sigV2, step: head.step }
+                this.newHeads.push(head)
+              }
+            }
+          }
+        } else {
+          throw "HEAD_MESSAGE_WRONGLY_SIGNED"
+        }
+      } else {
+        throw "HEAD_WRONG_FORMAT"
+      }
+    } catch (e) {
+      this.server.logger.trace(e)
+    }
   }
 
   private async isMemberKey(pub:string) {
@@ -266,9 +273,8 @@ export class WS2PCluster {
       await this.ws2pServer.close()
     }
     this.ws2pServer = await WS2PServer.bindOn(this.server, host, port, this.fifo, (pubkey:string, connectedPubkeys:string[]) => {
-      const privilegedNodes = (this.server.conf.ws2p && this.server.conf.ws2p.privilegedNodes) ? this.server.conf.ws2p.privilegedNodes:[]
-      return this.acceptPubkey(pubkey, connectedPubkeys, () => this.servedCount(), this.maxLevel2Peers, privilegedNodes, (this.server.conf.ws2p && this.server.conf.ws2p.privilegedOnly || false))
-    }, this.messageHandler)
+      return this.acceptPubkey(pubkey, connectedPubkeys, [], () => this.servedCount(), this.maxLevel2Peers, this.privilegedNodes(), (this.server.conf.ws2p !== undefined && this.server.conf.ws2p.privilegedOnly)) 
+    }, this.keyPriorityLevel, this.messageHandler)
     this.host = host
     this.port = port
     return this.ws2pServer
@@ -283,23 +289,51 @@ export class WS2PCluster {
   }
 
   clientsCount() {
-    return Object.keys(this.ws2pClients).length
+    let count = 0
+    let connectedKeys:string[] = []
+    for (const ws2pid in this.ws2pClients) {
+      if (this.ws2pClients[ws2pid].connection.pubkey != this.server.conf.pair.pub
+        && connectedKeys.indexOf(this.ws2pClients[ws2pid].connection.pubkey) == -1) {
+        count++
+        connectedKeys.push(this.ws2pClients[ws2pid].connection.pubkey)
+      }
+    }
+    return count
+  }
+
+  numberOfConnectedPublicNodesWithSameKey() {
+    let count = 0
+    for (const ws2pid in this.ws2pClients) {
+      if (this.ws2pClients[ws2pid].connection.pubkey === this.server.conf.pair.pub) {
+        count++
+      }
+    }
+    return count
   }
 
   servedCount() {
-    return this.ws2pServer ? this.ws2pServer.getConnexions().length : 0
+    return (this.ws2pServer) ? this.ws2pServer.countConnexions():0
+  }
+
+  privilegedNodes() {
+    if (this.server.conf.ws2p && this.server.conf.ws2p.privilegedNodes) {
+      return this.server.conf.ws2p.privilegedNodes
+    } else {
+      return  []
+    }
   }
 
-  async connectToRemoteWS(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<WS2PConnection> {
     const uuid = nuuid.v4()
     let pub = expectedPub.slice(0, 8)
     const api:string = (host.match(WS2PConstants.HOST_ONION_REGEX) !== null) ? 'WS2PTOR':'WS2P'
     try {
       const fullEndpointAddress = WS2PCluster.getFullAddress(host, port, path)
-      const ws2pc = await WS2PClient.connectTo(this.server, fullEndpointAddress, ws2pEndpointUUID, messageHandler, expectedPub, (pub:string) => {
+      const ws2pc = await WS2PClient.connectTo(this.server, fullEndpointAddress, endpointVersion, ws2pEndpointUUID, messageHandler, expectedPub, (pub:string) => {
         const connectedPubkeys = this.getConnectedPubkeys()
+        const connectedWS2PUID = this.getConnectedWS2PUID()
         const preferedNodes = (this.server.conf.ws2p && this.server.conf.ws2p.preferedNodes) ? this.server.conf.ws2p.preferedNodes:[]
-        return this.acceptPubkey(expectedPub, connectedPubkeys, () => this.clientsCount(), this.maxLevel1Size, preferedNodes, (this.server.conf.ws2p && this.server.conf.ws2p.preferedOnly) || false, ws2pEndpointUUID)
+        return this.acceptPubkey(expectedPub, connectedPubkeys, connectedWS2PUID, () => this.clientsCount(), this.maxLevel1Size, preferedNodes, (this.server.conf.ws2p && this.server.conf.ws2p.preferedOnly) || false, ws2pEndpointUUID)
       })
       this.ws2pClients[uuid] = ws2pc
       pub = ws2pc.connection.pubkey
@@ -329,15 +363,30 @@ export class WS2PCluster {
   }
 
   async connectToWS2Peers() {
+    // If incoming connections quota is full, delete one low-priority connection
+    if (this.ws2pServer !== null && this.ws2pServer.countConnexions() === this.ws2pServer.maxLevel2Peers) {
+      const privilegedKeys = ((this.server.conf.ws2p && this.server.conf.ws2p.privilegedNodes) || []).slice() // Copy
+      this.ws2pServer.removeLowPriorityConnection(privilegedKeys)
+    }
+    const myUUID = (this.server.conf.ws2p && this.server.conf.ws2p.uuid) ? this.server.conf.ws2p.uuid:""
     const potentials = await this.server.dal.getWS2Peers()
     const peers:PeerDTO[] = potentials.map((p:any) => PeerDTO.fromJSONObject(p))
     const prefered = ((this.server.conf.ws2p && this.server.conf.ws2p.preferedNodes) || []).slice() // Copy
     // Our key is also a prefered one, so we connect to our siblings
-    prefered.push(this.server.conf.pair.pub)
     const canReachTorEndpoint = ProxiesConf.canReachTorEndpoint(this.server.conf.proxiesConf)
+    const canReachClearEndpoint = ProxiesConf.canReachClearEndpoint(this.server.conf.proxiesConf)
     peers.sort((a, b) => {
+      // Top priority at our own nodes
+      if (a.pubkey === this.server.conf.pair.pub && b.pubkey !== this.server.conf.pair.pub) {
+          return -1
+      } else if (a.pubkey !== this.server.conf.pair.pub && b.pubkey === this.server.conf.pair.pub) {
+        return 1
+      }
+
       const aIsPrefered = prefered.indexOf(a.pubkey) !== -1
       const bIsPrefered = prefered.indexOf(b.pubkey) !== -1
+      const aNumberOfFreeRooms = this.numberOfFreeRooms(a, canReachTorEndpoint, canReachClearEndpoint)
+      const bNumberOfFreeRooms = this.numberOfFreeRooms(b, canReachTorEndpoint, canReachClearEndpoint)
 
       if (canReachTorEndpoint) {
         const aAtWs2pTorEnpoint = a.endpoints.filter(function (element) { return element.match(CommonConstants.WS2PTOR_REGEXP); }).length > 0
@@ -345,48 +394,85 @@ export class WS2PCluster {
 
         if ( (aAtWs2pTorEnpoint && bAtWs2pTorEnpoint) || (!aAtWs2pTorEnpoint && !bAtWs2pTorEnpoint) ) {
           if ((aIsPrefered && bIsPrefered) || (!aIsPrefered && !bIsPrefered))  {
+            if (aNumberOfFreeRooms > bNumberOfFreeRooms) {
+              return -1
+            } else if (aNumberOfFreeRooms < bNumberOfFreeRooms) {
+              return 1
+            }
             return 0
           } else if (aIsPrefered) {
             return -1
-          } else {
-            return 1
           }
+          return 1
         } else {
           if (aAtWs2pTorEnpoint) {
             return -1
-          } else {
-            return 1
           }
+          return 1
         }
       } else {
         if ((aIsPrefered && bIsPrefered) || (!aIsPrefered && !bIsPrefered))  {
+          if (aNumberOfFreeRooms > bNumberOfFreeRooms) {
+            return -1
+          } else if (aNumberOfFreeRooms < bNumberOfFreeRooms) {
+            return 1
+          }
           return 0
         } else if (aIsPrefered) {
           return -1
-        } else {
-          return 1
         }
+        return 1
       }
     })
     let i = 0
-    const canReachClearEndpoint = ProxiesConf.canReachClearEndpoint(this.server.conf.proxiesConf)
-    while (i < peers.length && this.clientsCount() < this.maxLevel1Size) {
+    let countPublicNodesWithSameKey:number = 1 // Necessary if maxPrivate = 0
+    let endpointsNodesWithSameKey:WS2PEndpoint[] = []
+    while (i < peers.length && (this.clientsCount() < this.maxLevel1Size || this.numberOfConnectedPublicNodesWithSameKey() < countPublicNodesWithSameKey) ) {
       const p = peers[i]
-      const api = p.getWS2P(canReachTorEndpoint, canReachClearEndpoint)
-      if (api) {
-        try {
-          // We do not connect to local host
-          if (!this.server.conf.ws2p || api.uuid !== this.server.conf.ws2p.uuid || p.pubkey !== this.server.conf.pair.pub || api.uuid === '11111111') {
-            await this.connectToRemoteWS(api.host, api.port, api.path, this.messageHandler, p.pubkey, api.uuid)
+      if (p.pubkey === this.server.conf.pair.pub) {
+        endpointsNodesWithSameKey = p.getAllWS2PEndpoints(canReachTorEndpoint, canReachClearEndpoint, myUUID)
+        countPublicNodesWithSameKey = endpointsNodesWithSameKey.length
+        for (const api of endpointsNodesWithSameKey) {
+          try {
+            // We do not connect to local host
+            if (api.uuid !== myUUID) {
+              await this.connectToRemoteWS(api.version, api.host, api.port, api.path, this.messageHandler, p.pubkey, api.uuid)
+            }
+          } catch (e) {
+            this.server.logger.debug('WS2P: init: failed connection')
+          }
+        }
+      } else {
+        const api = p.getOnceWS2PEndpoint(canReachTorEndpoint, canReachClearEndpoint)
+        if (api) {
+          try {
+            // We do not connect to local host
+            await this.connectToRemoteWS(api.version, api.host, api.port, api.path, this.messageHandler, p.pubkey, api.uuid)
+          } catch (e) {
+            this.server.logger.debug('WS2P: init: failed connection')
           }
-        } catch (e) {
-          this.server.logger.debug('WS2P: init: failed connection')
         }
       }
       i++
       // Trim the eventual extra connections
-      setTimeout(() => this.trimClientConnections(), WS2PConstants.CONNEXION_TIMEOUT)
+      setTimeout(() => this.removeLowPriorityConnections(prefered), WS2PConstants.CONNEXION_TIMEOUT)
+    }
+  }
+
+  private numberOfFreeRooms(p:PeerDTO, canReachTorEndpoint:boolean, canReachClearEndpoint:boolean) {
+    const api = p.getOnceWS2PEndpoint(canReachTorEndpoint, canReachClearEndpoint)
+    if (api) {
+      for (const ws2pFullId in this.headsCache) {
+        if (ws2pFullId.slice(0, 8) == api.uuid) {
+          const messageV2 = this.headsCache[ws2pFullId].messageV2
+          if (messageV2 !== undefined) {
+            const [,,, pub, blockstamp, ws2pId,,,,freeMemberRoom,freeMirorRoom]:string[] = messageV2.split(':')
+            return (this.server.dal.isMember(this.server.conf.pair.pub)) ? freeMemberRoom:freeMirorRoom
+          }
+        }
+      }
     }
+    return 0
   }
 
   listenServerFlow() {
@@ -399,15 +485,16 @@ export class WS2PCluster {
         // New peer
         if (data.endpoints) {
           const peer = PeerDTO.fromJSONObject(data)
-          const ws2pEnpoint = peer.getWS2P(ProxiesConf.canReachTorEndpoint(this.server.conf.proxiesConf), ProxiesConf.canReachClearEndpoint(this.server.conf.proxiesConf))
+          const ws2pEnpoint = peer.getOnceWS2PEndpoint(ProxiesConf.canReachTorEndpoint(this.server.conf.proxiesConf), ProxiesConf.canReachClearEndpoint(this.server.conf.proxiesConf))
           if (ws2pEnpoint) {
             // Check if already connected to the pubkey (in any way: server or client)
             const connectedPubkeys = this.getConnectedPubkeys()
-            const preferedNodes = (this.server.conf.ws2p && this.server.conf.ws2p.preferedNodes) ? this.server.conf.ws2p.preferedNodes:[]
-            const shouldAccept = await this.acceptPubkey(peer.pubkey, connectedPubkeys, () => this.clientsCount(), this.maxLevel1Size, preferedNodes, (this.server.conf.ws2p && this.server.conf.ws2p.preferedOnly) || false, ws2pEnpoint.uuid)
-            if (shouldAccept && (!this.server.conf.ws2p || ws2pEnpoint.uuid !== this.server.conf.ws2p.uuid || peer.pubkey !== this.server.conf.pair.pub || ws2pEnpoint.uuid === '11111111')) {
-              await this.connectToRemoteWS(ws2pEnpoint.host, ws2pEnpoint.port, ws2pEnpoint.path, this.messageHandler, peer.pubkey)
-              await this.trimClientConnections()
+            const connectedWS2PUID = this.getConnectedWS2PUID()
+            const preferedKeys = (this.server.conf.ws2p && this.server.conf.ws2p.preferedNodes) ? this.server.conf.ws2p.preferedNodes:[]
+            const shouldAccept = await this.acceptPubkey(peer.pubkey, connectedPubkeys, connectedWS2PUID, () => this.clientsCount(), this.maxLevel1Size, preferedKeys, (this.server.conf.ws2p && this.server.conf.ws2p.preferedOnly) || false, ws2pEnpoint.uuid)
+            if (shouldAccept && (!this.server.conf.ws2p || ws2pEnpoint.uuid !== this.server.conf.ws2p.uuid || peer.pubkey !== this.server.conf.pair.pub)) {
+              await this.connectToRemoteWS(ws2pEnpoint.version, ws2pEnpoint.host, ws2pEnpoint.port, ws2pEnpoint.path, this.messageHandler, peer.pubkey, ws2pEnpoint.uuid)
+              await this.removeLowPriorityConnections(preferedKeys)
             }
           }
         }
@@ -421,157 +508,204 @@ export class WS2PCluster {
         // HEAD changed
         else if (data.bcEvent === OtherConstants.BC_EVENT.HEAD_CHANGED || data.bcEvent === OtherConstants.BC_EVENT.SWITCHED) {
           // Propagate this change to the network
-          const { sig, message } = this.sayHeadChangedTo(data.block.number, data.block.hash)
+          const myHead = await this.sayHeadChangedTo(data.block.number, data.block.hash)
           try {
-            await this.broadcastHead(message, sig)
+            await this.broadcastHead(myHead)
           } catch (e) {
             this.server.logger.warn(e)
           }
         }
-
-        // WS2P disconnection
-        else if (data.ws2p === 'disconnected') {
-          const nbConnections = this.getAllConnections().length
-          if (nbConnections < WS2PConstants.CONNECTIONS_LOW_LEVEL && !connectingToNodesByFlow) {
-            try {
-              connectingToNodesByFlow = true
-              await this.connectToWS2Peers()
-            } catch (e) {
-              throw e
-            } finally {
-              connectingToNodesByFlow = false
-            }
-          }
-        }
       })()
 
       return data
     }))
   }
 
-  private async broadcastHead(message:string, sig:string) {
-    await this.headsReceived([{ message, sig }])
-    return this.spreadNewHeads([{ message, sig }])
+  private async broadcastHead(head:WS2PHead) {
+    await this.headsReceived([head])
+    return this.spreadNewHeads([head])
   }
 
-  private async spreadNewHeads(heads:{ message:string, sig:string }[]) {
+  private async spreadNewHeads(heads:WS2PHead[]) {
+    heads = this.incrementHeadsStep(heads)
     const connexions = this.getAllConnections()
     return Promise.all(connexions.map(async (c) => {
       try {
-        await c.pushHeads(heads)
+          await c.pushHeads(heads)
       } catch (e) {
-        this.server.logger.warn('Could not spread new HEAD info to %s WS2P %s %s', c.pubkey)
+        this.server.logger.warn('Could not spread new HEAD info to %s WS2PID %s', c.pubkey, c.uuid)
       }
     }))
   }
 
-  private sayHeadChangedTo(number:number, hash:string) {
-    const api = (this.server.conf.ws2p && this.server.conf.ws2p.remotehost && this.server.conf.ws2p.remotehost.match(WS2PConstants.HOST_ONION_REGEX)) ? 'WS2P':'WS2P'
+  private incrementHeadsStep(heads_:WS2PHead[]) {
+    let heads:WS2PHead[] = []
+    for (let head of heads_) {
+      if (head.step !== undefined) {
+        head.step++
+      }
+      // Prevent injections
+      heads.push({
+        message: head.message,
+        sig: head.sig,
+        messageV2: head.messageV2,
+        sigV2: head.sigV2,
+        step: head.step
+      })
+    }
+    return heads
+  }
+
+  private async sayHeadChangedTo(number:number, hash:string) {
+    const api = this.getApi()
     const key = new Key(this.server.conf.pair.pub, this.server.conf.pair.sec)
-    const pub = key.publicKey
     const software = 'duniter'
     const softVersion = Package.getInstance().version
     const ws2pId = (this.server.conf.ws2p && this.server.conf.ws2p.uuid) || '00000000'
-    const prefix = this.server.conf.prefix || Constants.DEFAULT_PEER_ID
-    const message = `${api}:HEAD:1:${pub}:${number}-${hash}:${ws2pId}:${software}:${softVersion}:${prefix}`
+    const prefix = this.server.conf.prefix || ProverConstants.DEFAULT_PEER_ID
+    const { freeMemberRoom , freeMirorRoom }  = await this.countFreeRooms()
+    const message = `${api}:HEAD:1:${key.publicKey}:${number}-${hash}:${ws2pId}:${software}:${softVersion}:${prefix}`
     const sig = key.signSync(message)
-    return { sig, message, pub }
+    const messageV2 = `${api}:HEAD:2:${key.publicKey}:${number}-${hash}:${ws2pId}:${software}:${softVersion}:${prefix}:${freeMemberRoom}:${freeMirorRoom}`
+    const sigV2 = key.signSync(messageV2)
+    
+    const myHead:WS2PHead = {
+      message,
+      sig,
+      messageV2,
+      sigV2,
+      step: 0 }
+
+    return myHead
+  }
+
+  private getApi() {
+    let api = 'WS2P'
+    let network = {
+      in: WS2PConstants.NETWORK.INCOMING.DEFAULT,
+      out: WS2PConstants.NETWORK.OUTCOMING.DEFAULT,
+    }
+    let ws2pPrivate = ''
+    let ws2pPublic = ''
+    if (this.server.conf.proxiesConf && (this.server.conf.proxiesConf.proxyTorAddress || this.server.conf.proxiesConf.forceTor)) {
+      network.out = WS2PConstants.NETWORK.OUTCOMING.TOR
+    }
+    if (this.server.conf.ws2p) {
+      if (this.server.conf.ws2p.remotehost) {
+        if (this.server.conf.ws2p.remotehost.match(WS2PConstants.HOST_ONION_REGEX)) {
+          network.in = WS2PConstants.NETWORK.INCOMING.TOR
+        }
+        if (this.server.conf.ws2p.publicAccess) {
+          ws2pPublic = 'I'
+          switch (network.in) {
+            case WS2PConstants.NETWORK.INCOMING.TOR: ws2pPublic += 'T'; break;
+            default: ws2pPublic += 'C'; break;
+          }
+        }
+      }
+      if (this.server.conf.ws2p.privateAccess) {
+        ws2pPrivate = 'O'
+        switch (network.out) {
+          case WS2PConstants.NETWORK.OUTCOMING.TOR: ws2pPrivate += 'T';
+            if (this.server.conf.proxiesConf && this.server.conf.proxiesConf.reachingClearEp) {
+              switch (this.server.conf.proxiesConf.reachingClearEp) {
+                case 'none': ws2pPrivate += 'S'; break;
+                case 'tor': ws2pPrivate += 'A'; break;
+                default: ws2pPrivate += 'M'; break;
+              }
+            }
+          break;
+          default: ws2pPrivate += 'C'; break;
+        }
+      }
+    }
+
+
+    api += ws2pPrivate + ws2pPublic
+    return api
+  }
+
+  private async countFreeRooms() {
+    if (!this.ws2pServer) {
+      return {
+        freeMemberRoom: 0,
+        freeMirorRoom: 0
+      }
+    }
+
+    let freeMirorRoom = this.maxLevel2Peers - this.ws2pServer.countConnexions()
+    let freeMemberRoom = freeMirorRoom
+    const privilegedNodes = (this.server.conf.ws2p && this.server.conf.ws2p.privilegedNodes) ? this.server.conf.ws2p.privilegedNodes:[]
+    for (const c of this.ws2pServer.getConnexions()) {
+      const connexionPriority = await this.keyPriorityLevel(c.pubkey, privilegedNodes)
+      if (connexionPriority < WS2PConstants.CONNECTIONS_PRIORITY.MEMBER_KEY_LEVEL) {
+        freeMemberRoom++
+      }
+    }
+
+    return {
+      freeMemberRoom,
+      freeMirorRoom
+    }
   }
 
   async trimServerConnections() {
     if (this.ws2pServer) {
-      await this.ws2pServer.trimConnections()
+      await this.ws2pServer.removeExcessIncomingConnections()
     }
   }
 
-  async trimClientConnections() {
+  async removeLowPriorityConnections(preferedKeys:string[]) {
     let serverPubkeys:string[] = []
     if (this.ws2pServer) {
       serverPubkeys = this.ws2pServer.getConnexions().map(c => c.pubkey)
     }
-    let disconnectedOne = true
     // Disconnect Private connexions already present under Public
-    while (disconnectedOne) {
-      disconnectedOne = false
-      let uuids = Object.keys(this.ws2pClients)
-      uuids = _.shuffle(uuids)
-      for (const uuid of uuids) {
-        const client = this.ws2pClients[uuid]
-        const pub = client.connection.pubkey
-        const isNotOurself = pub !== this.server.conf.pair.pub
-        const isAlreadyInPublic = serverPubkeys.indexOf(pub) !== -1
-        if (isNotOurself && isAlreadyInPublic) {
-          client.connection.close()
-          await client.connection.closed
-          disconnectedOne = true
-          if (this.ws2pClients[uuid]) {
-            delete this.ws2pClients[uuid]
-          }
-        }
-      }
-    }
-    // Disconnect non-members
-    while (disconnectedOne && this.clientsCount() > this.maxLevel1Size) {
-      disconnectedOne = false
-      let uuids = Object.keys(this.ws2pClients)
-      uuids = _.shuffle(uuids)
-      for (const uuid of uuids) {
-        const client = this.ws2pClients[uuid]
-        const pub = client.connection.pubkey
-        const isNotOurself = pub !== this.server.conf.pair.pub
-        const isMember = await this.server.dal.isMember(pub)
-        const isPrefered = this.getPreferedNodes().indexOf(pub) !== -1
-        if (isNotOurself && !isMember && !disconnectedOne && !isPrefered) {
-          client.connection.close()
-          await client.connection.closed
-          disconnectedOne = true
-          if (this.ws2pClients[uuid]) {
-            delete this.ws2pClients[uuid]
-          }
-        }
-      }
-    }
-    disconnectedOne = true
-    // Disconnect non-prefered members
-    while (disconnectedOne && this.clientsCount() > this.maxLevel1Size) {
-      disconnectedOne = false
-      let uuids = Object.keys(this.ws2pClients)
-      uuids = _.shuffle(uuids)
-      for (const uuid of uuids) {
-        const client = this.ws2pClients[uuid]
-        const pub = client.connection.pubkey
-        const isNotOurself = pub !== this.server.conf.pair.pub
-        const isPrefered = this.getPreferedNodes().indexOf(pub) !== -1
-        if (isNotOurself && !disconnectedOne && !isPrefered) {
-          client.connection.close()
-          disconnectedOne = true
-          await client.connection.closed
-          if (this.ws2pClients[uuid]) {
-            delete this.ws2pClients[uuid]
-          }
+    let uuids = Object.keys(this.ws2pClients)
+    uuids = _.shuffle(uuids)
+    for (const uuid of uuids) {
+      const client = this.ws2pClients[uuid]
+      const pub = client.connection.pubkey
+      const isNotOurself = pub !== this.server.conf.pair.pub
+      const isAlreadyInPublic = serverPubkeys.indexOf(pub) !== -1
+      if (isNotOurself && isAlreadyInPublic) {
+        client.connection.close()
+        await client.connection.closed
+        if (this.ws2pClients[uuid]) {
+          delete this.ws2pClients[uuid]
         }
       }
     }
-    // Disconnect anything
-    disconnectedOne = true
-    while (disconnectedOne && this.clientsCount() > this.maxLevel1Size) {
-      disconnectedOne = false
+    // Disconnect Private connexions until the maximum size is respected
+    while (this.clientsCount() > this.maxLevel1Size) {
       let uuids = Object.keys(this.ws2pClients)
       uuids = _.shuffle(uuids)
+      let lowPriorityConnectionUUID:string = uuids[0]
+      let minPriorityLevel = this.keyPriorityLevel(this.ws2pClients[lowPriorityConnectionUUID].connection.pubkey, preferedKeys)
       for (const uuid of uuids) {
         const client = this.ws2pClients[uuid]
-        if (!disconnectedOne) {
-          client.connection.close()
-          disconnectedOne = true
-          await client.connection.closed
-          if (this.ws2pClients[uuid]) {
-            delete this.ws2pClients[uuid]
+          if (uuid !== lowPriorityConnectionUUID) {
+            let uuidPriorityLevel = this.keyPriorityLevel(client.connection.pubkey, preferedKeys)
+            if (uuidPriorityLevel < minPriorityLevel) {
+              lowPriorityConnectionUUID = uuid
+              minPriorityLevel = uuidPriorityLevel
+            }
           }
-        }
       }
+      this.ws2pClients[lowPriorityConnectionUUID].connection.close()
+      await this.ws2pClients[lowPriorityConnectionUUID].connection.closed
+      delete this.ws2pClients[lowPriorityConnectionUUID]
     }
   }
 
+  async keyPriorityLevel(pubkey:string, preferedOrPrivilegedKeys:string[]) {
+    const isMember = await this.server.dal.isMember(pubkey)
+    let priorityLevel = (isMember) ? WS2PConstants.CONNECTIONS_PRIORITY.MEMBER_KEY_LEVEL:0
+    priorityLevel += (preferedOrPrivilegedKeys.indexOf(pubkey) !== -1) ? WS2PConstants.CONNECTIONS_PRIORITY.PREFERED_PRIVILEGED_KEY_LEVEL:0
+    priorityLevel += (this.server.conf.pair.pub === pubkey) ? WS2PConstants.CONNECTIONS_PRIORITY.SELF_KEY_LEVEL:0
+    return priorityLevel
+  }
+
   private getPreferedNodes(): string[] {
     return (this.server.conf.ws2p && this.server.conf.ws2p.preferedNodes) || []
   }
@@ -579,64 +713,79 @@ export class WS2PCluster {
   protected async acceptPubkey(
     pub:string,
     connectedPubkeys:string[],
+    connectedWS2PUID:string[],
     getConcurrentConnexionsCount:()=>number,
     maxConcurrentConnexionsSize:number,
     priorityKeys:string[],
     priorityKeysOnly:boolean,
     targetWS2PUID = ""
   ) {
+    if (this.server.conf.pair.pub === pub) {
+      // We do not accept oneself connetion
+      if (this.server.conf.ws2p && this.server.conf.ws2p.uuid === targetWS2PUID || targetWS2PUID === '11111111') {
+        return false
+      } else {
+        // We always accept self nodes, and they have a supreme priority (these are siblings)
+        if (targetWS2PUID === "" ||  this.isNewSiblingNode(pub, targetWS2PUID, connectedWS2PUID) ) {
+            return true
+        } else {
+          // We are already connected to this self node (same WS2PUID)
+          return false
+        }
+      }
+    }
+
     // We do not accept banned keys
     if (this.banned[pub]) {
       this.server.logger.warn('Connection to %s refused, reason: %s', pub.slice(0, 8), this.banned[pub])
       return false
     }
-    let accept = priorityKeys.indexOf(pub) !== -1
-    if (!accept && !priorityKeysOnly && connectedPubkeys.indexOf(pub) === -1) {
-      // Do we have room?
-      if (this.server.conf.pair.pub === pub && this.server.conf.ws2p && this.server.conf.ws2p.uuid === targetWS2PUID) {
-        accept = false
-      }
-      else if (getConcurrentConnexionsCount() < maxConcurrentConnexionsSize) {
-        // Yes: just connect to it
-        accept = true
-      }
-      else {
-        // No: let's verify some peer has a lower priority
-        if (connectedPubkeys.indexOf(this.server.conf.pair.pub) !== -1) {
-          // Yes, we are connected to ourself. Let's replace this connexion
-          accept = true
-        }
-        else {
-          // Does this node have the priority over at least one node?
-          const isMemberPeer = await this.server.dal.isMember(pub)
-          if (isMemberPeer) {
-            // The node may have the priority over at least 1 other node
-            let i = 0, existsOneNonMemberNode = false
-            while (!existsOneNonMemberNode && i < connectedPubkeys.length) {
-              const isAlsoAMemberPeer = await this.server.dal.isMember(connectedPubkeys[i])
-              existsOneNonMemberNode = !isAlsoAMemberPeer
-              i++
-            }
-            if (existsOneNonMemberNode) {
-              // The node has the priority over a non-member peer: try to connect
-              accept = true
-            }
-          }
+
+    // Is priority key ?
+    let isPriorityKey = priorityKeys.indexOf(pub) !== -1
+
+    // We do not accept forbidden keys
+    if (priorityKeysOnly && !isPriorityKey && this.server.conf.pair.pub !== pub) {
+      return false
+    }
+
+    // We do not accept keys already connected
+    if (connectedPubkeys.indexOf(pub) !== -1) {
+      return false
+    }
+
+    // Is member key ?
+    const isMemberPeer = await this.server.dal.isMember(pub)
+
+    // Do we have room?
+    if (getConcurrentConnexionsCount() < maxConcurrentConnexionsSize) {
+      // Yes: just connect to it
+      return true
+    }
+    else {
+      let minPriorityLevel = WS2PConstants.CONNECTIONS_PRIORITY.MAX_PRIORITY_LEVEL
+      for (const connectedPubkey of connectedPubkeys) {
+        const connectedPubkeyPriorityLevel = await this.keyPriorityLevel(connectedPubkey, priorityKeys)
+        if (connectedPubkeyPriorityLevel < minPriorityLevel) {
+          minPriorityLevel = connectedPubkeyPriorityLevel
         }
       }
-    } else {
-      // The pubkey is already connected: we accept only self nodes, and they have a supreme priority (these are siblings)
-      if (targetWS2PUID) {
-        if (this.isSiblingNode(pub, targetWS2PUID)) {
-          accept = true
-        }
+      const pubkeyPriorityLevel = await this.keyPriorityLevel(pub, priorityKeys)
+      if (pubkeyPriorityLevel > minPriorityLevel) {
+        return true
       }
     }
-    return accept
+
+    return false
   }
 
-  isSiblingNode(pub:string, uuid:string) {
-    return !!(this.server.conf.pair.pub === pub && this.server.conf.ws2p && this.server.conf.ws2p.uuid !== uuid)
+  isNewSiblingNode(pub:string, targetWS2PUID:string, connectedWS2PUID:string[]) {
+    for (const uuid of connectedWS2PUID) {
+      if (uuid === targetWS2PUID) {
+        return false
+      }
+    }
+    return true
   }
 
   async getLevel1Connections() {
@@ -661,7 +810,7 @@ export class WS2PCluster {
 
   async startCrawling(waitConnection = false) {
     // For connectivity
-    this.reconnectionInteval = setInterval(() => this.server.push({ ws2p: 'disconnected' }), 1000 * WS2PConstants.RECONNEXION_INTERVAL_IN_SEC)
+    this.reconnectionInteval = setInterval(() => this.connectToWS2Peers(), 1000 * WS2PConstants.RECONNEXION_INTERVAL_IN_SEC)
     // For blocks
     if (this.syncBlockInterval)
       clearInterval(this.syncBlockInterval);
@@ -748,6 +897,12 @@ export class WS2PCluster {
     return clients.concat(served)
   }
 
+  getConnectedWS2PUID() {
+    const clients = Object.keys(this.ws2pClients).map(k => this.ws2pClients[k].connection.uuid)
+    const served = this.ws2pServer ? this.ws2pServer.getConnexions().map(c => c.uuid) : []
+    return clients.concat(served)
+  }
+
   banConnection(c:WS2PConnection, reason:string) {
     this.server.logger.warn('Banning connections of %s for %ss, reason: %s', c.pubkey.slice(0, 8), WS2PConstants.BAN_DURATION_IN_SECONDS, reason)
     if (c.pubkey) {
diff --git a/app/modules/ws2p/lib/WS2PConnection.ts b/app/modules/ws2p/lib/WS2PConnection.ts
index 0595e5626b4e307fffdd2be5d149ce6d33323bd7..752a3cf408c9a309b9780a78edb46b396fd70d3d 100644
--- a/app/modules/ws2p/lib/WS2PConnection.ts
+++ b/app/modules/ws2p/lib/WS2PConnection.ts
@@ -6,7 +6,7 @@ import {CertificationDTO} from "../../../lib/dto/CertificationDTO"
 import {MembershipDTO} from "../../../lib/dto/MembershipDTO"
 import {TransactionDTO} from "../../../lib/dto/TransactionDTO"
 import {PeerDTO} from "../../../lib/dto/PeerDTO"
-import {WS2PConstants} from "./constants"
+import { WS2PConstants } from './constants';
 import { ProxiesConf } from '../../../lib/proxy';
 const ws = require('ws')
 const SocksProxyAgent = require('socks-proxy-agent');
@@ -49,15 +49,16 @@ export interface WS2PAuth {
 }
 
 export interface WS2PRemoteAuth extends WS2PAuth {
-  registerCONNECT(challenge:string, sig: string, pub: string): Promise<boolean>
+  registerCONNECT(ws2pVersion:number, challenge:string, sig: string, pub: string, ws2pId:string): Promise<boolean>
   sendACK(ws:any): Promise<void>
   registerOK(sig: string): Promise<boolean>
   isAuthenticatedByRemote(): boolean
   getPubkey(): string
+  getVersion(): number
 }
 
 export interface WS2PLocalAuth extends WS2PAuth {
-  sendCONNECT(ws:any): Promise<void>
+  sendCONNECT(ws:any, ws2pVersion:number): Promise<void>
   registerACK(sig: string, pub: string): Promise<boolean>
   sendOK(ws:any): Promise<void>
   isRemoteAuthenticated(): boolean
@@ -71,6 +72,8 @@ export class WS2PPubkeyRemoteAuth implements WS2PRemoteAuth {
   protected challenge:string
   protected authenticatedByRemote = false
   protected remotePub = ""
+  protected remoteWs2pId = ""
+  protected remoteVersion = 1
   protected serverAuth:Promise<void>
   protected serverAuthResolve:()=>void
   protected serverAuthReject:(err:any)=>void
@@ -87,6 +90,10 @@ export class WS2PPubkeyRemoteAuth implements WS2PRemoteAuth {
     })
   }
 
+  getVersion() {
+    return this.remoteVersion
+  }
+
   getPubkey() {
     return this.remotePub
   }
@@ -102,17 +109,19 @@ export class WS2PPubkeyRemoteAuth implements WS2PRemoteAuth {
     }))
   }
 
-  async registerCONNECT(challenge:string, sig: string, pub: string): Promise<boolean> {
+  async registerCONNECT(ws2pVersion:number, challenge:string, sig: string, pub: string, ws2pId:string = ""): Promise<boolean> {
     const allow = await this.tellIsAuthorizedPubkey(pub)
     if (!allow) {
       return false
     }
-    const challengeMessage = `WS2P:CONNECT:${this.currency}:${pub}:${challenge}`
+    const challengeMessage = (ws2pVersion > 1) ? `WS2P:CONNECT:${this.currency}:${pub}:${ws2pId}:${challenge}`:`WS2P:CONNECT:${this.currency}:${pub}:${challenge}`
     Logger.log('registerCONNECT >>> ' + challengeMessage)
     const verified = verify(challengeMessage, sig, pub)
     if (verified) {
+      this.remoteVersion = ws2pVersion
       this.challenge = challenge
       this.remotePub = pub
+      this.remoteWs2pId = ws2pId
     }
     return verified
   }
@@ -152,6 +161,7 @@ export class WS2PPubkeyLocalAuth implements WS2PLocalAuth {
   constructor(
     protected currency:string,
     protected pair:Key,
+    protected ws2pId:string,
     protected tellIsAuthorizedPubkey:(pub: string) => Promise<boolean> = () => Promise.resolve(true)
   ) {
     this.challenge = nuuid.v4() + nuuid.v4()
@@ -161,17 +171,32 @@ export class WS2PPubkeyLocalAuth implements WS2PLocalAuth {
     })
   }
 
-  async sendCONNECT(ws:any): Promise<void> {
-    const challengeMessage = `WS2P:CONNECT:${this.currency}:${this.pair.pub}:${this.challenge}`
-    Logger.log('sendCONNECT >>> ' + challengeMessage)
-    const sig = this.pair.signSync(challengeMessage)
-    await ws.send(JSON.stringify({
-      auth: 'CONNECT',
-      pub: this.pair.pub,
-      challenge: this.challenge,
-      sig
-    }))
-    return this.serverAuth
+  async sendCONNECT(ws:any, ws2pVersion:number): Promise<void> {
+    if (ws2pVersion > 1) {
+      const challengeMessage = `WS2P:${ws2pVersion}:CONNECT:${this.currency}:${this.pair.pub}:${this.ws2pId}:${this.challenge}`
+      Logger.log('sendCONNECT >>> ' + challengeMessage)
+      const sig = this.pair.signSync(challengeMessage)
+      await ws.send(JSON.stringify({
+        auth: 'CONNECT',
+        version: ws2pVersion,
+        pub: this.pair.pub,
+        ws2pid: this.ws2pId,
+        challenge: this.challenge,
+        sig
+      }))
+      return this.serverAuth
+    } else if (ws2pVersion == 1) {
+      const challengeMessage = `WS2P:CONNECT:${this.currency}:${this.pair.pub}:${this.challenge}`
+      Logger.log('sendCONNECT >>> ' + challengeMessage)
+      const sig = this.pair.signSync(challengeMessage)
+      await ws.send(JSON.stringify({
+        auth: 'CONNECT',
+        pub: this.pair.pub,
+        challenge: this.challenge,
+        sig
+      }))
+      return this.serverAuth
+    }
   }
 
   async registerACK(sig: string, pub: string): Promise<boolean> {
@@ -243,6 +268,7 @@ export class WS2PConnection {
   } = {}
 
   constructor(
+    private ws2pVersion:number,
     private ws:any,
     private onWsOpened:Promise<void>,
     private onWsClosed:Promise<void>,
@@ -256,7 +282,8 @@ export class WS2PConnection {
       connectionTimeout: REQUEST_TIMEOUT_VALUE,
       requestTimeout: REQUEST_TIMEOUT_VALUE
     },
-    private expectedPub:string = ""
+    private expectedPub:string = "",
+    private expectedWS2PUID:string = ""
   ) {
     this.connectedp = new Promise((resolve, reject) => {
       this.connectedResolve = resolve
@@ -265,6 +292,7 @@ export class WS2PConnection {
   }
 
   static newConnectionToAddress(
+    ws2pVersion:number,
     address:string,
     messageHandler:WS2PMessageHandler,
     localAuth:WS2PLocalAuth,
@@ -277,7 +305,8 @@ export class WS2PConnection {
       connectionTimeout: REQUEST_TIMEOUT_VALUE,
       requestTimeout: REQUEST_TIMEOUT_VALUE
     },
-    expectedPub:string = "") {
+    expectedPub:string = "", 
+    expectedWS2PUID:string = "") {
       if (address.match(WS2PConstants.FULL_ADDRESS_ONION_REGEX)) {
         options = {
           connectionTimeout: WS2PConstants.CONNEXION_TOR_TIMEOUT,
@@ -292,7 +321,7 @@ export class WS2PConnection {
       websocket.on('close', () => res())
     })
     websocket.on('error', () => websocket.close())
-    return new WS2PConnection(websocket, onWsOpened, onWsClosed, messageHandler, localAuth, remoteAuth, options, expectedPub)
+    return new WS2PConnection(ws2pVersion, websocket, onWsOpened, onWsClosed, messageHandler, localAuth, remoteAuth, options, expectedPub, expectedWS2PUID)
   }
 
   static newConnectionFromWebSocketServer(
@@ -312,13 +341,21 @@ export class WS2PConnection {
     const onWsClosed:Promise<void> = new Promise(res => {
       websocket.on('close', () => res())
     })
-    return new WS2PConnection(websocket, onWsOpened, onWsClosed, messageHandler, localAuth, remoteAuth, options, expectedPub)
+    return new WS2PConnection(WS2PConstants.WS2P_DEFAULT_API_VERSION, websocket, onWsOpened, onWsClosed, messageHandler, localAuth, remoteAuth, options, expectedPub)
+  }
+
+  get version() {
+    return Math.min(WS2PConstants.WS2P_HEAD_VERSION, this.remoteAuth.getVersion())
   }
 
   get pubkey() {
     return this.remoteAuth.getPubkey()
   }
 
+  get uuid() {
+    return this.expectedWS2PUID
+  }
+
   get nbRequests() {
     return this.nbRequestsCount
   }
@@ -361,7 +398,7 @@ export class WS2PConnection {
             (async () => {
               await this.onWsOpened
               try {
-                await this.localAuth.sendCONNECT(this.ws)
+                await this.localAuth.sendCONNECT(this.ws, this.ws2pVersion)
                 await Promise.all([
                   this.localAuth.authenticationIsDone(),
                   this.remoteAuth.authenticationIsDone()
@@ -391,17 +428,24 @@ export class WS2PConnection {
                 if (data.auth && typeof data.auth === "string") {
 
                   if (data.auth === "CONNECT") {
+                    if (data.version) {
+                      if (typeof data.version !== "number") {
+                        await this.errorDetected(WS2P_ERR.AUTH_INVALID_ASK_FIELDS)
+                      } else {
+                        this.ws2pVersion = data.version
+                      }
+                    }
                     if (this.remoteAuth.isAuthenticatedByRemote()) {
                       return this.errorDetected(WS2P_ERR.ALREADY_AUTHENTICATED_BY_REMOTE)
                     }
                     else if (
-                      typeof data.pub !== "string" || typeof data.sig !== "string" || typeof data.challenge !== "string") {
+                      typeof data.pub !== "string" || typeof data.sig !== "string" || typeof data.challenge !== "string" || (this.ws2pVersion > 1 && typeof data.ws2pId !== "string") ) {
                       await this.errorDetected(WS2P_ERR.AUTH_INVALID_ASK_FIELDS)
                     } else {
                       if (this.expectedPub && data.pub !== this.expectedPub) {
                         await this.errorDetected(WS2P_ERR.INCORRECT_PUBKEY_FOR_REMOTE)
                       } else {
-                        const valid = await this.remoteAuth.registerCONNECT(data.challenge, data.sig, data.pub)
+                        const valid = await this.remoteAuth.registerCONNECT(this.ws2pVersion, data.challenge, data.sig, data.pub, (this.ws2pVersion > 1) ? data.ws2pID:"")
                         if (valid) {
                           await this.remoteAuth.sendACK(this.ws)
                         } else {
@@ -571,7 +615,7 @@ export class WS2PConnection {
     return this.pushData(WS2P_PUSH.PEER, 'peer', peer)
   }
 
-  async pushHeads(heads:{ message:string, sig:string }[]) {
+  async pushHeads(heads:{ message:string, sig:string, messageV2?:string, sigV2?:string, step?:number }[]) {
     return this.pushData(WS2P_PUSH.HEAD, 'heads', heads)
   }
 
diff --git a/app/modules/ws2p/lib/WS2PServer.ts b/app/modules/ws2p/lib/WS2PServer.ts
index 251f01a631592b2152a1a9599ba11567927f6f38..002d0cf82c52c82c136b950e92aa6b808bd0c010 100644
--- a/app/modules/ws2p/lib/WS2PServer.ts
+++ b/app/modules/ws2p/lib/WS2PServer.ts
@@ -7,6 +7,7 @@ import {WS2PConstants} from "./constants"
 import {WS2PMessageHandler} from "./impl/WS2PMessageHandler"
 import {WS2PStreamer} from "./WS2PStreamer"
 import {WS2PSingleWriteStream} from "./WS2PSingleWriteStream"
+import { WS2PCluster } from './WS2PCluster';
 
 const WebSocketServer = require('ws').Server
 
@@ -20,7 +21,8 @@ export class WS2PServer extends events.EventEmitter {
     private host:string,
     private port:number,
     private fifo:GlobalFifoPromise,
-    private shouldAcceptConnection:(pubkey:string, connectedPubkeys:string[])=>Promise<boolean>) {
+    private shouldAcceptConnection:(pubkey:string, connectedPubkeys:string[])=>Promise<boolean>,
+    public keyPriorityLevel:(pubkey:string, privilegedKeys:string[])=>Promise<number>) {
     super()
   }
 
@@ -35,6 +37,17 @@ export class WS2PServer extends events.EventEmitter {
     return this.connections.slice()
   }
 
+  countConnexions() {
+    const connections = this.getConnexions()
+    let count = 0
+    for (const c of connections) {
+      if (c.pubkey != this.server.conf.pair.pub) {
+        count++
+      }
+    }
+    return count
+  }
+
   private listenToWebSocketConnections(messageHandler:WS2PMessageHandler) {
     const key = new Key(this.server.conf.pair.pub, this.server.conf.pair.sec)
     this.wss = new WebSocketServer({ host: this.host, port: this.port })
@@ -67,11 +80,11 @@ export class WS2PServer extends events.EventEmitter {
           requestTimeout: WS2PConstants.REQUEST_TOR_TIMEOUT
         }
       }
-
+      const myWs2pId = (this.server.conf.ws2p && this.server.conf.ws2p.uuid) ? this.server.conf.ws2p.uuid:""
       const c = WS2PConnection.newConnectionFromWebSocketServer(
         ws,
         messageHandler,
-        new WS2PPubkeyLocalAuth(this.server.conf.currency, key, acceptPubkey),
+        new WS2PPubkeyLocalAuth(this.server.conf.currency, key, myWs2pId, acceptPubkey),
         new WS2PPubkeyRemoteAuth(this.server.conf.currency, key, acceptPubkey),
         timeout
       )
@@ -86,7 +99,7 @@ export class WS2PServer extends events.EventEmitter {
         })
         this.connections.push(c)
         this.emit('newConnection', c)
-        this.server.logger.info('WS2P: established incoming connection from %s:%s', host, port)
+        this.server.logger.info('WS2P: established incoming connection from %s %s:%s', c.pubkey.slice(0, 8), host, port)
 
         // Broadcasting
         const singleWriteProtection = new WS2PSingleWriteStream()
@@ -102,6 +115,7 @@ export class WS2PServer extends events.EventEmitter {
         ws.on('close', () => {
           this.server.unpipe(singleWriteProtection)
           singleWriteProtection.unpipe(ws2pStreamer)
+          this.server.logger.info('WS2P: close incoming connection from %s %s:%s', c.pubkey.slice(0, 8), host, port)
           this.removeConnection(c)
           this.server.push({
             ws2p: 'disconnected',
@@ -111,7 +125,8 @@ export class WS2PServer extends events.EventEmitter {
           })
         })
 
-        await this.trimConnections()
+        // Remove excess incoming connections
+        this.removeExcessIncomingConnections()
 
         await this.server.dal.setPeerUP(c.pubkey)
 
@@ -122,44 +137,39 @@ export class WS2PServer extends events.EventEmitter {
     })
   }
 
-  async trimConnections() {
-    /*** OVERFLOW TRIMMING ***/
-    let disconnectedOne = true
-    // Disconnect non-members
-    while (disconnectedOne && this.connections.length > this.maxLevel2Peers) {
-      disconnectedOne = false
-      for (const c of this.connections) {
-        const isMember = await this.server.dal.isMember(c.pubkey)
-        if (!isMember && !disconnectedOne) {
-          c.close()
-          this.removeConnection(c)
-          disconnectedOne = true
-        }
-      }
+  async removeExcessIncomingConnections() {
+    await this.removeDuplicateConnections()
+    const ws2pPublicMax = (this.server.conf.ws2p && this.server.conf.ws2p.maxPublic) ? this.server.conf.ws2p.maxPublic:WS2PConstants.MAX_LEVEL_2_PEERS
+    let privilegedKeys = (this.server.conf.ws2p && this.server.conf.ws2p.privilegedNodes) ? this.server.conf.ws2p.privilegedNodes:[]
+    while (this.countConnexions() > this.maxLevel2Peers) {
+      await this.removeLowPriorityConnection(privilegedKeys)
     }
-    // Disconnect members
-    while (this.connections.length > this.maxLevel2Peers) {
-      for (const c of this.connections) {
-        c.close()
+  }
+
+  async removeDuplicateConnections() {
+    let connectedPubkeys:string[] = []
+    for (const c of this.connections) {
+      if (connectedPubkeys.indexOf(c.pubkey) !== -1) {
         this.removeConnection(c)
+      } else if (c.pubkey !== this.server.conf.pair.pub) {
+        connectedPubkeys.push(c.pubkey)
       }
     }
-    /*** DUPLICATES TRIMMING ***/
-    disconnectedOne = true
-    while (disconnectedOne) {
-      disconnectedOne = false
-      const pubkeysFound = []
-      for (const c of this.connections) {
-        if (pubkeysFound.indexOf(c.pubkey) !== -1) {
-          c.close()
-          this.removeConnection(c)
-          disconnectedOne = true
-        }
-        else if (c.pubkey !== this.server.conf.pair.pub) {
-          pubkeysFound.push(c.pubkey)
+  }
+
+  async removeLowPriorityConnection(privilegedKeys:string[]) {
+    let lowPriorityConnection:WS2PConnection = this.connections[0]
+    let minPriorityLevel = this.keyPriorityLevel(lowPriorityConnection.pubkey, privilegedKeys)
+    for (const c of this.connections) {
+      if (c !== lowPriorityConnection) {
+        let cPriorityLevel = this.keyPriorityLevel(c.pubkey, privilegedKeys)
+        if (cPriorityLevel < minPriorityLevel) {
+          lowPriorityConnection = c
+          minPriorityLevel = cPriorityLevel
         }
       }
     }
+    this.removeConnection(lowPriorityConnection)
   }
 
   private removeConnection(c:WS2PConnection) {
@@ -167,6 +177,7 @@ export class WS2PServer extends events.EventEmitter {
     if (index !== -1) {
       // Remove the connection
       this.connections.splice(index, 1)
+      c.close()
     }
   }
 
@@ -195,8 +206,8 @@ export class WS2PServer extends events.EventEmitter {
     }))
   }
 
-  static async bindOn(server:Server, host:string, port:number, fifo:GlobalFifoPromise, shouldAcceptConnection:(pubkey:string, connectedPubkeys:string[])=>Promise<boolean>, messageHandler:WS2PMessageHandler) {
-    const ws2ps = new WS2PServer(server, host, port, fifo, shouldAcceptConnection)
+  static async bindOn(server:Server, host:string, port:number, fifo:GlobalFifoPromise, shouldAcceptConnection:(pubkey:string, connectedPubkeys:string[])=>Promise<boolean>, keyPriorityLevel:(pubkey:string, privilegedKeys:string[])=>Promise<number>, messageHandler:WS2PMessageHandler) {
+    const ws2ps = new WS2PServer(server, host, port, fifo, shouldAcceptConnection, keyPriorityLevel)
     await ws2ps.listenToWebSocketConnections(messageHandler)
     server.logger.info('WS2P server %s listening on %s:%s', server.conf.pair.pub, host, port)
     return ws2ps
diff --git a/app/modules/ws2p/lib/constants.ts b/app/modules/ws2p/lib/constants.ts
index bea7664e8be4f202675c17e912273ee0feff9001..b57598b7bbe327066124970f0469d33a9df9f9c6 100644
--- a/app/modules/ws2p/lib/constants.ts
+++ b/app/modules/ws2p/lib/constants.ts
@@ -1,6 +1,22 @@
 import {CommonConstants} from "../../../lib/common-libs/constants"
 export const WS2PConstants = {
 
+  NETWORK: {
+    INCOMING: {
+      DEFAULT: 0,
+      TOR: 1
+    },
+    OUTCOMING: {
+      DEFAULT: 0,
+      TOR: 1
+    },
+  },
+
+  WS2P_DEFAULT_API_VERSION:1,
+  WS2P_DEFAULT_HEAD_VERSION:1,
+  WS2P_API_VERSION: 1,
+  WS2P_HEAD_VERSION: 2,
+
   WS2P_UPNP_TTL: 600,
   WS2P_PORTS_START: 20900,
   WS2P_PORTS_END: 20999,
@@ -18,7 +34,13 @@ export const WS2PConstants = {
 
   MAX_LEVEL_1_PEERS: 5,
   MAX_LEVEL_2_PEERS: 20,
-  CONNECTIONS_LOW_LEVEL: 3,
+
+  CONNECTIONS_PRIORITY: {
+    MEMBER_KEY_LEVEL: 1,
+    PREFERED_PRIVILEGED_KEY_LEVEL: 2,
+    SELF_KEY_LEVEL: 4,
+    MAX_PRIORITY_LEVEL: 7,
+  },
 
   BAN_DURATION_IN_SECONDS: 120,
   BAN_ON_REPEAT_THRESHOLD: 5,
@@ -37,8 +59,21 @@ export const WS2PConstants = {
   + '(' + CommonConstants.FORMATS.SOFTWARE + '):'
   + '(' + CommonConstants.FORMATS.SOFT_VERSION + '):'
   + '(' + CommonConstants.FORMATS.POW_PREFIX + ')'
+  + '$'),
+
+  HEAD_V2_REGEXP: new RegExp('^WS2P(?:O[CT][SAM])?(?:I[CT])?:HEAD:2:'
+  + '(' + CommonConstants.FORMATS.PUBKEY + '):'
+  + '(' + CommonConstants.FORMATS.BLOCKSTAMP + '):'
+  + '(' + CommonConstants.FORMATS.WS2PID + '):'
+  + '(' + CommonConstants.FORMATS.SOFTWARE + '):'
+  + '(' + CommonConstants.FORMATS.SOFT_VERSION + '):'
+  + '(' + CommonConstants.FORMATS.POW_PREFIX + '):'
+  + '(' + CommonConstants.FORMATS.ZERO_OR_POSITIVE_INT + '):'
+  + '(' + CommonConstants.FORMATS.ZERO_OR_POSITIVE_INT + ')'
   + '(?::' + CommonConstants.FORMATS.TIMESTAMP + ')?'
   + '$'),
+  
+  HEAD_SIG_REGEXP: new RegExp(CommonConstants.FORMATS.SIGNATURE),
 
   HOST_ONION_REGEX: CommonConstants.HOST_ONION_REGEX,
   FULL_ADDRESS_ONION_REGEX: CommonConstants.WS_FULL_ADDRESS_ONION_REGEX,
diff --git a/app/service/IdentityService.ts b/app/service/IdentityService.ts
index 81288451dc47dda3de811b1cc02c104d8f994b94..e052aa29a0c04e3172adea6ae0eb044cae15d554 100644
--- a/app/service/IdentityService.ts
+++ b/app/service/IdentityService.ts
@@ -115,7 +115,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({
-              pubkey: idty.pubkey,
+              issuers: [idty.pubkey],
               ref_block: parseInt(idty.buid.split('-')[0])
             }, this.conf.pair && this.conf.pair.pub))) {
             throw constants.ERRORS.SANDBOX_FOR_IDENTITY_IS_FULL;
@@ -166,6 +166,7 @@ export class IdentityService extends FIFOService {
             };
           }
           const mCert:DBCert = {
+            issuers: [cert.from],
             from: cert.from,
             sig: cert.sig,
             block_number: cert.block_number,
@@ -239,7 +240,7 @@ export class IdentityService extends FIFOService {
           const idty = IdentityDTO.fromRevocation(revoc);
           idty.revocation_sig = revoc.revocation;
           if (!(await this.dal.idtyDAL.sandbox.acceptNewSandBoxEntry({
-              pubkey: idty.pubkey,
+              issuers: [idty.pubkey],
               ref_block: parseInt(idty.buid.split('-')[0]),
               certsCount: 0
             }, this.conf.pair && this.conf.pair.pub))) {
diff --git a/app/service/MembershipService.ts b/app/service/MembershipService.ts
index fd27d3d24873ec524b77c2abe855254c405e7248..1cbb2d73cf10bfd00e63619abc638f854bc92a63 100644
--- a/app/service/MembershipService.ts
+++ b/app/service/MembershipService.ts
@@ -56,13 +56,14 @@ export class MembershipService extends FIFOService {
       const current = await this.dal.getCurrentBlockOrNull();
       const basedBlock = await GLOBAL_RULES_HELPERS.checkMembershipBlock(entry, current, this.conf, this.dal);
       if (!(await this.dal.msDAL.sandbox.acceptNewSandBoxEntry({
-          pubkey: entry.pubkey,
+          issuers: [entry.pubkey],
           block_number: entry.block_number
         }, this.conf.pair && this.conf.pair.pub))) {
         throw constants.ERRORS.SANDBOX_FOR_MEMERSHIP_IS_FULL;
       }
       // Saves entry
       await this.dal.savePendingMembership({
+        issuers: [entry.pubkey],
         membership: entry.membership,
         issuer: entry.issuer,
         number: entry.number,
diff --git a/app/service/TransactionsService.ts b/app/service/TransactionsService.ts
index ab144b243d20b433221959e1eedf2444ad2ac30c..e6ddf1263234920e509ca684438cc19cec1ecb5f 100644
--- a/app/service/TransactionsService.ts
+++ b/app/service/TransactionsService.ts
@@ -46,7 +46,7 @@ export class TransactionService extends FIFOService {
         await GLOBAL_RULES_HELPERS.checkSingleTransaction(dto, nextBlockWithFakeTimeVariation, this.conf, this.dal, CHECK_PENDING_TRANSACTIONS);
         const server_pubkey = this.conf.pair && this.conf.pair.pub;
         if (!(await this.dal.txsDAL.sandbox.acceptNewSandBoxEntry({
-            pubkey: tx.issuers.indexOf(server_pubkey) !== -1 ? server_pubkey : '',
+            issuers: tx.issuers,
             output_base: tx.output_base,
             output_amount: tx.output_amount
           }, server_pubkey))) {
diff --git a/index.ts b/index.ts
index f9e3cf445157876a33b1c8d5be9335d121b6a070..ecf7be9d67231df6e4e63ef96c903457272b675d 100644
--- a/index.ts
+++ b/index.ts
@@ -7,7 +7,7 @@ import {KeypairDependency} from "./app/modules/keypair/index"
 import {CrawlerDependency} from "./app/modules/crawler/index"
 import {BmaDependency} from "./app/modules/bma/index"
 import {WS2PDependency} from "./app/modules/ws2p/index"
-import {Constants} from "./app/modules/prover/lib/constants"
+import {ProverConstants} from "./app/modules/prover/lib/constants"
 import { ProxiesConf } from './app/lib/proxy';
 
 const path = require('path');
@@ -444,6 +444,7 @@ function commandLineConf(program:any, conf:any = {}) {
   const cli = {
     currency: program.currency,
     cpu: program.cpu,
+    nbCores: program.nbCores,
     prefix: program.prefix,
     server: {
       port: program.port,
@@ -485,7 +486,7 @@ function commandLineConf(program:any, conf:any = {}) {
   if (cli.currency)                             conf.currency = cli.currency;
   if (cli.server.port)                          conf.port = cli.server.port;
   if (cli.cpu)                                  conf.cpu = Math.max(0.01, Math.min(1.0, cli.cpu));
-  if (cli.prefix)                               conf.prefix = Math.max(Constants.MIN_PEER_ID, Math.min(Constants.MAX_PEER_ID, cli.prefix));
+  if (cli.prefix)                               conf.prefix = Math.max(ProverConstants.MIN_PEER_ID, Math.min(ProverConstants.MAX_PEER_ID, cli.prefix));
   if (cli.logs.http)                            conf.httplogs = true;
   if (cli.logs.nohttp)                          conf.httplogs = false;
   if (cli.isolate)                              conf.isolate = cli.isolate;
diff --git a/test/dal/triming.js b/test/dal/triming.js
index db2c0cb849343c53b7db558a368729cf7185b440..501ec550e41e568107bbcd4ff9b803038a4e7684 100644
--- a/test/dal/triming.js
+++ b/test/dal/triming.js
@@ -124,10 +124,6 @@ describe("Triming", function(){
   it('should be able to trim the bindex', () => co(function *() {
     // Triming
     const server = (yield toolbox.simpleNodeWith2Users({
-      pair: {
-        pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
-        sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
-      },
       forksize: 9,
       sigQty: 1,
       dtDiffEval: 2,
diff --git a/test/fast/modules/bma/ddos-test.js b/test/fast/modules/bma/ddos-test.js
index c4127c62d6754fb0fc8f1a64260d235590a68dc9..5bb0d64f59d88f379ebd301b97d05bab0bb343dc 100644
--- a/test/fast/modules/bma/ddos-test.js
+++ b/test/fast/modules/bma/ddos-test.js
@@ -3,7 +3,7 @@
 // const co = require('co');
 // const limiter = require('../../app/lib/system/limiter');
 // const toolbox = require('../integration/tools/toolbox');
-// const user    = require('../integration/tools/user');
+// const TestUser = require('../integration/tools/TestUser').TestUser
 // const bma     = require('../lib/bma');
 //
 // limiter.noLimit();
diff --git a/test/fast/modules/bma/limiter-test.js b/test/fast/modules/bma/limiter-test.js
index 0ba0c0254a0b8c6597f4628b01d09e3245a52e65..2ec5db9f4ae4587e9f637b088667a1b8125f113c 100644
--- a/test/fast/modules/bma/limiter-test.js
+++ b/test/fast/modules/bma/limiter-test.js
@@ -3,7 +3,7 @@
 // const co = require('co');
 // const limiter = require('../lib/limiter');
 // const toolbox = require('../integration/tools/toolbox');
-// const user    = require('../integration/tools/user');
+// const TestUser = require('../integration/tools/TestUser').TestUser
 // const bma     = require('duniter-bma').duniter.methods.bma;
 //
 // limiter.noLimit();
@@ -15,7 +15,7 @@
 //   }
 // });
 //
-// const cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
+// const cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
 //
 // let theLimiter;
 //
diff --git a/test/integration/branches2.js b/test/integration/branches2.js
index 0970f97333bb4e18b9ede6bfb3beb3f5a06cfebf..18d0555795268fae555bad1a150e1a087db3d873 100644
--- a/test/integration/branches2.js
+++ b/test/integration/branches2.js
@@ -13,11 +13,11 @@ const logger_1 = require("../../app/lib/logger");
 const index_1 = require("../../app/modules/bma/index");
 const index_2 = require("../../app/modules/crawler/index");
 const toolbox_1 = require("./tools/toolbox");
+const TestUser_1 = require("./tools/TestUser");
 const co = require('co');
 const _ = require('underscore');
 const duniter = require('../../index');
 const bma = index_1.BmaDependency.duniter.methods.bma;
-const user = require('./tools/user');
 const rp = require('request-promise');
 const httpTest = require('./tools/http');
 const commit = require('./tools/commit');
@@ -61,8 +61,8 @@ describe("SelfFork", function () {
                 sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'
             }
         }, commonConf));
-        cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP' }, { server: s1 });
-        toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F' }, { server: s1 });
+        cat = new TestUser_1.TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP' }, { server: s1 });
+        toc = new TestUser_1.TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F' }, { server: s1 });
         const commitS1 = commit(s1);
         const commitS2 = commit(s2, {
             time: now + 37180
diff --git a/test/integration/branches2.ts b/test/integration/branches2.ts
index 0d4eb63a7912917c36dccec729acc22b452574b0..6626d06133c62a7f7d8716830473d488762823ee 100644
--- a/test/integration/branches2.ts
+++ b/test/integration/branches2.ts
@@ -3,12 +3,12 @@ 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 user      = require('./tools/user');
 const rp        = require('request-promise');
 const httpTest  = require('./tools/http');
 const commit    = require('./tools/commit');
@@ -69,8 +69,8 @@ describe("SelfFork", function() {
         }
       }, commonConf));
 
-    cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
+    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, {
diff --git a/test/integration/branches_pending_data.js b/test/integration/branches_pending_data.js
index e4d4184d1ba3e39333bd9c1b461986244f3efff9..ef60584d2194905a241d3df4424da21f566160e3 100644
--- a/test/integration/branches_pending_data.js
+++ b/test/integration/branches_pending_data.js
@@ -4,7 +4,7 @@ const co = require('co');
 const _         = require('underscore');
 const duniter   = require('../../index');
 const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const rp        = require('request-promise');
 const httpTest  = require('./tools/http');
 const commit    = require('./tools/commit');
@@ -39,10 +39,10 @@ describe("Pending data", function() {
         }
       }, commonConf));
 
-    cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
-    tic = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
-    tuc = user('tuc', { pub: '3conGDUXdrTGbQPMQQhEC4Ubu1MCAnFrAYvUaewbUhtk', sec: '5ks7qQ8Fpkin7ycXpxQSxxjVhs8VTzpM3vEBMqM7NfC1ZiFJ93uQryDcoM93Mj77T6hDAABdeHZJDFnkDb35bgiU'}, { server: 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 });
 
     const commitS1 = commit(s1);
 
diff --git a/test/integration/branches_revert.js b/test/integration/branches_revert.js
index d92ff38d102c7823cf027a291e4431d89af05f04..b23325740eefdaf15095c6f860cd573fca639327 100644
--- a/test/integration/branches_revert.js
+++ b/test/integration/branches_revert.js
@@ -3,7 +3,7 @@
 const co = require('co');
 const _         = require('underscore');
 const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const toolbox   = require('./tools/toolbox');
 const commit    = require('./tools/commit');
 
@@ -32,8 +32,8 @@ describe("Revert root", function() {
         sigQty: 1, dt: 1, ud0: 120
       }, commonConf));
 
-      cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-      toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
+      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();
diff --git a/test/integration/branches_revert2.js b/test/integration/branches_revert2.js
index 9800c3ad7e1415fd1df5dd1584cbeec4bfb8df98..bc85ff5b69d24e2351a9d5710fded4939775ede5 100644
--- a/test/integration/branches_revert2.js
+++ b/test/integration/branches_revert2.js
@@ -4,13 +4,13 @@ const co = require('co');
 const _         = require('underscore');
 const duniter     = require('../../index');
 const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const user      = require('./tools/user');
+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').Constants.CORES_MAXIMUM_USE_IN_PARALLEL = 1
+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;
@@ -23,6 +23,7 @@ const MEMORY_MODE = true;
 const commonConf = {
   ipv4: '127.0.0.1',
   currency: 'bb',
+  nbCores:1,
   httpLogs: true,
   forksize: 3,
   sigQty: 1
@@ -49,8 +50,8 @@ describe("Revert two blocks", function() {
         sigQty: 1, dt: 1, ud0: 120
       }, commonConf));
 
-    cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
+    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());
diff --git a/test/integration/branches_revert_memberships.js b/test/integration/branches_revert_memberships.js
index f1a6df5e46908403ece4cba3143b23313d899301..b1b115f2fed5ce4417833dc6ec62f67fad5d8089 100644
--- a/test/integration/branches_revert_memberships.js
+++ b/test/integration/branches_revert_memberships.js
@@ -3,7 +3,7 @@
 const co        = require('co');
 const should    = require('should');
 const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const commit    = require('./tools/commit');
 const toolbox   = require('./tools/toolbox');
 
@@ -24,9 +24,9 @@ describe("Revert memberships", function() {
       }
     });
 
-    i1 = user('i1',   { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    i2 = user('i2',   { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
-    i3 = user('i3',   { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
+    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();
 
diff --git a/test/integration/branches_switch.js b/test/integration/branches_switch.js
index 44839640a6d678d0e325c96218c8323e8096493c..353ef8113098859a1f9e67a0b9592211759b1194 100644
--- a/test/integration/branches_switch.js
+++ b/test/integration/branches_switch.js
@@ -6,7 +6,7 @@ const co = require('co');
 const _ = require('underscore');
 const duniter = require('../../index');
 const bma = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const user = require('./tools/user');
+const TestUser = require('./tools/TestUser').TestUser;
 const rp = require('request-promise');
 const httpTest = require('./tools/http');
 const commit = require('./tools/commit');
@@ -43,8 +43,8 @@ describe("Switch", function () {
                 sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'
             }
         }, commonConf));
-        cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP' }, { server: s1 });
-        toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F' }, { server: s1 });
+        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) => bmapi.openConnections());
         yield s2.initWithDAL().then(bma).then((bmapi) => bmapi.openConnections());
         s1.addEndpointsDefinitions(() => index_2.BmaDependency.duniter.methods.getMainEndpoint(s1.conf));
diff --git a/test/integration/branches_switch.ts b/test/integration/branches_switch.ts
index 862257dcaf5cf1d8f6be5fd9b3aa14d29dafc45a..2eb7fae68263581106b049d653402e133aa6508a 100644
--- a/test/integration/branches_switch.ts
+++ b/test/integration/branches_switch.ts
@@ -6,7 +6,7 @@ const co = require('co');
 const _         = require('underscore');
 const duniter     = require('../../index');
 const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const rp        = require('request-promise');
 const httpTest  = require('./tools/http');
 const commit    = require('./tools/commit');
@@ -57,8 +57,8 @@ describe("Switch", function() {
         }
       }, commonConf));
 
-    cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
+    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());
diff --git a/test/integration/certification_chainability.js b/test/integration/certification_chainability.js
index f33feec85e425db2196085f28fc0d4f0b60b4483..3eaf70f90208fe76bc2d38c93b3ff91fea725475 100644
--- a/test/integration/certification_chainability.js
+++ b/test/integration/certification_chainability.js
@@ -5,7 +5,7 @@ const co        = require('co');
 const should    = require('should');
 const duniter     = require('../../index');
 const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const constants = require('../../app/lib/constants');
 const rp        = require('request-promise');
 const httpTest  = require('./tools/http');
@@ -41,10 +41,10 @@ describe("Certification chainability", function() {
         }
       }, commonConf));
 
-    cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    tac = user('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
-    toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
-    tic = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
+    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 });
+    tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
 
     const now = 1482220000;
 
diff --git a/test/integration/certifier-is-member.js b/test/integration/certifier-is-member.js
index 25287c7b5e21d9e10361bb7a355c9d771043a741..ffc5ec0156feff6ba99af96d8d198753bdb9c3b1 100644
--- a/test/integration/certifier-is-member.js
+++ b/test/integration/certifier-is-member.js
@@ -6,7 +6,7 @@ const assert    = require('assert');
 const should    = require('should');
 const duniter   = require('../../index');
 const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const constants = require('../../app/lib/constants');
 const toolbox   = require('./tools/toolbox');
 
@@ -29,9 +29,9 @@ describe("Certifier must be a member", function() {
       medianTimeBlocks: 1
     });
 
-    cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    tac = user('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
-    tic = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
+    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 });
 
     yield s1.initDalBmaConnections();
     yield cat.createIdentity();
diff --git a/test/integration/collapse.js b/test/integration/collapse.js
index 234e6d938c0a807f4918dd7cb9fd3a3fc82c076e..f343b513b045bab65529b0ffbddcce83b78c35cd 100644
--- a/test/integration/collapse.js
+++ b/test/integration/collapse.js
@@ -4,7 +4,7 @@ const co        = require('co');
 const _         = require('underscore');
 const duniter     = require('../../index');
 const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const commit    = require('./tools/commit');
 const httpTest  = require('./tools/http');
 const shutDownEngine  = require('./tools/shutDownEngine');
@@ -40,8 +40,8 @@ describe("Community collapse", function() {
         sigQty: 1, dt: 100, ud0: 120, sigValidity: 1
       }, commonConf));
 
-    cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    tac = user('tac', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
+    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());
diff --git a/test/integration/continuous-proof.js b/test/integration/continuous-proof.js
index 39b4de1281d614b7b1e7730f28ff32c599abded5..289d5b694b3f5ceeef79fb2f479af64c6080548f 100644
--- a/test/integration/continuous-proof.js
+++ b/test/integration/continuous-proof.js
@@ -3,7 +3,7 @@
 const co        = require('co');
 const es        = require('event-stream');
 const should    = require('should');
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const toolbox   = require('./tools/toolbox');
 const constants = require('../../app/lib/constants');
 
@@ -26,8 +26,8 @@ describe("Continous proof-of-work", function() {
       }
     })
 
-    i1 = user('i1',   { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    i2 = user('i2',   { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
+    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();
diff --git a/test/integration/crosschain-test.js b/test/integration/crosschain-test.js
index c00e626e5954a0a23b971ec8fff59b5971f4bc7c..e0adfbc1e57dc6dc9767e63972a8e7e61802ee2d 100644
--- a/test/integration/crosschain-test.js
+++ b/test/integration/crosschain-test.js
@@ -8,7 +8,7 @@ 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 user   = require('./tools/user');
+const TestUser = require('./tools/TestUser').TestUser
 const unit   = require('./tools/unit');
 const httpTest  = require('./tools/http');
 
@@ -57,11 +57,11 @@ describe("Crosschain transactions", function() {
       }, commonConf));
 
       // toc is on 2 currencies
-      tocB = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: sB });
-      tocM = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: sM });
+      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 = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: sB });
-      ticM = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: sM });
+      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();
@@ -243,11 +243,11 @@ describe("Crosschain transactions", function() {
         }, commonConf));
 
         // toc is on 2 currencies
-        tocB = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: sB });
-        tocM = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: sM });
+        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 = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: sB });
-        ticM = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: sM });
+        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()
diff --git a/test/integration/documents-currency.ts b/test/integration/documents-currency.ts
index 2bffa0b1a2d6aad957f60a0a4759cf6a9649ba7e..50327d07d860ac73031d52f6fb15808175197ff0 100644
--- a/test/integration/documents-currency.ts
+++ b/test/integration/documents-currency.ts
@@ -1,8 +1,12 @@
-import { NewTestingServer } from './tools/toolbox';
+
+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';
 
 const co        = require('co');
 const should    = require('should');
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 
 let s1:any, s2:any, cat1:any, tac1:any, toc2:any, tic2:any;
 
@@ -15,25 +19,25 @@ describe("Document pool currency", function() {
     s1 = NewTestingServer({
       currency: 'currency_one',
       pair: {
-        pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
-        sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
-      },
-      udTime0: now - 1,
-      dt: 1,
-      ud0: 1500
-    });
-    s2 = NewTestingServer({
-      currency: 'currency_two',
-      pair: {
-        pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo',
-        sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'
-      }
-    });
-
-    cat1 = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    tac1 = user('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
-    toc2 = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s2 });
-    tic2 = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s2 });
+          pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
+          sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
+        },
+        udTime0: now - 1,
+        dt: 1,
+        ud0: 1500
+      });
+      s2 = NewTestingServer({
+        currency: 'currency_two',
+        pair: {
+          pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo',
+          sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'
+        }
+      });
+
+    cat1 = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
+    tac1 = new TestUser('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
+    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();
diff --git a/test/integration/forwarding.js b/test/integration/forwarding.js
index ba392a69af5d2b461920c09622ec5d2558d34215..993247afcae309b74a8001914f99576823085ed0 100644
--- a/test/integration/forwarding.js
+++ b/test/integration/forwarding.js
@@ -5,7 +5,7 @@ const async  = require('async');
 const _      = require('underscore');
 const co     = require('co');
 const node   = require('./tools/node');
-const user   = require('./tools/user');
+const TestUser = require('./tools/TestUser').TestUser
 const jspckg = require('../../package');
 const constants = require('../../app/lib/constants');
 
@@ -24,10 +24,10 @@ describe("Forwarding", function() {
     const node1 = node('db_1', _({ upnp: false, httplogs: false, port: 9600, remoteport: 9600, pair: { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'} }).extend(common));
     const node2 = node('db_2', _({ upnp: false, httplogs: false, port: 9601, remoteport: 9601, pair: { pub: 'G2CBgZBPLe6FSFUgpx2Jf1Aqsgta6iib3vmDRA1yLiqU', sec: '58LDg8QLmF5pv6Dn9h7X4yFKfMTdP8fdAiWVcyDoTRJu454fwRihCLULH4MW37zncsg4ruoTGJPZneWk22QmG1w4'} }).extend(common));
 
-    const cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, node1);
-    const tac = user('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, node1);
-    const tic = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, node1);
-    const toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, node1);
+    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(() => co(function*(){
       yield [node1, node2].map((theNode) => theNode.startTesting());
diff --git a/test/integration/http_api.js b/test/integration/http_api.js
index 43e8733a2eab320b05669c892f1095ec483da3bb..83cd3ccb202b102879c48a2bbed2170436992c67 100644
--- a/test/integration/http_api.js
+++ b/test/integration/http_api.js
@@ -7,13 +7,13 @@ 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 user      = require('./tools/user');
+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').Constants.CORES_MAXIMUM_USE_IN_PARALLEL = 1
+require('../../app/modules/prover/lib/constants').ProverConstants.CORES_MAXIMUM_USE_IN_PARALLEL = 1
 
 let server, server2, cat, toc
 
@@ -64,8 +64,8 @@ describe("HTTP API", function() {
         }
       });
 
-    cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: server });
-    toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: server });
+    cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: server });
+    toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: server });
 
     commit = makeBlockAndPost(server);
 
diff --git a/test/integration/identity-absorption.js b/test/integration/identity-absorption.js
index 2c0574f14e31b86e1655dbb4948cc988251210c2..2f85059b9ec5b096578b8f23ba1d307833d8e223 100644
--- a/test/integration/identity-absorption.js
+++ b/test/integration/identity-absorption.js
@@ -4,7 +4,7 @@ const _         = require('underscore');
 const co        = require('co');
 const duniter     = require('../../index');
 const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const rp        = require('request-promise');
 const httpTest  = require('./tools/http');
 const toolbox   = require('./tools/toolbox');
@@ -51,8 +51,8 @@ describe("Identity absorption", function() {
         }
       }, commonConf));
 
-    cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    tic = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s2 });
+    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());
diff --git a/test/integration/identity-clean-test.js b/test/integration/identity-clean-test.js
index df0606b4f524f8bb5e623b0f8edf254a991a778e..99e5c4686797fba6583af9872ff25a961622abcb 100644
--- a/test/integration/identity-clean-test.js
+++ b/test/integration/identity-clean-test.js
@@ -4,7 +4,7 @@ const _         = require('underscore');
 const co        = require('co');
 const duniter     = require('../../index');
 const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const rp        = require('request-promise');
 const httpTest  = require('./tools/http');
 const commit    = require('./tools/commit');
@@ -40,10 +40,10 @@ describe("Identities cleaned", function() {
         }
       }, commonConf));
 
-    cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    tic = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
-    toc = user('cat', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
-    tac = user('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
+    cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
+    tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
+    toc = new TestUser('cat', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
+    tac = new TestUser('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
 
     const commitS1 = commit(s1);
 
diff --git a/test/integration/identity-expiry.js b/test/integration/identity-expiry.js
index c6a80f1aee095c7d16463f211696a0dd90b6a68c..58ba310cb142cdaac7d8ec190151a25de0952e2b 100644
--- a/test/integration/identity-expiry.js
+++ b/test/integration/identity-expiry.js
@@ -6,7 +6,7 @@ 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 user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const constants = require('../../app/lib/constants');
 const rp        = require('request-promise');
 const httpTest  = require('./tools/http');
@@ -50,10 +50,10 @@ describe("Identities expiry", function() {
           }
         }, commonConf));
 
-      cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-      tac = user('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
-      tic = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
-      toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
+      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)
diff --git a/test/integration/identity-implicit-revocation.js b/test/integration/identity-implicit-revocation.js
index 255778f2ca2b7c5ab87da36b36f40b98de95aa81..ee1475f9dc9970ef57e18afd27a56e292a3f4e3b 100644
--- a/test/integration/identity-implicit-revocation.js
+++ b/test/integration/identity-implicit-revocation.js
@@ -6,7 +6,7 @@ const assert    = require('assert');
 const should    = require('should');
 const duniter   = require('../../index');
 const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const constants = require('../../app/lib/constants');
 const toolbox   = require('./tools/toolbox');
 
@@ -29,9 +29,9 @@ describe("Implicit revocation", function() {
       medianTimeBlocks: 1
     });
 
-    cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    tac = user('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
-    tic = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
+    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 });
 
     yield s1.initDalBmaConnections();
     yield cat.createIdentity();
diff --git a/test/integration/identity-kicking-by-certs.js b/test/integration/identity-kicking-by-certs.js
index 199bf75e142ba022f1e44826e9a9a4cc86c31c48..2d52411324853015f58a761bf98574360f5b6c69 100644
--- a/test/integration/identity-kicking-by-certs.js
+++ b/test/integration/identity-kicking-by-certs.js
@@ -2,7 +2,7 @@
 
 const co        = require('co');
 const assert    = require('assert');
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const toolbox   = require('./tools/toolbox');
 
 const now = 1480000000;
@@ -25,11 +25,11 @@ describe("Identities kicking by certs", function() {
       sigQty: 2
     });
 
-    cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    tac = user('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
-    tic = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
-    toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
-    tuc = user('tuc', { pub: '3conGDUXdrTGbQPMQQhEC4Ubu1MCAnFrAYvUaewbUhtk', sec: '5ks7qQ8Fpkin7ycXpxQSxxjVhs8VTzpM3vEBMqM7NfC1ZiFJ93uQryDcoM93Mj77T6hDAABdeHZJDFnkDb35bgiU'}, { server: s1 });
+    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 });
+    tuc = new TestUser('tuc', { pub: '3conGDUXdrTGbQPMQQhEC4Ubu1MCAnFrAYvUaewbUhtk', sec: '5ks7qQ8Fpkin7ycXpxQSxxjVhs8VTzpM3vEBMqM7NfC1ZiFJ93uQryDcoM93Mj77T6hDAABdeHZJDFnkDb35bgiU'}, { server: s1 });
 
     yield s1.initDalBmaConnections();
     yield cat.createIdentity();
diff --git a/test/integration/identity-kicking.js b/test/integration/identity-kicking.js
index b6e91d65a027d945262e1cf111e8bee62017166f..ac90bc8f6ac8e433c65bd8c8716128f7fc0ecfa7 100644
--- a/test/integration/identity-kicking.js
+++ b/test/integration/identity-kicking.js
@@ -5,7 +5,7 @@ const co        = require('co');
 const should    = require('should');
 const duniter   = require('../../index');
 const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const constants = require('../../app/lib/constants');
 const rp        = require('request-promise');
 const httpTest  = require('./tools/http');
@@ -47,9 +47,9 @@ describe("Identities kicking", function() {
           }
         }, commonConf));
 
-      cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-      tac = user('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
-      toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
+      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());
diff --git a/test/integration/identity-pulling.js b/test/integration/identity-pulling.js
index 6cfffb2fbcfda85eeecd793ecc419a5d2c688749..427d792e2e73a8b5ae47f88c14d9a92d04980ed9 100644
--- a/test/integration/identity-pulling.js
+++ b/test/integration/identity-pulling.js
@@ -3,7 +3,7 @@
 const _ = require('underscore');
 const co        = require('co');
 const assert    = require('assert');
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const commit    = require('./tools/commit');
 const toolbox   = require('./tools/toolbox');
 
@@ -26,11 +26,11 @@ describe("Identity pulling", function() {
       }
     });
 
-    cat1 = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    tac1 = user('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
-    toc2 = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s2 });
-    tic2 = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s2 });
-    tuc2 = user('tuc', { pub: '3conGDUXdrTGbQPMQQhEC4Ubu1MCAnFrAYvUaewbUhtk', sec: '5ks7qQ8Fpkin7ycXpxQSxxjVhs8VTzpM3vEBMqM7NfC1ZiFJ93uQryDcoM93Mj77T6hDAABdeHZJDFnkDb35bgiU'}, { server: s2 });
+    cat1 = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
+    tac1 = new TestUser('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
+    toc2 = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s2 });
+    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();
diff --git a/test/integration/identity-same-pubkey.js b/test/integration/identity-same-pubkey.js
index 65480a3d1141168a0a17c5a7645036a76c25de2e..d42dc0067697d0977f809cdcd5f343015a33ec50 100644
--- a/test/integration/identity-same-pubkey.js
+++ b/test/integration/identity-same-pubkey.js
@@ -3,7 +3,7 @@
 const co        = require('co');
 const should    = require('should');
 const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const commit    = require('./tools/commit');
 const toolbox   = require('./tools/toolbox');
 
@@ -20,9 +20,9 @@ describe("Identities with shared pubkey", function() {
       }
     });
 
-    cat1 = user('cat1', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    cat2 = user('cat2', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    catb = user('cat1', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
+    cat1 = new TestUser('cat1', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
+    cat2 = new TestUser('cat2', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
+    catb = new TestUser('cat1', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
 
     yield s1.initDalBmaConnections();
 
diff --git a/test/integration/identity-test.js b/test/integration/identity-test.js
index 59612a366849a909a0f8c11e03958f7d2089ea32..de996d07f844d9971a1acdb5a58961801f937ed9 100644
--- a/test/integration/identity-test.js
+++ b/test/integration/identity-test.js
@@ -5,7 +5,7 @@ const co        = require('co');
 const should    = require('should');
 const duniter     = require('../../index');
 const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const constants = require('../../app/lib/constants');
 const rp        = require('request-promise');
 const httpTest  = require('./tools/http');
@@ -44,14 +44,14 @@ describe("Identities collision", function() {
         }
       }, commonConf));
 
-    cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    tac = user('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
-    toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
-    tic = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
-    tic2 = user('tic', { pub: '4KEA63RCFF7AXUePPg5Q7JX9RtzXjywai1iKmE7LcoEC', sec: '48vHGE2xkhnC81ChSu7dHaNv8JqnYubyyHRbkmkeAPKNg8Tv2BE7kVi3voh2ZhfVpQhEJLzceufzqpJ2dqnyXNSp'}, { server: s1 });
-    man1 = user('man1', { pub: '12AbjvYY5hxV4v2KrN9pnGzgFxogwrzgYyncYHHsyFDK', sec: '2h8UNKE4YRnjmTGQTrgf4DZp2h3F5LqjnecxP8AgU6aH1x4dvbNVirsNeBiSR2UQfExuLAbdXiyM465hb5qUxYC1'}, { server: s1 });
-    man2 = user('man2', { pub: 'E44RxG9jKZQsaPLFSw2ZTJgW7AVRqo1NGy6KGLbKgtNm', sec: 'pJRwpaCWshKZNWsbDxAHFQbVjk6X8gz9eBy9jaLnVY9gUZRqotrZLZPZe68ag4vEX1Y8mX77NhPXV2hj9F1UkX3'}, { server: s1 });
-    man3 = user('man3', { pub: '5bfpAfZJ4xYspUBYseASJrofhRm6e6JMombt43HBaRzW', sec: '2VFQtEcYZRwjoc8Lxwfzcejtw9VP8VAi47WjwDDjCJCXu7g1tXUAbVZN3QmvG6NJqaSuLCuYP7WDHWkFmTrUEMaE'}, { server: s1 });
+    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 });
+    tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
+    tic2 = new TestUser('tic', { pub: '4KEA63RCFF7AXUePPg5Q7JX9RtzXjywai1iKmE7LcoEC', sec: '48vHGE2xkhnC81ChSu7dHaNv8JqnYubyyHRbkmkeAPKNg8Tv2BE7kVi3voh2ZhfVpQhEJLzceufzqpJ2dqnyXNSp'}, { server: s1 });
+    man1 = new TestUser('man1', { pub: '12AbjvYY5hxV4v2KrN9pnGzgFxogwrzgYyncYHHsyFDK', sec: '2h8UNKE4YRnjmTGQTrgf4DZp2h3F5LqjnecxP8AgU6aH1x4dvbNVirsNeBiSR2UQfExuLAbdXiyM465hb5qUxYC1'}, { server: s1 });
+    man2 = new TestUser('man2', { pub: 'E44RxG9jKZQsaPLFSw2ZTJgW7AVRqo1NGy6KGLbKgtNm', sec: 'pJRwpaCWshKZNWsbDxAHFQbVjk6X8gz9eBy9jaLnVY9gUZRqotrZLZPZe68ag4vEX1Y8mX77NhPXV2hj9F1UkX3'}, { server: s1 });
+    man3 = new TestUser('man3', { pub: '5bfpAfZJ4xYspUBYseASJrofhRm6e6JMombt43HBaRzW', sec: '2VFQtEcYZRwjoc8Lxwfzcejtw9VP8VAi47WjwDDjCJCXu7g1tXUAbVZN3QmvG6NJqaSuLCuYP7WDHWkFmTrUEMaE'}, { server: s1 });
 
     const commitS1 = commit(s1);
 
diff --git a/test/integration/lookup.js b/test/integration/lookup.js
index 44de12ffef99189fd39328845fce0374b8b7fb3d..381ebf67e55d5262a9ccaacec59fc328402940c9 100644
--- a/test/integration/lookup.js
+++ b/test/integration/lookup.js
@@ -4,7 +4,7 @@ const _         = require('underscore');
 const co        = require('co');
 const duniter     = require('../../index');
 const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const rp        = require('request-promise');
 const httpTest  = require('./tools/http');
 const shutDownEngine  = require('./tools/shutDownEngine');
@@ -32,9 +32,9 @@ describe("Lookup identity grouping", () => {
         }
       }, commonConf));
 
-    cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    tic1 = user('tic1', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
-    tic2 = user('tic2', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
+    cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
+    tic1 = new TestUser('tic1', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
+    tic2 = new TestUser('tic2', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
 
     // Server initialization
     yield s1.initWithDAL().then(bma).then((bmapi) => bmapi.openConnections());
diff --git a/test/integration/network-update.js b/test/integration/network-update.js
index 7d533a0974494eaa9c55d18e48ea7827714f8700..44c7ce9293b128fd57563f2c44527f610e265adb 100644
--- a/test/integration/network-update.js
+++ b/test/integration/network-update.js
@@ -5,7 +5,7 @@ const _         = require('underscore');
 const rp        = require('request-promise');
 const httpTest  = require('./tools/http');
 const node      = require('./tools/node');
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const commit    = require('./tools/commit');
 const sync      = require('./tools/sync');
 const until     = require('./tools/until');
@@ -51,8 +51,8 @@ describe("Network updating", function() {
       s1 = toolbox.server(_.clone(catKeyPair));
       s2 = toolbox.server(_.clone(tocKeyPair));
 
-      cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-      toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
+      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);
diff --git a/test/integration/newcomers-shuffling.js b/test/integration/newcomers-shuffling.js
index 6d9e0ffd2ea6cf83b3f1f7b517dbbc3e045fe7b4..0de6bdc11e52590825adaf6ca3458a8806a3ca26 100644
--- a/test/integration/newcomers-shuffling.js
+++ b/test/integration/newcomers-shuffling.js
@@ -3,7 +3,7 @@
 const _ = require('underscore');
 const co        = require('co');
 const assert    = require('assert');
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const commit    = require('./tools/commit');
 const toolbox   = require('./tools/toolbox');
 
@@ -20,10 +20,10 @@ describe("Newcomers shuffling", function() {
       }
     });
 
-    cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    tac = user('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
-    toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
-    tic = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
+    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 });
+    tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
 
     yield s1.prepareForNetwork();
 
diff --git a/test/integration/peer-outdated.js b/test/integration/peer-outdated.js
index 31af4bc78417a86a6f93577b7479aa5d53ce344e..3f2cb0e1f4b37553114a501b8b8ceb66e34c4ab5 100644
--- a/test/integration/peer-outdated.js
+++ b/test/integration/peer-outdated.js
@@ -5,7 +5,7 @@ const should    = require('should');
 const es        = require('event-stream');
 const _         = require('underscore');
 const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const commit    = require('./tools/commit');
 const until     = require('./tools/until');
 const toolbox   = require('./tools/toolbox');
@@ -34,8 +34,8 @@ describe("Peer document expiry", function() {
       }
     });
 
-    cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
+    cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
+    toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
 
     const commitS1 = commit(s1);
 
diff --git a/test/integration/peerings.js b/test/integration/peerings.js
index da7f16c6e538c29d12a5e42e198e2f99d6e0c49c..4b227f6317b951c2776dbd8b32a672bf31ca4237 100644
--- a/test/integration/peerings.js
+++ b/test/integration/peerings.js
@@ -5,7 +5,7 @@ const _         = require('underscore');
 const should    = require('should');
 const duniter     = require('../../index');
 const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const constants = require('../../app/lib/constants');
 const rp        = require('request-promise');
 const httpTest  = require('./tools/http');
@@ -74,9 +74,9 @@ describe("Network", function() {
         }
       }, commonConf));
 
-    cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
-    tic = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: 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 });
 
     const commitS1 = commit(s1);
     const commitS2 = commit(s2);
diff --git a/test/integration/peers-same-pubkey.js b/test/integration/peers-same-pubkey.js
index 6afed89fab1f4148377b1e7054c52517d25af363..41c4b9c19edb5c6362a53784f1120d73fae53cb4 100644
--- a/test/integration/peers-same-pubkey.js
+++ b/test/integration/peers-same-pubkey.js
@@ -3,7 +3,7 @@
 const co        = require('co');
 const _         = require('underscore');
 const should    = require('should');
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const commit    = require('./tools/commit');
 const sync      = require('./tools/sync');
 const until     = require('./tools/until');
@@ -27,8 +27,8 @@ describe("Peer document", function() {
     s2 = toolbox.server(_.clone(catKeyPair));
     s3 = toolbox.server(_.clone(catKeyPair));
 
-    cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
+    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);
diff --git a/test/integration/register-fork-blocks.js b/test/integration/register-fork-blocks.js
index cf1faf59ba15289bd67d3cdb067a3cf53b1bd990..c308cf78fb1f28118c5f45afc0fb2a0f8750bdd8 100644
--- a/test/integration/register-fork-blocks.js
+++ b/test/integration/register-fork-blocks.js
@@ -3,7 +3,7 @@
 const _ = require('underscore');
 const co        = require('co');
 const assert    = require('assert');
-const user      = require('./tools/user');
+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
@@ -20,6 +20,7 @@ describe("Fork blocks", function() {
     s1 = toolbox.server({
 
       // The common conf
+      nbCores:1,
       medianTimeBlocks: 1,
       avgGenTime: 11,
       udTime0: now,
@@ -35,6 +36,7 @@ describe("Fork blocks", function() {
     s2 = toolbox.server({
 
       // Particular conf
+      nbCores:1,
       switchOnHeadAdvance: 5,
       forksize,
 
@@ -47,6 +49,7 @@ describe("Fork blocks", function() {
     s3 = toolbox.server({
 
       // Particular conf
+      nbCores:1,
       switchOnHeadAdvance: 5,
       forksize,
 
@@ -56,9 +59,9 @@ describe("Fork blocks", function() {
       }
     });
 
-    cat1 = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    tac1 = user('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
-    toc1 = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
+    cat1 = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
+    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();
diff --git a/test/integration/revocation-test.js b/test/integration/revocation-test.js
index 63300af0ef0ddba6bd5786d1fd4e26d78f4150be..a49dce4560ae3e037c1724c790b1e81526491aca 100644
--- a/test/integration/revocation-test.js
+++ b/test/integration/revocation-test.js
@@ -5,7 +5,7 @@ const co        = require('co');
 const should    = require('should');
 const duniter   = require('../../index');
 const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const rp        = require('request-promise');
 const httpTest  = require('./tools/http');
 const commit    = require('./tools/commit');
@@ -59,11 +59,11 @@ describe("Revocation", function() {
           }
         }, commonConf));
 
-      cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-      tic = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
-      toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
-      tacOnS1 = user('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
-      tacOnS2 = user('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s2 });
+      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());
diff --git a/test/integration/revoked_pubkey_replay.ts b/test/integration/revoked_pubkey_replay.ts
index dbaddc9a2104d9b265e4912fbbeb0827dc7e5d14..03f4bab6a3977a3c6530fa2e396fa8bf0ce39bb2 100644
--- a/test/integration/revoked_pubkey_replay.ts
+++ b/test/integration/revoked_pubkey_replay.ts
@@ -1,7 +1,7 @@
 import {simpleNodeWith2Users, TestingServer} from "./tools/toolbox"
 
 const _ = require('underscore')
-const user = require('./tools/user')
+const TestUser = require('./tools/TestUser').TestUser
 
 describe("Revoked pubkey replay", function() {
 
@@ -15,7 +15,7 @@ describe("Revoked pubkey replay", function() {
     const res1 = await simpleNodeWith2Users(conf)
     s1 = res1.s1
     cat = res1.cat
-    tic = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 })
+    tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 })
     await s1.commit({ time: now })
     await s1.commit({ time: now })
     // Create the tested identity « tic »
diff --git a/test/integration/server-import-export.js b/test/integration/server-import-export.js
index b4ab2c49f01675a046f76078abf489d2f5b88bb9..4c56854060f461cae02c95fa7b4629b40e4b9966 100644
--- a/test/integration/server-import-export.js
+++ b/test/integration/server-import-export.js
@@ -5,7 +5,7 @@ const fs = require('fs');
 const co = require('co');
 const unzip = require('unzip');
 const toolbox = require('../integration/tools/toolbox');
-const user    = require('../integration/tools/user');
+const TestUser = require('../integration/tools/TestUser').TestUser
 const bma     = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
 
 const serverConfig = {
@@ -26,8 +26,8 @@ describe('Import/Export', () => {
 
     s1 = toolbox.server(_.extend({ homename: 'dev_unit_tests1' }, serverConfig));
 
-    const cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    const tac = user('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
+    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();
diff --git a/test/integration/server-sandbox.js b/test/integration/server-sandbox.js
index b50525515188e69ec04051b0d2948f3d2149932a..e3d438be419c4680a3801b2c9a61938114af7d31 100644
--- a/test/integration/server-sandbox.js
+++ b/test/integration/server-sandbox.js
@@ -3,7 +3,7 @@
 const co        = require('co');
 const should    = require('should');
 const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const commit    = require('./tools/commit');
 const toolbox   = require('./tools/toolbox');
 const constants = require('../../app/lib/constants');
@@ -43,23 +43,23 @@ describe("Sandboxes", function() {
       }
     });
 
-    i1 = user('i1',   { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    i2 = user('i2',   { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
-    i3 = user('i3',   { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
-    i4 = user('i4',   { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
-    i5 = user('i5',   { pub: '91dWdiyf7KaC4GAiKrwU7nGuue1vvmHqjCXbPziJFYtE', sec: '4Zno2b8ZULwBLY3RU5JcZhUf2a5FfXLVUMaYwPEzzN6i4ow9vXPsiCq7u2pEhkgJywqWdj97Hje1fdqnnzHeFgQe'}, { server: s1 });
-    i6 = user('i6',   { pub: '3C95HniUZsUN55AJy7z4wkz1UwtebbNd63dVAZ6EaUNm', sec: '3iJMz8JKNeU692L7jvug8xVnKvzN9RDee2m6QkMKbWKrvoHhv6apS4LR9hP786PUyFYJWz8bReMrFK8PY3aGxB8m'}, { server: s1 });
-    i7 = user('i7',   { pub: '4e9QJhJqHfMzEHgt3GtbfCXjqHVaQuJZKrKt8CNKR3AF', sec: 'TqdT99RpPEUjiz8su5QY7AQwharxPeo4ELCmeaFcvBEd3fW7wY7s9i531LMnTrCYBsgkrES494V6KjkhGppyEcF' }, { server: s1 });
-    i7onS2 = user('i7',   { pub: '4e9QJhJqHfMzEHgt3GtbfCXjqHVaQuJZKrKt8CNKR3AF', sec: 'TqdT99RpPEUjiz8su5QY7AQwharxPeo4ELCmeaFcvBEd3fW7wY7s9i531LMnTrCYBsgkrES494V6KjkhGppyEcF' }, { server: s2 });
-    i8 = user('i8',   { pub: '6GiiWjJxr29Stc4Ph4J4EipZJCzaQW1j6QXKANTNzRV3', sec: 'Yju625FGz6FHErshRc7jZyJUJ83MG4Zh9TXUNML62rKLXz7VJmwofnhJzeRRensranFJGQMYBLNSAeycAAsp62m' }, { server: s1 });
-    i9 = user('i9',   { pub: '6v4HnmiGxNzKwEjnBqxicWAmdKo6Bk51GvfQByS5YmiB', sec: '2wXPPDYfM3a8jmpYiFihS9qzdqFZrLWryu4uwpNPRuw5TRW3JCdJPsMa64eAcpshLTnMXkrKL94argk3FGxzzBKh' }, { server: s1 });
-    i10 = user('i10', { pub: '6kr9Xr86qmrrwGq3XEjUXRVpHqS63FL52tcutcYGcRiv', sec: '2jCzQx7XUWoxboH67mMMv2z8VcrQabtYWpxS39iF6hNQnSBwN1d9RVauVC52PTRz6mgMzTjrSMETPrrB5N3oC7qQ' }, { server: s1 });
-    i11 = user('i11', { pub: '5VLVTp96iX3YAq7NXwZeM2N6RjCkmxaU4G6bwMg1ZNwf', sec: '3BJtyeH1Q8jPcKuzL35m4eVPGuFXpcfRiGSseVawToCWykz1qAic9V2wk31wzEqXjqCq7ZKW4MjtZrzKCGN5K7sT' }, { server: s1 });
-    i12 = user('i12', { pub: 'D6zJSPxZqs1bpgGpzJu9MgkCH7UxkG7D5u4xnnSH62wz', sec: '375vhCZdmVx7MaYD4bMZCevRLtebSuNPucfGevyPiPtdqpRzYLLNfd1h25Q59h4bm54dakpZ1RJ45ZofAyBmX4Et' }, { server: s1 });
-    i13 = user('i13', { pub: 'BQ1fhCsJGohYKKfCbt58zQ8RpiSy5M8vwzdXzm4rH7mZ', sec: '4bTX2rMeAv8x79xQdFWPgY8zQLbPZ4HE7MWKXoXHyCoYgeCFpiWLdfvXwTbt31UMGrkNp2CViEt68WkjAZAQkjjm' }, { server: s1 });
-    i14 = user('i14', { pub: 'H9dtBFmJohAwMNXSbfoL6xfRtmrqMw8WZnjXMHr4vEHX', sec: '2ANWb1qjjYRtT2TPFv1rBWA4EVfY7pqE4WqFUuzEgWG4vzcuvyUxMtyeBSf93M4V3g4MeEkELaj6NjA72jxnb4yF' }, { server: s1 });
-// i15 = user('i15', { pub: '8cHWEmVrdT249w8vJdiBms9mbu6CguQgXx2gRVE8gfnT', sec: '5Fy9GXiLMyhvRLCpoFf35XXNj24WXX29wM6xeCQiy5Uk7ggNhRcZjjp8GcpjRyE94oNR2jRNK4eAGiYUFnvbEnGB' }, { server: s1 });
-// i16 = user('i16', { pub: 'vi8hUTxss825cFCQE4SzmqBaAwLS236NmtrTQZBAAhG',  sec: '5dVvAdWKcndQSaR9pzjEriRhGkCjef74HzecqKnydBVHdxXDewpAu3mcSU72PRKcCkTYTJPpgWmwuCyZubDKmoy4' }, { server: s1 });
+    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 });
+    i4 = new TestUser('i4',   { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
+    i5 = new TestUser('i5',   { pub: '91dWdiyf7KaC4GAiKrwU7nGuue1vvmHqjCXbPziJFYtE', sec: '4Zno2b8ZULwBLY3RU5JcZhUf2a5FfXLVUMaYwPEzzN6i4ow9vXPsiCq7u2pEhkgJywqWdj97Hje1fdqnnzHeFgQe'}, { server: s1 });
+    i6 = new TestUser('i6',   { pub: '3C95HniUZsUN55AJy7z4wkz1UwtebbNd63dVAZ6EaUNm', sec: '3iJMz8JKNeU692L7jvug8xVnKvzN9RDee2m6QkMKbWKrvoHhv6apS4LR9hP786PUyFYJWz8bReMrFK8PY3aGxB8m'}, { server: s1 });
+    i7 = new TestUser('i7',   { pub: '4e9QJhJqHfMzEHgt3GtbfCXjqHVaQuJZKrKt8CNKR3AF', sec: 'TqdT99RpPEUjiz8su5QY7AQwharxPeo4ELCmeaFcvBEd3fW7wY7s9i531LMnTrCYBsgkrES494V6KjkhGppyEcF' }, { server: s1 });
+    i7onS2 = new TestUser('i7',   { pub: '4e9QJhJqHfMzEHgt3GtbfCXjqHVaQuJZKrKt8CNKR3AF', sec: 'TqdT99RpPEUjiz8su5QY7AQwharxPeo4ELCmeaFcvBEd3fW7wY7s9i531LMnTrCYBsgkrES494V6KjkhGppyEcF' }, { server: s2 });
+    i8 = new TestUser('i8',   { pub: '6GiiWjJxr29Stc4Ph4J4EipZJCzaQW1j6QXKANTNzRV3', sec: 'Yju625FGz6FHErshRc7jZyJUJ83MG4Zh9TXUNML62rKLXz7VJmwofnhJzeRRensranFJGQMYBLNSAeycAAsp62m' }, { server: s1 });
+    i9 = new TestUser('i9',   { pub: '6v4HnmiGxNzKwEjnBqxicWAmdKo6Bk51GvfQByS5YmiB', sec: '2wXPPDYfM3a8jmpYiFihS9qzdqFZrLWryu4uwpNPRuw5TRW3JCdJPsMa64eAcpshLTnMXkrKL94argk3FGxzzBKh' }, { server: s1 });
+    i10 = new TestUser('i10', { pub: '6kr9Xr86qmrrwGq3XEjUXRVpHqS63FL52tcutcYGcRiv', sec: '2jCzQx7XUWoxboH67mMMv2z8VcrQabtYWpxS39iF6hNQnSBwN1d9RVauVC52PTRz6mgMzTjrSMETPrrB5N3oC7qQ' }, { server: s1 });
+    i11 = new TestUser('i11', { pub: '5VLVTp96iX3YAq7NXwZeM2N6RjCkmxaU4G6bwMg1ZNwf', sec: '3BJtyeH1Q8jPcKuzL35m4eVPGuFXpcfRiGSseVawToCWykz1qAic9V2wk31wzEqXjqCq7ZKW4MjtZrzKCGN5K7sT' }, { server: s1 });
+    i12 = new TestUser('i12', { pub: 'D6zJSPxZqs1bpgGpzJu9MgkCH7UxkG7D5u4xnnSH62wz', sec: '375vhCZdmVx7MaYD4bMZCevRLtebSuNPucfGevyPiPtdqpRzYLLNfd1h25Q59h4bm54dakpZ1RJ45ZofAyBmX4Et' }, { server: s1 });
+    i13 = new TestUser('i13', { pub: 'BQ1fhCsJGohYKKfCbt58zQ8RpiSy5M8vwzdXzm4rH7mZ', sec: '4bTX2rMeAv8x79xQdFWPgY8zQLbPZ4HE7MWKXoXHyCoYgeCFpiWLdfvXwTbt31UMGrkNp2CViEt68WkjAZAQkjjm' }, { server: s1 });
+    i14 = new TestUser('i14', { pub: 'H9dtBFmJohAwMNXSbfoL6xfRtmrqMw8WZnjXMHr4vEHX', sec: '2ANWb1qjjYRtT2TPFv1rBWA4EVfY7pqE4WqFUuzEgWG4vzcuvyUxMtyeBSf93M4V3g4MeEkELaj6NjA72jxnb4yF' }, { server: s1 });
+// 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();
diff --git a/test/integration/server-shutdown.ts b/test/integration/server-shutdown.ts
index 854e20eae037d8e801a7d1fab6b827033b43b0e9..033ef307691e3a2ea9d19c879c69a967fc81fae4 100644
--- a/test/integration/server-shutdown.ts
+++ b/test/integration/server-shutdown.ts
@@ -1,3 +1,5 @@
+import { ConfDTO } from '../../app/lib/dto/ConfDTO';
+import { setTimeout } from 'timers';
 import {NewTestingServer} from "./tools/toolbox"
 
 const should = require('should')
diff --git a/test/integration/single-document-treatment.js b/test/integration/single-document-treatment.js
index a525dd8b54fcf0260b9a5a92fee121c4de03bff9..9661f4628f37b11b41dee6e6e4e815aed282746f 100644
--- a/test/integration/single-document-treatment.js
+++ b/test/integration/single-document-treatment.js
@@ -3,7 +3,7 @@
 const _ = require('underscore');
 const co        = require('co');
 const assert    = require('assert');
-const user      = require('./tools/user');
+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
@@ -35,8 +35,8 @@ describe("Single document treatment", function() {
       }
     });
 
-    cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    tac = user('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
+    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();
diff --git a/test/integration/start_generate_blocks.js b/test/integration/start_generate_blocks.js
index c71bd8c808a9f997afed7a64d7f4861a6ac5e3c3..3c79c48341eadb7b7948f71467ac79fd44259b78 100644
--- a/test/integration/start_generate_blocks.js
+++ b/test/integration/start_generate_blocks.js
@@ -4,7 +4,7 @@ const co        = require('co');
 const _         = require('underscore');
 const duniter     = require('../../index');
 const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const rp        = require('request-promise');
 const httpTest  = require('./tools/http');
 const commit    = require('./tools/commit');
@@ -65,10 +65,10 @@ describe("Generation", function() {
 
       const commitS1 = commit(s1);
 
-      cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-      toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
-      tic = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
-      tuc = user('tuc', { pub: '3conGDUXdrTGbQPMQQhEC4Ubu1MCAnFrAYvUaewbUhtk', sec: '5ks7qQ8Fpkin7ycXpxQSxxjVhs8VTzpM3vEBMqM7NfC1ZiFJ93uQryDcoM93Mj77T6hDAABdeHZJDFnkDb35bgiU'}, { server: 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) {
diff --git a/test/integration/tests.js b/test/integration/tests.js
index 3848b6b9b51e7330c2697dd2b1ac6a5ec6542fda..8f910656746aa8c80c759dbcba11284b0664d7aa 100644
--- a/test/integration/tests.js
+++ b/test/integration/tests.js
@@ -8,7 +8,7 @@ const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods
 const constants = require('../../app/lib/constants');
 const node   = require('./tools/node');
 const duniter     = require('../../index');
-const user   = require('./tools/user');
+const TestUser = require('./tools/TestUser').TestUser
 const jspckg = require('../../package');
 const commit    = require('./tools/commit');
 const httpTest  = require('./tools/http');
@@ -33,10 +33,10 @@ describe("Integration", function() {
       }
     });
 
-    const cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, node1);
-    const tac = user('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, node1);
-    const tic = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, node1);
-    const toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, node1);
+    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()
@@ -187,10 +187,10 @@ describe("Integration", function() {
           }
         });
 
-        cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: node3 });
-        tac = user('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: node3 });
-        tic = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: node3 });
-        toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: node3 });
+        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;
diff --git a/test/integration/tools/TestUser.ts b/test/integration/tools/TestUser.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8c6cf1303b0a0c5926bda5556edba3e80d903c3e
--- /dev/null
+++ b/test/integration/tools/TestUser.ts
@@ -0,0 +1,403 @@
+import {KeyGen} from "../../../app/lib/common-libs/crypto/keyring"
+import {IdentityDTO} from "../../../app/lib/dto/IdentityDTO";
+import {TestingServer} from "./toolbox"
+import {CommonConstants} from "../../../app/lib/common-libs/constants"
+import {CertificationDTO} from "../../../app/lib/dto/CertificationDTO"
+import {MembershipDTO} from "../../../app/lib/dto/MembershipDTO"
+import {RevocationDTO} from "../../../app/lib/dto/RevocationDTO"
+import {CrawlerDependency} from "../../../app/modules/crawler/index"
+import {Buid} from "../../../app/lib/common-libs/buid"
+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"
+
+const request	= require('request')
+const _ = require('underscore')
+
+export interface TestInput {
+  src:string
+  unlock:string
+}
+
+export interface TestOutput {
+  qty:number
+  base:number
+  lock:string
+}
+
+export class TestUser {
+
+  public pub = ""
+  public sec = ""
+  private createdIdentity = ""
+
+  constructor(public uid:string, private options:any, public node:any) {
+    // For sync code
+    if (this.options.pub && this.options.sec) {
+      this.pub = this.options.pub
+      this.sec = this.options.sec
+    }
+  }
+
+  private init(done:()=>void) {
+    if (this.options.pub && this.options.sec) {
+      this.pub = this.options.pub
+      this.sec = this.options.sec
+      done()
+    } else {
+      throw 'Not keypair information given for testing user ' + this.uid
+    }
+  }
+
+  public async createIdentity(useRoot?:boolean, fromServer?:any) {
+    if (!this.pub) {
+      this.init(() => {})
+    }
+    const current = await this.node.server.BlockchainService.current();
+    let buid = !useRoot && current ? Buid.format.buid(current.number, current.hash) : CommonConstants.SPECIAL_BLOCK
+    this.createdIdentity = IdentityDTO.fromJSONObject({
+      buid: buid,
+      uid: this.uid,
+      issuer: this.pub,
+      currency: this.node.server.conf.currency
+    }).getRawUnSigned()
+    this.createdIdentity += KeyGen(this.pub, this.sec).signSync(this.createdIdentity) + '\n'
+    await this.submitIdentity(this.createdIdentity, fromServer);
+  }
+
+  public submitIdentity(raw:string, fromServer:any) {
+    return this.doPost('/wot/add', {
+      "identity": raw
+    }, fromServer)
+  }
+
+  public getIdentityRaw() {
+    return this.createdIdentity
+  }
+
+  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]
+    let buid = current ? Buid.format.buid(current.number, current.hash) : CommonConstants.SPECIAL_BLOCK
+    const cert = {
+      "version": CommonConstants.DOCUMENTS_VERSION,
+      "currency": this.node.server.conf.currency,
+      "issuer": this.pub,
+      "idty_issuer": user.pub,
+      "idty_uid": idty.uid,
+      "idty_buid": idty.meta.timestamp,
+      "idty_sig": idty.self,
+      "buid": buid,
+      "sig": ""
+    }
+    _.extend(cert, overrideProps || {});
+    const rawCert = CertificationDTO.fromJSONObject(cert).getRawUnSigned()
+    cert.sig = KeyGen(this.pub, this.sec).signSync(rawCert)
+    return CertificationDTO.fromJSONObject(cert)
+  }
+
+  public async cert(user:TestUser, fromServer?:TestingServer, toServer?:TestingServer) {
+    const cert = await this.makeCert(user, fromServer)
+    await this.doPost('/wot/certify', {
+      "cert": cert.getRawSigned()
+    }, toServer);
+  }
+
+  public async join() {
+    return await this.sendMembership("IN")
+  }
+
+  public async leave() {
+    return await this.sendMembership("OUT")
+  }
+
+  public async makeRevocation(givenLookupIdty?:any, 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 idty = {
+      uid: matchingResult.uid,
+      buid: matchingResult.meta.timestamp,
+      sig: matchingResult.self
+    }
+    const revocation = {
+      "currency": this.node.server.conf.currency,
+      "issuer": this.pub,
+      "uid": idty.uid,
+      "sig": idty.sig,
+      "buid": idty.buid,
+      "revocation": ''
+    };
+    _.extend(revocation, overrideProps || {});
+    const rawRevocation = RevocationDTO.fromJSONObject(revocation).getRawUnsigned()
+    revocation.revocation = KeyGen(this.pub, this.sec).signSync(rawRevocation);
+    return RevocationDTO.fromJSONObject(revocation)
+  }
+
+  public async revoke(givenLookupIdty?:any) {
+    const revocation = await this.makeRevocation(givenLookupIdty)
+    return this.post('/wot/revoke', {
+      "revocation": revocation.getRaw()
+    })
+  }
+
+  public async makeMembership(type:string, fromServer?:TestingServer, overrideProps?:any) {
+    const lookup = await this.lookup(this.pub, fromServer)
+    const current = await this.node.server.BlockchainService.current();
+    const idty = lookup.results[0].uids[0];
+    const block = Buid.format.buid(current);
+    const join = {
+      "version": CommonConstants.DOCUMENTS_VERSION,
+      "currency": this.node.server.conf.currency,
+      "issuer": this.pub,
+      "block": block,
+      "membership": type,
+      "userid": this.uid,
+      "certts": idty.meta.timestamp,
+      "signature": ""
+    };
+    _.extend(join, overrideProps || {});
+    const rawJoin = MembershipDTO.fromJSONObject(join).getRaw()
+    join.signature = KeyGen(this.pub, this.sec).signSync(rawJoin)
+    return MembershipDTO.fromJSONObject(join)
+  }
+
+  public async sendMembership(type:string) {
+    const ms = await this.makeMembership(type);
+    await this.post('/blockchain/membership', {
+      "membership": ms.getRawSigned()
+    })
+  }
+
+  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)
+  }
+
+  public async sendTX(rawTX:string) {
+    let http = await this.getContacter()
+    return http.processTransaction(rawTX)
+  }
+
+  public async prepareUTX(previousTX:string, unlocks:string[], outputs:TestOutput[], opts:any) {
+    let obj = parsers.parseTransaction.syncWrite(previousTX);
+    // Unlocks inputs with given "unlocks" strings
+    let outputsToConsume = obj.outputs;
+    if (opts.theseOutputsStart !== undefined) {
+      outputsToConsume = outputsToConsume.slice(opts.theseOutputsStart);
+    }
+    let inputs = outputsToConsume.map((out:string, index:number) => {
+      const output = TransactionDTO.outputStr2Obj(out);
+      return {
+        src: [output.amount, output.base, 'T', obj.hash, (opts.theseOutputsStart || 0) + index].join(':'),
+        unlock: unlocks[index]
+      }
+    })
+    return this.signed(this.prepareTX(inputs, outputs, opts))
+  }
+
+  public async prepareMTX(previousTX:string, user2:TestUser, unlocks:string[], outputs:TestOutput[], opts:any) {
+    let obj = parsers.parseTransaction.syncWrite(previousTX);
+    // Unlocks inputs with given "unlocks" strings
+    let inputs = obj.outputs.map((out:string, index:number) => {
+      const output = TransactionDTO.outputStr2Obj(out);
+      return {
+        src: [output.amount, output.base, 'T', obj.hash, index].join(':'),
+        unlock: unlocks[index]
+      }
+    })
+    opts = opts || {}
+    opts.issuers = [this.pub, user2.pub]
+    return this.signed(this.prepareTX(inputs, outputs, opts), user2)
+  }
+
+  public async prepareITX(amount:number, recipient:TestUser|string, comment?:string) {
+    let sources = []
+    if (!amount || !recipient) {
+      throw 'Amount and recipient are required'
+    }
+    let http = await this.getContacter()
+    let current = await http.getCurrent()
+    let version = current && Math.min(CommonConstants.LAST_VERSION_FOR_TX, current.version)
+    let json = await http.getSources(this.pub)
+    let i = 0
+    let cumulated = 0
+    let commonbase = 99999999
+    while (i < json.sources.length) {
+      let src = json.sources[i];
+      sources.push({
+        'type': src.type,
+        'amount': src.amount,
+        'base': src.base,
+        'noffset': src.noffset,
+        'identifier': src.identifier
+      })
+      commonbase = Math.min(commonbase, src.base);
+      cumulated += src.amount * Math.pow(10, src.base);
+      i++;
+    }
+    if (cumulated < amount) {
+      throw 'You do not have enough coins! (' + cumulated + ' ' + this.node.server.conf.currency + ' left)';
+    }
+    let sources2 = [];
+    let total = 0;
+    for (let j = 0; j < sources.length && total < amount; j++) {
+      let src = sources[j];
+      total += src.amount * Math.pow(10, src.base);
+      sources2.push(src);
+    }
+    let inputSum = 0;
+    sources2.forEach((src) => inputSum += src.amount * Math.pow(10, src.base));
+    let inputs = sources2.map((src) => {
+      return {
+        src: [src.amount, src.base].concat([src.type, src.identifier, src.noffset]).join(':'),
+        unlock: 'SIG(0)'
+      };
+    });
+    let outputs = [{
+      qty: amount,
+      base: commonbase,
+      lock: 'SIG(' + (typeof recipient === 'string' ? recipient : recipient.pub) + ')'
+    }];
+    if (inputSum - amount > 0) {
+      // Rest back to issuer
+      outputs.push({
+        qty: inputSum - amount,
+        base: commonbase,
+        lock: "SIG(" + this.pub + ")"
+      });
+    }
+    let raw = this.prepareTX(inputs, outputs, {
+      version: version,
+      blockstamp: current && [current.number, current.hash].join('-'),
+      comment: comment
+    });
+    return this.signed(raw)
+  }
+
+  private signed(raw:string, user2?:TestUser) {
+    let signatures = [KeyGen(this.pub, this.sec).signSync(raw)];
+    if (user2) {
+      signatures.push(KeyGen(user2.pub, user2.sec).signSync(raw));
+    }
+    return raw + signatures.join('\n') + '\n';
+  }
+
+  public makeTX(inputs:TestInput[], outputs:TestOutput[], theOptions:any) {
+    const raw = this.prepareTX(inputs, outputs, theOptions)
+    return this.signed(raw)
+  }
+
+  public prepareTX(inputs:TestInput[], outputs:TestOutput[], theOptions:any) {
+    let opts = theOptions || {};
+    let issuers = opts.issuers || [this.pub];
+    let raw = '';
+    raw += "Version: " + (opts.version || CommonConstants.TRANSACTION_VERSION) + '\n';
+    raw += "Type: Transaction\n";
+    raw += "Currency: " + (opts.currency || this.node.server.conf.currency) + '\n';
+    raw += "Blockstamp: " + opts.blockstamp + '\n';
+    raw += "Locktime: " + (opts.locktime || 0) + '\n';
+    raw += "Issuers:\n";
+    issuers.forEach((issuer:string) => raw += issuer + '\n');
+    raw += "Inputs:\n";
+    inputs.forEach(function (input) {
+      raw += input.src + '\n';
+    });
+    raw += "Unlocks:\n";
+    inputs.forEach(function (input, index) {
+      if (input.unlock) {
+        raw += index + ":" + input.unlock + '\n';
+      }
+    });
+    raw += "Outputs:\n";
+    outputs.forEach(function (output) {
+      raw += [output.qty, output.base, output.lock].join(':') + '\n';
+    });
+    raw += "Comment: " + (opts.comment || "") + "\n";
+    return raw;
+  }
+
+  public async makePeer(endpoints:string[], overrideProps:any) {
+    const peer = PeerDTO.fromJSONObject({
+      currency: this.node.server.conf.currency,
+      pubkey: this.pub,
+      block: '2-00008DF633FC158F9DB4864ABED696C1AA0FE5D617A7B5F7AB8DE7CA2EFCD4CB',
+      endpoints: endpoints
+    });
+    _.extend(peer, overrideProps || {});
+    const rawPeer = PeerDTO.fromJSONObject(peer).getRawUnsigned()
+    peer.signature = KeyGen(this.pub, this.sec).signSync(rawPeer)
+    return PeerDTO.fromJSONObject(peer)
+  }
+
+  private async post(uri:string, data:any, done?:(e?:any, res?:any, body?:string)=>void) {
+    return new Promise((resolve, reject) => {
+      var postReq = request.post({
+        "uri": 'http://' + [this.node.server.conf.remoteipv4, this.node.server.conf.remoteport].join(':') + uri,
+        "timeout": 1000 * 100000
+      }, function (err:any, res:any, body:string) {
+        err = err || (res.statusCode != 200 && body != 'Already up-to-date' && body) || null;
+        if (err) {
+          reject(err)
+        } else {
+          resolve(res)
+        }
+        done && done(err, res, body)
+      });
+      postReq.form(data);
+    })
+  }
+
+  private async doPost(uri:string, data:any, toServer?:TestingServer) {
+    const ip = toServer ? toServer.conf.ipv4 : this.node.server.conf.remoteipv4;
+    const port = toServer ? toServer.conf.port : this.node.server.conf.remoteport;
+    return new Promise((resolve, reject) => {
+      var postReq = request.post({
+        "uri": 'http://' + [ip, port].join(':') + uri,
+        "timeout": 1000 * 100000
+      }, function (err:any, res:any, body:string) {
+        err = err || (res.statusCode != 200 && body != 'Already up-to-date' && body) || null;
+        err ? reject(err) : resolve(res);
+      });
+      postReq.form(data);
+    });
+  }
+
+  private async getContacter(fromServer?:TestingServer) {
+    const that = this
+    return new Promise<Contacter>(function(resolve){
+      let theNode = (fromServer && { server: fromServer }) || that.node
+      resolve(CrawlerDependency.duniter.methods.contacter(theNode.server.conf.ipv4, theNode.server.conf.port, {
+        timeout: 1000 * 100000
+      }));
+    });
+  }
+
+  public async lookup(pubkey:string, fromServer?:TestingServer) {
+    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/node.js b/test/integration/tools/node.js
index cb65f6ff450334decefebb12794c0b3892e174c6..2748b3dacf15b5f229469b84c8c10cecf64ebd5a 100644
--- a/test/integration/tools/node.js
+++ b/test/integration/tools/node.js
@@ -8,7 +8,6 @@ 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 user   = require('./user');
 var http   = require('./http');
 const bma = require('../../../app/modules/bma').BmaDependency.duniter.methods.bma;
 
diff --git a/test/integration/tools/toolbox.ts b/test/integration/tools/toolbox.ts
index 0bb986b754c467fec1fac631b1917bd7528637e1..ea81eb794f4235b5456151abe0b7f4f6c8422c61 100644
--- a/test/integration/tools/toolbox.ts
+++ b/test/integration/tools/toolbox.ts
@@ -22,6 +22,7 @@ import {WS2PMessageHandler} from "../../../app/modules/ws2p/lib/impl/WS2PMessage
 import {WS2PCluster} from "../../../app/modules/ws2p/lib/WS2PCluster"
 import {WS2PServer} from "../../../app/modules/ws2p/lib/WS2PServer"
 import {WS2PServerMessageHandler} from "../../../app/modules/ws2p/lib/interface/WS2PServerMessageHandler"
+import {TestUser} from "./TestUser"
 
 const assert      = require('assert');
 const _           = require('underscore');
@@ -31,7 +32,6 @@ const WebSocketServer = require('ws').Server
 const httpTest    = require('../tools/http');
 const sync        = require('../tools/sync');
 const commit      = require('../tools/commit');
-const user        = require('../tools/user');
 const until       = require('../tools/until');
 const bma         = require('../../../app/modules/bma').BmaDependency.duniter.methods.bma;
 const logger      = require('../../../app/lib/logger').NewLogger('toolbox');
@@ -72,7 +72,7 @@ export const assertThrows = async (promise:Promise<any>, message:string|null = n
 }
 
 export const simpleUser = (uid:string, keyring:{ pub:string, sec:string }, server:TestingServer) => {
-  return user(uid, keyring, { server });
+  return new TestUser(uid, keyring, { server });
 }
 
 export const simpleNetworkOf2NodesAnd2Users = async (options:any) => {
@@ -82,8 +82,8 @@ export const simpleNetworkOf2NodesAnd2Users = async (options:any) => {
   const s1 = NewTestingServer(_.extend({ pair: catKeyring }, options || {}));
   const s2 = NewTestingServer(_.extend({ pair: tacKeyring }, options || {}));
 
-  const cat = user('cat', catKeyring, { server: s1 });
-  const tac = user('tac', tacKeyring, { server: s1 });
+  const cat = new TestUser('cat', catKeyring, { server: s1 });
+  const tac = new TestUser('tac', tacKeyring, { server: s1 });
 
   await s1.initDalBmaConnections()
   await s2.initDalBmaConnections()
@@ -113,8 +113,8 @@ export const simpleNodeWith2Users = async (options:any) => {
 
   const s1 = NewTestingServer(_.extend({ pair: catKeyring }, options || {}));
 
-  const cat = user('cat', catKeyring, { server: s1 });
-  const tac = user('tac', tacKeyring, { server: s1 });
+  const cat = new TestUser('cat', catKeyring, { server: s1 });
+  const tac = new TestUser('tac', tacKeyring, { server: s1 });
 
   await s1.initDalBmaConnections()
 
@@ -135,8 +135,8 @@ export const simpleNodeWith2otherUsers = async (options:any) => {
 
   const s1 = NewTestingServer(_.extend({ pair: ticKeyring }, options || {}));
 
-  const tic = user('cat', ticKeyring, { server: s1 });
-  const toc = user('tac', tocKeyring, { server: s1 });
+  const tic = new TestUser('cat', ticKeyring, { server: s1 });
+  const toc = new TestUser('tac', tocKeyring, { server: s1 });
 
   await s1.initDalBmaConnections()
 
@@ -152,7 +152,7 @@ export const simpleNodeWith2otherUsers = async (options:any) => {
 
 export const createUser = async (uid:string, pub:string, sec:string, defaultServer:Server) => {
   const keyring = { pub: pub, sec: sec };
-  return user(uid, keyring, { server: defaultServer });
+  return new TestUser(uid, keyring, { server: defaultServer });
 }
 
 export const fakeSyncServer = async (readBlocksMethod:any, readParticularBlockMethod:any, onPeersRequested:any) => {
@@ -643,7 +643,7 @@ export async function newWS2PBidirectionnalConnection(currency:string, k1:Key, k
     wss.on('connection', async (ws:any) => {
       switch (i) {
         case 1:
-          s1 = WS2PConnection.newConnectionFromWebSocketServer(ws, serverHandler, new WS2PPubkeyLocalAuth(currency, k1), new WS2PPubkeyRemoteAuth(currency, k1), {
+          s1 = WS2PConnection.newConnectionFromWebSocketServer(ws, serverHandler, new WS2PPubkeyLocalAuth(currency, k1, ""), new WS2PPubkeyRemoteAuth(currency, k1), {
             connectionTimeout: 100,
             requestTimeout: 100
           });
@@ -657,13 +657,13 @@ export async function newWS2PBidirectionnalConnection(currency:string, k1:Key, k
       })
       i++
     })
-    c1 = WS2PConnection.newConnectionToAddress('ws://localhost:' + port, new (class EmptyHandler implements WS2PMessageHandler {
+    c1 = WS2PConnection.newConnectionToAddress(1, 'ws://localhost:' + port, new (class EmptyHandler implements WS2PMessageHandler {
       async handlePushMessage(json: any): Promise<void> {
       }
       async answerToRequest(json: any): Promise<WS2PResponse> {
         return {}
       }
-    }), new WS2PPubkeyLocalAuth(currency, k2), new WS2PPubkeyRemoteAuth(currency, k2))
+    }), new WS2PPubkeyLocalAuth(currency, k2, ""), new WS2PPubkeyRemoteAuth(currency, k2))
   })
 }
 
@@ -678,7 +678,7 @@ export const simpleWS2PNetwork: (s1: TestingServer, s2: TestingServer) => Promis
   const connexionPromise = new Promise(res => {
     ws2ps.on('newConnection', res)
   })
-  const ws2pc = await cluster2.connectToRemoteWS('localhost', port, '', new WS2PServerMessageHandler(s2._server, cluster2), s1._server.conf.pair.pub)
+  const ws2pc = await cluster2.connectToRemoteWS(1, 'localhost', port, '', new WS2PServerMessageHandler(s2._server, cluster2), s1._server.conf.pair.pub)
 
   await connexionPromise
   w1 = await ws2ps.getConnection(clientPub)
diff --git a/test/integration/tools/user.js b/test/integration/tools/user.js
deleted file mode 100644
index 1f910f88e0146e73cb441332c734fa45b82ebf1b..0000000000000000000000000000000000000000
--- a/test/integration/tools/user.js
+++ /dev/null
@@ -1,394 +0,0 @@
-"use strict";
-const co      = require('co');
-const _ = require('underscore');
-const async		= require('async');
-const request	= require('request');
-const contacter = require('../../../app/modules/crawler').CrawlerDependency.duniter.methods.contacter;
-const CommonConstants = require('../../../app/lib/common-libs/constants').CommonConstants
-const ucp     = require('../../../app/lib/common-libs/buid').Buid
-const parsers = require('../../../app/lib/common-libs/parsers').parsers
-const rawer = require('../../../app/lib/common-libs').rawer
-const keyring = require('../../../app/lib/common-libs/crypto/keyring')
-const constants = require('../../../app/lib/constants');
-const CertificationDTO = require('../../../app/lib/dto/CertificationDTO').CertificationDTO
-const MembershipDTO = require('../../../app/lib/dto/MembershipDTO').MembershipDTO
-const RevocationDTO = require('../../../app/lib/dto/RevocationDTO').RevocationDTO
-const PeerDTO = require('../../../app/lib/dto/PeerDTO').PeerDTO
-const TransactionDTO = require('../../../app/lib/dto/TransactionDTO').TransactionDTO
-
-module.exports = function (uid, url, node) {
-  return new User(uid, url, node);
-};
-
-function User (uid, options, node) {
-
-  var that = this;
-  var pub, sec;
-  var createdIdentity = "";
-  that.node = node;
-  that.uid = uid
-
-  // For sync code
-  if (options.pub && options.sec) {
-    pub = that.pub = options.pub;
-    sec = that.sec = options.sec;
-  }
-
-  function init(done) {
-    if (options.pub && options.sec) {
-      pub = that.pub = options.pub;
-      sec = that.sec = options.sec;
-      done();
-    } else {
-      throw 'Not keypair information given for testing user ' + uid;
-    }
-  }
-
-  this.createIdentity = (useRoot, fromServer) => co(function*() {
-    if (!pub) {
-      init(() => {})
-    }
-    const current = yield node.server.BlockchainService.current();
-    let buid = !useRoot && current ? ucp.format.buid(current.number, current.hash) : '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855';
-    createdIdentity = rawer.getOfficialIdentity({
-      buid: buid,
-      uid: uid,
-      issuer: pub,
-      currency: node.server.conf.currency
-    }, false);
-    createdIdentity += keyring.KeyGen(pub, sec).signSync(createdIdentity) + '\n';
-    yield that.submitIdentity(createdIdentity, fromServer);
-  });
-
-  this.submitIdentity = (raw, fromServer) => doPost('/wot/add', {
-    "identity": raw
-  }, fromServer);
-
-  this.getIdentityRaw = () => createdIdentity;
-
-  this.makeCert = (user, fromServer, overrideProps) => co(function*() {
-    const lookup = yield that.lookup(user.pub, fromServer);
-    const current = yield node.server.BlockchainService.current();
-    const idty = _.filter(lookup.results[0].uids, (uidEntry) => uidEntry.uid === user.uid)[0]
-    let buid = current ? ucp.format.buid(current.number, current.hash) : ucp.format.buid();
-    const cert = {
-      "version": constants.DOCUMENTS_VERSION,
-      "currency": node.server.conf.currency,
-      "issuer": pub,
-      "idty_issuer": user.pub,
-      "idty_uid": idty.uid,
-      "idty_buid": idty.meta.timestamp,
-      "idty_sig": idty.self,
-      "buid": buid
-    };
-    _.extend(cert, overrideProps || {});
-    const rawCert = rawer.getOfficialCertification(cert);
-    cert.sig = keyring.KeyGen(pub, sec).signSync(rawCert, sec);
-    return CertificationDTO.fromJSONObject(cert);
-  });
-
-  this.cert = (user, fromServer, toServer) => co(function*() {
-    const cert = yield that.makeCert(user, fromServer);
-    yield doPost('/wot/certify', {
-      "cert": cert.getRawSigned()
-    }, toServer);
-  });
-
-  this.join = () => co(function*() {
-    return yield that.sendMembership("IN");
-  });
-
-  this.leave = () => co(function*() {
-    return yield that.sendMembership("OUT");
-  });
-
-  this.makeRevocation = (givenLookupIdty, overrideProps) => co(function*() {
-    const res = givenLookupIdty || (yield that.lookup(pub));
-    const matchingResult = _.filter(res.results[0].uids, (uidEntry) => uidEntry.uid === uid)[0]
-    const idty = {
-      uid: matchingResult.uid,
-      buid: matchingResult.meta.timestamp,
-      sig: matchingResult.self
-    }
-    const revocation = {
-      "currency": node.server.conf.currency,
-      "issuer": pub,
-      "uid": idty.uid,
-      "sig": idty.sig,
-      "buid": idty.buid,
-      "revocation": ''
-    };
-    _.extend(revocation, overrideProps || {});
-    const rawRevocation = rawer.getOfficialRevocation(revocation);
-    revocation.revocation = keyring.KeyGen(pub, sec).signSync(rawRevocation);
-    return RevocationDTO.fromJSONObject(revocation);
-  });
-
-  this.revoke = (givenLookupIdty) => co(function *() {
-    const revocation = yield that.makeRevocation(givenLookupIdty);
-    return post('/wot/revoke', {
-      "revocation": revocation.getRaw()
-    })
-  });
-
-  this.makeMembership = (type, fromServer, overrideProps) => co(function*() {
-    const lookup = yield that.lookup(pub, fromServer);
-    const current = yield node.server.BlockchainService.current();
-    const idty = lookup.results[0].uids[0];
-    const block = ucp.format.buid(current);
-    const join = {
-      "version": constants.DOCUMENTS_VERSION,
-      "currency": node.server.conf.currency,
-      "issuer": pub,
-      "block": block,
-      "membership": type,
-      "userid": uid,
-      "certts": idty.meta.timestamp
-    };
-    _.extend(join, overrideProps || {});
-    const rawJoin = rawer.getMembershipWithoutSignature(join);
-    join.signature = keyring.KeyGen(pub, sec).signSync(rawJoin);
-    return MembershipDTO.fromJSONObject(join)
-  });
-
-  this.sendMembership = (type) => co(function*() {
-    const ms = yield that.makeMembership(type);
-    yield post('/blockchain/membership', {
-      "membership": ms.getRawSigned()
-    });
-  });
-
-  this.send = function (amount, recipient, comment) {
-    return function(done) {
-      return co(function *() {
-        try {
-          let raw = yield that.prepareITX(amount, recipient, comment);
-          yield that.sendTX(raw);
-          done();
-        } catch (e) {
-          done(e);
-        }
-      });
-    };
-  };
-
-  this.sendMoney = function (amount, recipient, comment) {
-    return co(function *() {
-      let raw = yield that.prepareITX(amount, recipient, comment);
-      yield that.sendTX(raw);
-    })
-  };
-
-  this.sendTX = (rawTX) => co(function *() {
-    let http = yield getContacter();
-    return http.processTransaction(rawTX);
-  });
-
-  this.prepareUTX = (previousTX, unlocks, outputs, opts) => co(function *() {
-    let obj = parsers.parseTransaction.syncWrite(previousTX);
-    // Unlocks inputs with given "unlocks" strings
-    let outputsToConsume = obj.outputs;
-    if (opts.theseOutputsStart !== undefined) {
-      outputsToConsume = outputsToConsume.slice(opts.theseOutputsStart);
-    }
-    let inputs = outputsToConsume.map((out, index) => {
-      const output = TransactionDTO.outputStr2Obj(out);
-      return {
-        src: [output.amount, output.base, 'T', obj.hash, (opts.theseOutputsStart || 0) + index].join(':'),
-        unlock: unlocks[index]
-      };
-    });
-    return signed(that.prepareTX(inputs, outputs, opts));
-  });
-
-  this.prepareMTX = (previousTX, user2, unlocks, outputs, opts) => co(function *() {
-    let obj = parsers.parseTransaction.syncWrite(previousTX);
-    // Unlocks inputs with given "unlocks" strings
-    let inputs = obj.outputs.map((out, index) => {
-      const output = TransactionDTO.outputStr2Obj(out);
-      return {
-        src: [output.amount, output.base, 'T', obj.hash, index].join(':'),
-        unlock: unlocks[index]
-      };
-    });
-    opts = opts || {};
-    opts.issuers = [pub, user2.pub];
-    return signed(that.prepareTX(inputs, outputs, opts), user2);
-  });
-
-  this.prepareITX = (amount, recipient, comment) => co(function *() {
-    let sources = [];
-    if (!amount || !recipient) {
-      throw 'Amount and recipient are required';
-    }
-    let http = yield getContacter();
-    let current = yield http.getCurrent();
-    let version = current && Math.min(CommonConstants.LAST_VERSION_FOR_TX, current.version);
-    let json = yield http.getSources(pub);
-    let i = 0;
-    let cumulated = 0;
-    let commonbase = null;
-    while (i < json.sources.length) {
-      let src = json.sources[i];
-      sources.push({
-        'type': src.type,
-        'amount': src.amount,
-        'base': src.base,
-        'noffset': src.noffset,
-        'identifier': src.identifier
-      });
-      if (commonbase == null) {
-        commonbase = src.base;
-      }
-      commonbase = Math.min(commonbase, src.base);
-      cumulated += src.amount * Math.pow(10, src.base);
-      i++;
-    }
-    if (cumulated < amount) {
-      throw 'You do not have enough coins! (' + cumulated + ' ' + node.server.conf.currency + ' left)';
-    }
-    let sources2 = [];
-    let total = 0;
-    for (let j = 0; j < sources.length && total < amount; j++) {
-      let src = sources[j];
-      total += src.amount * Math.pow(10, src.base);
-      sources2.push(src);
-    }
-    let inputSum = 0;
-    sources2.forEach((src) => inputSum += src.amount * Math.pow(10, src.base));
-    let inputs = sources2.map((src) => {
-      return {
-        src: [src.amount, src.base].concat([src.type, src.identifier, src.noffset]).join(':'),
-        unlock: 'SIG(0)'
-      };
-    });
-    let outputs = [{
-      qty: amount,
-      base: commonbase,
-      lock: 'SIG(' + (recipient.pub || recipient) + ')'
-    }];
-    if (inputSum - amount > 0) {
-      // Rest back to issuer
-      outputs.push({
-        qty: inputSum - amount,
-        base: commonbase,
-        lock: "SIG(" + pub + ")"
-      });
-    }
-    let raw = that.prepareTX(inputs, outputs, {
-      version: version,
-      blockstamp: current && [current.number, current.hash].join('-'),
-      comment: comment
-    });
-    return signed(raw);
-  });
-
-  function signed(raw, user2) {
-    let signatures = [keyring.KeyGen(pub, sec).signSync(raw)];
-    if (user2) {
-      signatures.push(keyring.KeyGen(user2.pub, user2.sec).signSync(raw));
-    }
-    return raw + signatures.join('\n') + '\n';
-  }
-
-  this.makeTX = (inputs, outputs, theOptions) => {
-    const raw = that.prepareTX(inputs, outputs, theOptions);
-    return signed(raw);
-  };
-
-  this.prepareTX = (inputs, outputs, theOptions) => {
-    let opts = theOptions || {};
-    let issuers = opts.issuers || [pub];
-    let raw = '';
-    raw += "Version: " + (opts.version || constants.TRANSACTION_VERSION) + '\n';
-    raw += "Type: Transaction\n";
-    raw += "Currency: " + (opts.currency || node.server.conf.currency) + '\n';
-    raw += "Blockstamp: " + opts.blockstamp + '\n';
-    raw += "Locktime: " + (opts.locktime || 0) + '\n';
-    raw += "Issuers:\n";
-    issuers.forEach((issuer) => raw += issuer + '\n');
-    raw += "Inputs:\n";
-    inputs.forEach(function (input) {
-      raw += input.src + '\n';
-    });
-    raw += "Unlocks:\n";
-    inputs.forEach(function (input, index) {
-      if (input.unlock) {
-        raw += index + ":" + input.unlock + '\n';
-      }
-    });
-    raw += "Outputs:\n";
-    outputs.forEach(function (output) {
-      raw += [output.qty, output.base, output.lock].join(':') + '\n';
-    });
-    raw += "Comment: " + (opts.comment || "") + "\n";
-    return raw;
-  };
-
-  this.makePeer = (endpoints, overrideProps) => co(function*() {
-    const peer = PeerDTO.fromJSONObject({
-      currency: node.server.conf.currency,
-      pubkey: pub,
-      block: '2-00008DF633FC158F9DB4864ABED696C1AA0FE5D617A7B5F7AB8DE7CA2EFCD4CB',
-      endpoints: endpoints
-    });
-    _.extend(peer, overrideProps || {});
-    const rawPeer = rawer.getPeerWithoutSignature(peer);
-    peer.signature = keyring.KeyGen(pub, sec).signSync(rawPeer);
-    return PeerDTO.fromJSONObject(peer)
-  });
-
-  function post(uri, data, done) {
-    return new Promise((resolve, reject) => {
-      var postReq = request.post({
-        "uri": 'http://' + [node.server.conf.remoteipv4, node.server.conf.remoteport].join(':') + uri,
-        "timeout": 1000 * 100000
-      }, function (err, res, body) {
-        err = err || (res.statusCode != 200 && body != 'Already up-to-date' && body) || null;
-        if (err) {
-          reject(err)
-        } else {
-          resolve(res, body)
-        }
-        done && done(err, res, body);
-      });
-      postReq.form(data);
-    })
-  }
-
-  function doPost(uri, data, fromServer) {
-    const ip = fromServer ? fromServer.conf.ipv4 : node.server.conf.remoteipv4;
-    const port = fromServer ? fromServer.conf.port : node.server.conf.remoteport;
-    return new Promise((resolve, reject) => {
-      var postReq = request.post({
-        "uri": 'http://' + [ip, port].join(':') + uri,
-        "timeout": 1000 * 100000
-      }, function (err, res, body) {
-        err = err || (res.statusCode != 200 && body != 'Already up-to-date' && body) || null;
-        err ? reject(err) : resolve(res);
-      });
-      postReq.form(data);
-    });
-  }
-
-  function getContacter(fromServer) {
-    return new Promise(function(resolve){
-      let theNode = (fromServer && { server: fromServer }) || node;
-      resolve(contacter(theNode.server.conf.ipv4, theNode.server.conf.port, {
-        timeout: 1000 * 100000
-      }));
-    });
-  }
-
-  this.lookup = (pubkey, fromServer) => co(function*() {
-    const node2 = yield getContacter(fromServer);
-    return node2.getLookup(pubkey);
-  });
-
-  this.sendP = (amount, userid, comment) => new Promise((res, rej) => {
-    that.send(amount, userid, comment)((err, data) => {
-      if (err) return rej(err)
-      res(data)
-    })
-  })
-}
diff --git a/test/integration/transactions-chaining.js b/test/integration/transactions-chaining.js
index 600641b7819e6a70efbaf1ff3bc13a111e49d067..66a02c1ca402f6046a8ece5faaa057bbd26efba0 100644
--- a/test/integration/transactions-chaining.js
+++ b/test/integration/transactions-chaining.js
@@ -9,7 +9,7 @@ const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods
 const CommonConstants = require('../../app/lib/common-libs/constants').CommonConstants
 const toolbox   = require('./tools/toolbox');
 const node   = require('./tools/node');
-const user   = require('./tools/user');
+const TestUser = require('./tools/TestUser').TestUser
 const unit   = require('./tools/unit');
 const http   = require('./tools/http');
 
@@ -32,8 +32,8 @@ describe("Transaction chaining", function() {
       c: 0.1
     });
 
-    tic = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
-    toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
+    tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
+    toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
 
     yield s1.initDalBmaConnections();
     yield tic.createIdentity();
diff --git a/test/integration/transactions-pruning.js b/test/integration/transactions-pruning.js
index 13d8c9b18b7cee100d6e23823448428e792102c9..d5a6f5c323516ac537978dd6dc9b5c50315aaebe 100644
--- a/test/integration/transactions-pruning.js
+++ b/test/integration/transactions-pruning.js
@@ -2,7 +2,7 @@
 
 const co        = require('co');
 const should    = require('should');
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const commit    = require('./tools/commit');
 const toolbox   = require('./tools/toolbox');
 const constants = require('../../app/lib/constants');
@@ -23,8 +23,8 @@ describe("Transactions pruning", function() {
       }
     });
 
-    cat1 = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    tac1 = user('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
+    cat1 = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
+    tac1 = new TestUser('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
 
     yield s1.prepareForNetwork();
 
diff --git a/test/integration/transactions-test.js b/test/integration/transactions-test.js
index 5592ecf478b31d35f98992d4a6e69109c8bbe997..6b659eb903b4a1c8be07ff084c919c23cd77ab25 100644
--- a/test/integration/transactions-test.js
+++ b/test/integration/transactions-test.js
@@ -8,7 +8,7 @@ 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 user   = require('./tools/user');
+const TestUser = require('./tools/TestUser').TestUser
 const unit   = require('./tools/unit');
 const http   = require('./tools/http');
 
@@ -35,8 +35,8 @@ describe("Testing transactions", function() {
       medianTimeBlocks: 1
     });
 
-    tic = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
-    toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
+    tic = new TestUser('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
+    toc = new TestUser('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
 
     yield s1.initDalBmaConnections();
     // Self certifications
diff --git a/test/integration/v1.1-dividend.js b/test/integration/v1.1-dividend.js
index cc8698c2c5caa71ced1b69604074d253afdae778..2ba9e404c4a9c300fc21085a9f8a7db11799fa91 100644
--- a/test/integration/v1.1-dividend.js
+++ b/test/integration/v1.1-dividend.js
@@ -3,7 +3,7 @@
 const co        = require('co');
 const should    = require('should');
 const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const commit    = require('./tools/commit');
 const toolbox   = require('./tools/toolbox');
 
@@ -30,9 +30,9 @@ describe("Protocol 1.1 Dividend", function() {
       medianTimeBlocks: 1
     });
 
-    cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-    tac = user('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 });
-    tic = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s1 });
+    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 });
 
     yield s1.initDalBmaConnections();
 
diff --git a/test/integration/wotb.js b/test/integration/wotb.js
index a9b82f44ccf11ea5f3cf6a6686ceb8c64d6a1da1..d9a7db18bd1acfbf9123d95e30bfd915763bb381 100644
--- a/test/integration/wotb.js
+++ b/test/integration/wotb.js
@@ -5,7 +5,7 @@ const should    = require('should');
 const _         = require('underscore');
 const duniter     = require('../../index');
 const bma       = require('../../app/modules/bma').BmaDependency.duniter.methods.bma;
-const user      = require('./tools/user');
+const TestUser  = require('./tools/TestUser').TestUser
 const commit    = require('./tools/commit');
 const shutDownEngine  = require('./tools/shutDownEngine');
 
@@ -79,17 +79,17 @@ describe("WOTB module", function() {
             sigValidity: 1400, sigPeriod: 0
           }, commonConf));
 
-        cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 });
-        toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 });
-        tic = user('tic', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: 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 });
 
-        cat2 = user('cat2', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s2 });
-        toc2 = user('toc2', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s2 });
-        tic2 = user('tic2', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s2 });
+        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 = user('cat3', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s3 });
-        toc3 = user('toc3', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s3 });
-        tic3 = user('tic3', { pub: 'DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV', sec: '468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7'}, { server: s3 });
+        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
diff --git a/test/integration/ws2p_cluster.ts b/test/integration/ws2p_cluster.ts
index 08c976f75661a43b40cfe6a6c8a0e5551a3e2e5a..29b65119021c14ef5a94469a385eb59d684de901 100644
--- a/test/integration/ws2p_cluster.ts
+++ b/test/integration/ws2p_cluster.ts
@@ -8,6 +8,7 @@ import {
 } 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')
 
@@ -18,7 +19,7 @@ describe("WS2P cluster", function() {
 
   const now = 1500000000
   let s1:TestingServer, s2:TestingServer, s3:TestingServer
-  let cat:any, tac:any, toc: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'}
diff --git a/test/integration/ws2p_connection.ts b/test/integration/ws2p_connection.ts
index c84d9a42ecc109cd4dd0033d27d4229cd4e15671..e444726b3494123b084e81a6b865c8b9d0547c6e 100644
--- a/test/integration/ws2p_connection.ts
+++ b/test/integration/ws2p_connection.ts
@@ -44,7 +44,7 @@ describe('WS2P', () => {
       })
 
       it('should be able to create a connection', async () => {
-        const ws2p = WS2PConnection.newConnectionToAddress('ws://localhost:' + portA, new WS2PMutedHandler(), new WS2PNoLocalAuth(), new WS2PNoRemoteAuth())
+        const ws2p = WS2PConnection.newConnectionToAddress(1, 'ws://localhost:' + portA, new WS2PMutedHandler(), new WS2PNoLocalAuth(), new WS2PNoRemoteAuth())
         const res = await ws2p.request({ name: 'head' })
         assert.deepEqual({ bla: 'aa' }, res)
       })
@@ -95,7 +95,7 @@ describe('WS2P', () => {
 
       it('should refuse the connection if the server does not answer', async () => {
         const keypair = new Key('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP')
-        const ws2p = WS2PConnection.newConnectionToAddress('ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, keypair), new WS2PPubkeyRemoteAuth(gtest, keypair), undefined, {
+        const ws2p = WS2PConnection.newConnectionToAddress(1, 'ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, keypair, ""), new WS2PPubkeyRemoteAuth(gtest, keypair), undefined, {
           connectionTimeout: 100,
           requestTimeout: 100
         })
@@ -104,7 +104,7 @@ describe('WS2P', () => {
 
       it('should refuse the connection if the server answers with a wrong signature', async () => {
         const keypair = new Key('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP')
-        const ws2p = WS2PConnection.newConnectionToAddress('ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, keypair), new WS2PPubkeyRemoteAuth(gtest, keypair), undefined, {
+        const ws2p = WS2PConnection.newConnectionToAddress(1, 'ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, keypair, ""), new WS2PPubkeyRemoteAuth(gtest, keypair), undefined, {
           connectionTimeout: 100,
           requestTimeout: 100
         })
@@ -113,7 +113,7 @@ describe('WS2P', () => {
 
       it('should refuse the connection if the server refuses our signature', async () => {
         const keypair = new Key('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP')
-        const ws2p = WS2PConnection.newConnectionToAddress('ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, keypair), new WS2PPubkeyRemoteAuth(gtest, keypair), undefined, {
+        const ws2p = WS2PConnection.newConnectionToAddress(1, 'ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, keypair, ""), new WS2PPubkeyRemoteAuth(gtest, keypair), undefined, {
           connectionTimeout: 100,
           requestTimeout: 100
         })
@@ -123,7 +123,7 @@ describe('WS2P', () => {
 
       it('should accept the connection if the server answers with a good signature', async () => {
         const keypair = new Key('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP')
-        const ws2p = WS2PConnection.newConnectionToAddress('ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, keypair), new WS2PNoRemoteAuth(), undefined, {
+        const ws2p = WS2PConnection.newConnectionToAddress(1, 'ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, keypair, ""), new WS2PNoRemoteAuth(), undefined, {
           connectionTimeout: 1000,
           requestTimeout: 1000
         })
@@ -180,7 +180,7 @@ describe('WS2P', () => {
 
       it('should be able to create connections and make several requests', async () => {
         // connection 1
-        const c1 = WS2PConnection.newConnectionToAddress('ws://localhost:' + portB, new WS2PMutedHandler(), new WS2PNoLocalAuth(), new WS2PNoRemoteAuth())
+        const c1 = WS2PConnection.newConnectionToAddress(1, 'ws://localhost:' + portB, new WS2PMutedHandler(), new WS2PNoLocalAuth(), new WS2PNoRemoteAuth())
         assert.deepEqual({ answer: 'world' }, await c1.request({ name: 'hello!' }))
         assert.deepEqual({ answer: 'world' }, await c1.request({ name: 'hello2!' }))
         assert.equal(s1.nbRequests, 0)
@@ -192,7 +192,7 @@ describe('WS2P', () => {
         assert.equal(s1.nbPushsByRemote, 0)
         assert.equal(c1.nbPushsByRemote, 0)
         // connection 2
-        const c2 = WS2PConnection.newConnectionToAddress('ws://localhost:' + portB, new WS2PMutedHandler(), new WS2PNoLocalAuth(), new WS2PNoRemoteAuth())
+        const c2 = WS2PConnection.newConnectionToAddress(1 ,'ws://localhost:' + portB, new WS2PMutedHandler(), new WS2PNoLocalAuth(), new WS2PNoRemoteAuth())
         assert.deepEqual({ answer: 'this is s2![j = 0]' }, await c2.request({ name: 'test?' }))
         assert.deepEqual({ answer: 'this is s2![j = 1]' }, await c2.request({ name: 'test!' }))
         assert.deepEqual({ answer: 'this is s2![j = 2]' }, await c2.request({ name: 'test!!!' }))
@@ -230,7 +230,7 @@ describe('WS2P', () => {
         wss.on('connection', async (ws:any) => {
           switch (i) {
             case 1:
-              resolveS1(WS2PConnection.newConnectionFromWebSocketServer(ws, new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, serverKeypair), new WS2PPubkeyRemoteAuth(gtest, serverKeypair), {
+              resolveS1(WS2PConnection.newConnectionFromWebSocketServer(ws, new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, serverKeypair, ""), new WS2PPubkeyRemoteAuth(gtest, serverKeypair), {
                 connectionTimeout: 100,
                 requestTimeout: 100
               }));
@@ -244,7 +244,7 @@ describe('WS2P', () => {
               }
             }
 
-              resolveS2(WS2PConnection.newConnectionFromWebSocketServer(ws, new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, serverKeypair), new WS2PPubkeyNotAnsweringWithOKAuth(gtest, serverKeypair), {
+              resolveS2(WS2PConnection.newConnectionFromWebSocketServer(ws, new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, serverKeypair, ""), new WS2PPubkeyNotAnsweringWithOKAuth(gtest, serverKeypair), {
                 connectionTimeout: 100,
                 requestTimeout: 100
               }));
@@ -252,7 +252,7 @@ describe('WS2P', () => {
               break
             case 3:
 
-              resolveS3(WS2PConnection.newConnectionFromWebSocketServer(ws, new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, serverKeypair), new WS2PPubkeyRemoteAuth(gtest, serverKeypair), {
+              resolveS3(WS2PConnection.newConnectionFromWebSocketServer(ws, new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, serverKeypair, ""), new WS2PPubkeyRemoteAuth(gtest, serverKeypair), {
                 connectionTimeout: 100,
                 requestTimeout: 100
               }));
@@ -260,7 +260,7 @@ describe('WS2P', () => {
               break
             case 4:
 
-              resolveS4(WS2PConnection.newConnectionFromWebSocketServer(ws, new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, serverKeypair), new WS2PPubkeyRemoteAuth(gtest, serverKeypair), {
+              resolveS4(WS2PConnection.newConnectionFromWebSocketServer(ws, new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, serverKeypair, ""), new WS2PPubkeyRemoteAuth(gtest, serverKeypair), {
                 connectionTimeout: 100,
                 requestTimeout: 100
               }));
@@ -268,13 +268,13 @@ describe('WS2P', () => {
               break
 
             case 5:
-              resolveS5(WS2PConnection.newConnectionFromWebSocketServer(ws, new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, serverKeypair), new WS2PPubkeyRemoteAuth(gtest, serverKeypair)));
+              resolveS5(WS2PConnection.newConnectionFromWebSocketServer(ws, new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, serverKeypair, ""), new WS2PPubkeyRemoteAuth(gtest, serverKeypair)));
               (await s5p).connect().catch((e:any) => logger.error('WS2P: newConnectionFromWebSocketServer connection error'))
               break
 
             case 6:
 
-              resolveS6(WS2PConnection.newConnectionFromWebSocketServer(ws, new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, serverKeypair), new WS2PPubkeyRemoteAuth(gtest, serverKeypair), {
+              resolveS6(WS2PConnection.newConnectionFromWebSocketServer(ws, new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, serverKeypair, ""), new WS2PPubkeyRemoteAuth(gtest, serverKeypair), {
                 connectionTimeout: 100,
                 requestTimeout: 100
               }));
@@ -298,7 +298,7 @@ describe('WS2P', () => {
         }
 
         const keypair = new Key('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP')
-        const c1 = WS2PConnection.newConnectionToAddress('ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, keypair), new WS2PPubkeyNotAnsweringWithACKAuth(gtest, keypair))
+        const c1 = WS2PConnection.newConnectionToAddress(1, 'ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, keypair, ""), new WS2PPubkeyNotAnsweringWithACKAuth(gtest, keypair))
         c1.connect().catch((e:any) => logger.error('WS2P: connection error'))
         const s1 = await s1p
         await assertThrows(s1.request({ name: 'something' }), "WS2P connection timeout")
@@ -306,7 +306,7 @@ describe('WS2P', () => {
 
       it('should refuse the connection if the client not confirm with OK', async () => {
         const keypair = new Key('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP')
-        WS2PConnection.newConnectionToAddress('ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, keypair), new WS2PPubkeyRemoteAuth(gtest, keypair))
+        WS2PConnection.newConnectionToAddress(1, 'ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, keypair, ""), new WS2PPubkeyRemoteAuth(gtest, keypair))
         const s2 = await s2p
         await assertThrows(s2.request({ name: 'something' }), "WS2P connection timeout")
       })
@@ -326,7 +326,7 @@ describe('WS2P', () => {
         }
 
         const keypair = new Key('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP')
-        const c3 = WS2PConnection.newConnectionToAddress('ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, keypair), new WS2PPubkeyAnsweringWithWrongSigForACK(gtest, keypair))
+        const c3 = WS2PConnection.newConnectionToAddress(1, 'ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, keypair, ""), new WS2PPubkeyAnsweringWithWrongSigForACK(gtest, keypair))
         c3.connect().catch((e:any) => logger.error('WS2P: connection error'))
         const s3 = await s3p
         await assertThrows(s3.request({ name: 'something' }), "Wrong signature from server ACK")
@@ -349,20 +349,20 @@ describe('WS2P', () => {
         }
 
         const keypair = new Key('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP')
-        const c4 = WS2PConnection.newConnectionToAddress('ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyRefusingACKSignature(gtest, keypair), new WS2PPubkeyRemoteAuth(gtest, keypair))
+        const c4 = WS2PConnection.newConnectionToAddress(1, 'ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyRefusingACKSignature(gtest, keypair, ""), new WS2PPubkeyRemoteAuth(gtest, keypair))
         const s4 = await s4p
         await assertThrows(c4.connect(), "Wrong signature from server ACK")
       })
 
       it('should accept the connection if everything is OK on both side', async () => {
         const keypair = new Key('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP')
-        const c5 = WS2PConnection.newConnectionToAddress('ws://localhost:20903', new (class TmpHandler implements WS2PMessageHandler {
+        const c5 = WS2PConnection.newConnectionToAddress(1, 'ws://localhost:20903', new (class TmpHandler implements WS2PMessageHandler {
           async handlePushMessage(json: any): Promise<void> {
           }
           async answerToRequest(json: any): Promise<WS2PResponse> {
             return { answer: 'success!' }
           }
-        }), new WS2PPubkeyLocalAuth(gtest, keypair), new WS2PPubkeyRemoteAuth(gtest, keypair))
+        }), new WS2PPubkeyLocalAuth(gtest, keypair, ""), new WS2PPubkeyRemoteAuth(gtest, keypair))
         await c5.connect().catch((e:any) => logger.error('WS2P: connection error'))
         const s5 = await s5p
         assert.deepEqual({ answer: 'success!' }, await s5.request({ name: 'connection?'} ))
@@ -376,7 +376,7 @@ describe('WS2P', () => {
         }
 
         const keypair = new Key('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP')
-        const c6 = WS2PConnection.newConnectionToAddress('ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyNotAnsweringWithOKAuth(gtest, keypair), new WS2PPubkeyRemoteAuth(gtest, keypair))
+        const c6 = WS2PConnection.newConnectionToAddress(1, 'ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyNotAnsweringWithOKAuth(gtest, keypair, ""), new WS2PPubkeyRemoteAuth(gtest, keypair))
         c6.connect().catch((e:any) => logger.error('WS2P: connection error'))
         const s6 = await s6p
         await assertThrows(s6.request({ name: 'something' }), "WS2P connection timeout")
@@ -415,6 +415,10 @@ class WS2PNoLocalAuth implements WS2PLocalAuth {
 
 class WS2PNoRemoteAuth implements WS2PRemoteAuth {
 
+  getVersion(): number {
+    return 1
+  }
+
   getPubkey(): string {
     return ""
   }
@@ -422,7 +426,7 @@ class WS2PNoRemoteAuth implements WS2PRemoteAuth {
   async sendACK(ws: any): Promise<void> {
   }
 
-  async registerCONNECT(challenge:string, sig: string, pub: string): Promise<boolean> {
+  async registerCONNECT(version:number, challenge:string, sig: string, pub: string, ws2pId:string): Promise<boolean> {
     return true
   }
 
diff --git a/test/integration/ws2p_doc_sharing.ts b/test/integration/ws2p_doc_sharing.ts
index 9bf6043352fb41d553e9048949080fcf48d1ebe2..be10fa17beb9f3b2b791593caf51d7b6df8e9d33 100644
--- a/test/integration/ws2p_doc_sharing.ts
+++ b/test/integration/ws2p_doc_sharing.ts
@@ -1,3 +1,4 @@
+import { TestUser } from './tools/TestUser';
 import {simpleTestingConf, simpleTestingServer, simpleUser, simpleWS2PNetwork, TestingServer} from "./tools/toolbox"
 import {WS2PConstants} from "../../app/modules/ws2p/lib/constants"
 
@@ -10,7 +11,7 @@ describe("WS2P doc sharing", function() {
 
   const now = 1500000000
   let s1:TestingServer, s2:TestingServer, wss:any
-  let cat:any, tac:any, toc: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'}
diff --git a/test/integration/ws2p_heads.ts b/test/integration/ws2p_heads.ts
index 7f0e78e50fa47b3e4fa08c96f9eac99718480356..7d20af4b2e0ae9acd4e99620a6a753d524230351 100644
--- a/test/integration/ws2p_heads.ts
+++ b/test/integration/ws2p_heads.ts
@@ -86,7 +86,7 @@ describe("WS2P heads propagation", function() {
     b3 = s1.commit({ time: now })
     await Promise.all([
       s2.waitToHaveBlock(3),
-      s2.waitForHeads(1)
+      s2.waitForHeads(2) // head v2 + head v1
     ])
     await s1.expect('/network/ws2p/info', (res:any) => {
       assert.equal(res.peers.level1, 0)
diff --git a/test/integration/ws2p_server_limitations.ts b/test/integration/ws2p_server_limitations.ts
index 41efe96e9462442a6798b597ffdcc4b0f0047f75..fd4929955a38c1933b61c1787da6eb51e4b3b0c0 100644
--- a/test/integration/ws2p_server_limitations.ts
+++ b/test/integration/ws2p_server_limitations.ts
@@ -165,7 +165,11 @@ describe("WS2P server limitations", function() {
   })
 
   it('should be able to fully disconnect the WS2P network', async () => {
-    // Preparation for next test of configuration favorism
+    if (s1._server.conf.ws2p) s1._server.conf.ws2p.privateAccess = true
+    if (s3._server.conf.ws2p) {
+      s3._server.conf.ws2p.publicAccess = true
+      s3._server.conf.ws2p.maxPublic = 1
+    }
     await s3.writeBlock(b3)
     await s1.waitToHaveBlock(3)
     await s2.waitToHaveBlock(3)
@@ -176,6 +180,8 @@ describe("WS2P server limitations", function() {
     if (s3.conf.ws2p) s3.conf.ws2p.maxPublic = 0
     if (s1.conf.ws2p) s1.conf.ws2p.maxPublic = 0 // <-- Breaks the connection s2 -> s1
     await cluster1.trimServerConnections()
+    const s2PreferedKeys = (s2.conf.ws2p && s2.conf.ws2p.preferedNodes) ? s2.conf.ws2p.preferedNodes:[]
+    await cluster2.removeLowPriorityConnections(s2PreferedKeys)
     await waitForkWS2PDisconnection(s1._server, '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc')
     await cluster3.trimServerConnections()
     await s1.expect('/network/ws2p/info', (res:any) => {
diff --git a/yarn.lock b/yarn.lock
index 5cb6c4ae6a81506779aca196a7967f909c1bb91d..fd48982082b1b8eca41cbd968fbe604762124be7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -57,6 +57,10 @@ agent-base@^4.1.0:
   dependencies:
     es6-promisify "^5.0.0"
 
+adm-zip@0.4.7:
+  version "0.4.7"
+  resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.7.tgz#8606c2cbf1c426ce8c8ec00174447fd49b6eafc1"
+
 ajv-keywords@^1.0.0:
   version "1.5.1"
   resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
@@ -977,6 +981,28 @@ doctrine@^1.2.2:
     esutils "^2.0.2"
     isarray "^1.0.0"
 
+duniter-ui@^1.6.13:
+  version "1.6.13"
+  resolved "https://registry.yarnpkg.com/duniter-ui/-/duniter-ui-1.6.13.tgz#3f203152fc0e3e1cbae74c1a0353a620c82d72ee"
+  dependencies:
+    adm-zip "0.4.7"
+    body-parser "1.17.1"
+    co "4.6.0"
+    cors "2.8.2"
+    event-stream "3.3.4"
+    express "4.15.2"
+    express-fileupload "0.0.5"
+    fs-extra "2.1.2"
+    materialize-css "0.98.1"
+    moment "2.18.1"
+    node-pre-gyp "0.6.34"
+    q "1.5.0"
+    request "2.81.0"
+    request-promise "4.2.0"
+    rimraf "2.6.1"
+    tmp "0.0.31"
+    underscore "1.8.3"
+
 duplexer@~0.1.1:
   version "0.1.1"
   resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1"
@@ -1519,6 +1545,13 @@ from@~0:
   version "0.1.7"
   resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe"
 
+fs-extra@2.1.2:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-2.1.2.tgz#046c70163cef9aad46b0e4a7fa467fb22d71de35"
+  dependencies:
+    graceful-fs "^4.1.2"
+    jsonfile "^2.1.0"
+
 fs-extra@^0.22.1:
   version "0.22.1"
   resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.22.1.tgz#5fd6f8049dc976ca19eb2355d658173cabcce056"
@@ -1686,6 +1719,10 @@ growl@1.9.2:
   version "1.9.2"
   resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f"
 
+hammerjs@^2.0.4:
+  version "2.0.8"
+  resolved "https://registry.yarnpkg.com/hammerjs/-/hammerjs-2.0.8.tgz#04ef77862cff2bb79d30f7692095930222bf60f1"
+
 handlebars@^4.0.3:
   version "4.0.11"
   resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc"
@@ -2152,6 +2189,7 @@ jison@0.4.17:
     lex-parser "~0.1.3"
     nomnom "1.5.2"
 
+
 js-tokens@^3.0.0, js-tokens@^3.0.2:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
@@ -2407,6 +2445,14 @@ map-stream@~0.1.0:
     buffers "~0.1.1"
     readable-stream "~1.0.0"
 
+materialize-css@0.98.1:
+  version "0.98.1"
+  resolved "https://registry.yarnpkg.com/materialize-css/-/materialize-css-0.98.1.tgz#7276895b2c998b53e26deaa0c23a0484c0851d99"
+  dependencies:
+    hammerjs "^2.0.4"
+    jquery "^2.1.4"
+    node-archiver "^0.3.0"
+
 md5-hex@^1.2.0:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/md5-hex/-/md5-hex-1.3.0.tgz#d2c4afe983c4370662179b8cad145219135046c4"
@@ -2636,6 +2682,13 @@ nnupnp@1.0.2:
     request "2.10.0"
     xml2js "0.1.14"
 
+node-archiver@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/node-archiver/-/node-archiver-0.3.0.tgz#b9f1afe5006d0bdf29260181833a070978bc6947"
+  dependencies:
+    fstream "^1.0.10"
+    tar "^2.2.1"
+
 node-pre-gyp@0.6.23:
   version "0.6.23"
   resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.23.tgz#155bf3683abcfcde008aedab1248891a0773db95"