diff --git a/.eslintignore b/.eslintignore
index 7b9a68880f3504729c7ca57ea18d5c580e3cc457..bd009ef6ce226d0529c19cb1147ec7649a069d67 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -14,6 +14,8 @@ app/service/*.js
 app/lib/rules/*.js
 app/lib/system/*.js
 app/lib/streams/*.js
+app/lib/helpers/*.js
+app/lib/*.js
 app/modules/wizard.js
 app/modules/router.js
 app/modules/revert.js
diff --git a/.gitignore b/.gitignore
index ac726b307dd5eee23eefb6db0904c99eb61e82fa..444e37d3adda720316397f3fb0316ce66d91ce38 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,27 +32,25 @@ test/blockchain/*.js
 test/blockchain/*.js.map
 test/blockchain/lib/*.js
 test/blockchain/lib/*.js.map
+app/lib/*.js*
 app/lib/blockchain/*.js
 app/lib/blockchain/*.js.map
 app/lib/blockchain/interfaces/*.js
 app/lib/blockchain/interfaces/*.js.map
 app/lib/computation/*.js
 app/lib/computation/*.js.map
-app/lib/common.js*
 app/lib/db/*.js*
 app/lib/dto/*.js*
-app/lib/indexer.js*
 app/lib/dal/drivers/*.js*
 app/lib/dal/sqliteDAL/*.js*
 app/lib/dal/sqliteDAL/index/*.js*
 app/lib/dal/fileDALs/*.js*
 app/lib/dal/fileDAL.js*
 app/lib/rules/*.js*
-app/lib/logger*js*
 app/lib/system/directory.js*
 app/lib/streams/*.js*
+app/lib/helpers/*.js*
 app/service/*.js*
-app/lib/wot.js*
 app/modules/prover/*.js*
 app/modules/prover/lib/*.js*
 app/modules/router*.js*
diff --git a/app/lib/constants.js b/app/lib/constants.js
index 0e8e784f760cdf63cd7aacf54edd5680e815f8ce..43a17790aca2c597364abcdf1a6afde6d0a78fb1 100644
--- a/app/lib/constants.js
+++ b/app/lib/constants.js
@@ -1,176 +1,148 @@
 "use strict";
-
-const common = require('duniter-common')
-
-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       = common.constants.FORMATS.PUBKEY
-const TIMESTAMP    = common.constants.FORMATS.TIMESTAMP
-
+const common = require('duniter-common');
+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 = common.constants.FORMATS.PUBKEY;
+const TIMESTAMP = common.constants.FORMATS.TIMESTAMP;
 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}:))$/;
-
 module.exports = {
-
-  TIME_TO_TURN_ON_BRG_107: 1498860000,
-
-  ERROR: {
-
-    PEER: {
-      UNKNOWN_REFERENCE_BLOCK: 'Unknown reference block of peer'
+    TIME_TO_TURN_ON_BRG_107: 1498860000,
+    ERROR: {
+        PEER: {
+            UNKNOWN_REFERENCE_BLOCK: 'Unknown reference block of peer'
+        },
+        BLOCK: {
+            NO_CURRENT_BLOCK: 'No current block'
+        }
     },
-
-    BLOCK: {
-      NO_CURRENT_BLOCK: 'No current block'
-    }
-  },
-
-  ERRORS: {
-
-    // Technical errors
-    UNKNOWN:                              { httpCode: 500, uerr: { ucode: 1001, message: "An unknown error occured" }},
-    UNHANDLED:                            { httpCode: 500, uerr: { ucode: 1002, message: "An unhandled error occured" }},
-    SIGNATURE_DOES_NOT_MATCH:             { httpCode: 400, uerr: { ucode: 1003, message: "Signature does not match" }},
-    ALREADY_UP_TO_DATE:                   { httpCode: 400, uerr: { ucode: 1004, message: "Already up-to-date" }},
-    WRONG_DOCUMENT:                       common.constants.ERRORS.WRONG_DOCUMENT,
-    SANDBOX_FOR_IDENTITY_IS_FULL:         { httpCode: 503, uerr: { ucode: 1007, message: "The identities' sandbox is full. Please retry with another document or retry later." }},
-    SANDBOX_FOR_CERT_IS_FULL:             { httpCode: 503, uerr: { ucode: 1008, message: "The certifications' sandbox is full. Please retry with another document or retry later." }},
-    SANDBOX_FOR_MEMERSHIP_IS_FULL:        { httpCode: 503, uerr: { ucode: 1009, message: "The memberships' sandbox is full. Please retry with another document or retry later." }},
-    SANDBOX_FOR_TRANSACTION_IS_FULL:      { httpCode: 503, uerr: { ucode: 1010, message: "The transactions' sandbox is full. Please retry with another document or retry later." }},
-    NO_POTENTIAL_FORK_AS_NEXT:            { httpCode: 503, uerr: { ucode: 1011, message: "No fork block exists in the database as a potential next block." }},
-    INCONSISTENT_DB_MULTI_TXS_SAME_HASH:  { httpCode: 503, uerr: { ucode: 1012, message: "Several transactions written with the same hash." }},
-    CLI_CALLERR_RESET:                    { httpCode: 503, uerr: { ucode: 1013, message: "Bad command: usage is `reset config`, `reset data`, `reset peers`, `reset stats` or `reset all`" }},
-    CLI_CALLERR_CONFIG:                   { httpCode: 503, uerr: { ucode: 1014, message: "Bad command: usage is `config`." }},
-
-    // Business errors
-    NO_MATCHING_IDENTITY:                 { httpCode: 404, uerr: { ucode: 2001, message: "No matching identity" }},
-    UID_ALREADY_USED:                     { httpCode: 400, uerr: { ucode: 2002, message: "UID already used in the blockchain" }},
-    PUBKEY_ALREADY_USED:                  { httpCode: 400, uerr: { ucode: 2003, message: "Pubkey already used in the blockchain" }},
-    NO_MEMBER_MATCHING_PUB_OR_UID:        { httpCode: 404, uerr: { ucode: 2004, message: "No member matching this pubkey or uid" }},
-    WRONG_SIGNATURE_MEMBERSHIP:           { httpCode: 400, uerr: { ucode: 2006, message: "wrong signature for membership" }},
-    ALREADY_RECEIVED_MEMBERSHIP:          { httpCode: 400, uerr: { ucode: 2007, message: "Already received membership" }},
-    MEMBERSHIP_A_NON_MEMBER_CANNOT_LEAVE: { httpCode: 400, uerr: { ucode: 2008, message: "A non-member cannot leave" }},
-    NOT_A_MEMBER:                         { httpCode: 400, uerr: { ucode: 2009, message: "Not a member" }},
-    BLOCK_NOT_FOUND:                      { httpCode: 404, uerr: { ucode: 2011, message: "Block not found" }},
-    WRONG_UNLOCKER:                       common.constants.ERRORS.WRONG_UNLOCKER,
-    LOCKTIME_PREVENT:                     common.constants.ERRORS.LOCKTIME_PREVENT,
-    SOURCE_ALREADY_CONSUMED:              common.constants.ERRORS.SOURCE_ALREADY_CONSUMED,
-    WRONG_AMOUNTS:                        common.constants.ERRORS.WRONG_AMOUNTS,
-    WRONG_OUTPUT_BASE:                    common.constants.ERRORS.WRONG_OUTPUT_BASE,
-    CANNOT_ROOT_BLOCK_NO_MEMBERS:         common.constants.ERRORS.CANNOT_ROOT_BLOCK_NO_MEMBERS,
-    IDENTITY_WRONGLY_SIGNED:              common.constants.ERRORS.IDENTITY_WRONGLY_SIGNED,
-    TOO_OLD_IDENTITY:                     common.constants.ERRORS.TOO_OLD_IDENTITY,
-    NO_IDTY_MATCHING_PUB_OR_UID:          { httpCode: 404, uerr: { ucode: 2021, message: "No identity matching this pubkey or uid" }},
-    NEWER_PEER_DOCUMENT_AVAILABLE:        { httpCode: 409, uerr: { ucode: 2022, message: "A newer peer document is available" }},
-    PEER_DOCUMENT_ALREADY_KNOWN:          { httpCode: 400, uerr: { ucode: 2023, message: "Peer document already known" }},
-    TX_INPUTS_OUTPUTS_NOT_EQUAL:          common.constants.ERRORS.TX_INPUTS_OUTPUTS_NOT_EQUAL,
-    TX_OUTPUT_SUM_NOT_EQUALS_PREV_DELTAS: common.constants.ERRORS.TX_OUTPUT_SUM_NOT_EQUALS_PREV_DELTAS,
-    BLOCKSTAMP_DOES_NOT_MATCH_A_BLOCK:    common.constants.ERRORS.BLOCKSTAMP_DOES_NOT_MATCH_A_BLOCK,
-    A_TRANSACTION_HAS_A_MAX_SIZE:         common.constants.ERRORS.A_TRANSACTION_HAS_A_MAX_SIZE,
-    BLOCK_ALREADY_PROCESSED:              { httpCode: 400, uerr: { ucode: 2028, message: 'Already processed' }},
-    TOO_OLD_MEMBERSHIP:                   common.constants.ERRORS.TOO_OLD_MEMBERSHIP,
-    TX_ALREADY_PROCESSED:                 { httpCode: 400, uerr: { ucode: 2030, message: "Transaction already processed" }},
-    A_MORE_RECENT_MEMBERSHIP_EXISTS:      { httpCode: 400, uerr: { ucode: 2031, message: "A more recent membership already exists" }},
-    MAXIMUM_LEN_OF_OUTPUT:                common.constants.ERRORS.MAXIMUM_LEN_OF_OUTPUT,
-    MAXIMUM_LEN_OF_UNLOCK:                common.constants.ERRORS.MAXIMUM_LEN_OF_UNLOCK
-  },
-
-  DEBUG: {
-    LONG_DAL_PROCESS: 50
-  },
-
-  BMA_REGEXP: common.constants.BMA_REGEXP,
-  IPV4_REGEXP: IPV4_REGEXP,
-  IPV6_REGEXP: IPV6_REGEXP,
-
-  TIMESTAMP: exact(TIMESTAMP),
-  UDID2_FORMAT: exact(UDID2),
-  PUBLIC_KEY: exact(PUBKEY),
-
-  DOCUMENTS_VERSION: common.constants.DOCUMENTS_VERSION,
-  BLOCK_GENERATED_VERSION: common.constants.BLOCK_GENERATED_VERSION,
-  LAST_VERSION_FOR_TX: 10,
-  TRANSACTION_VERSION: common.constants.TRANSACTION_VERSION,
-
-  REVOCATION_FACTOR: common.constants.REVOCATION_FACTOR, // This is protocol fixed value
-  FIRST_UNIT_BASE: 0,
-
-  PEER: common.constants.PEER,
-  NETWORK: {
-    MAX_MEMBERS_TO_FORWARD_TO_FOR_SELF_DOCUMENTS: 10,
-    MAX_NON_MEMBERS_TO_FORWARD_TO_FOR_SELF_DOCUMENTS: 6,
-    MAX_NON_MEMBERS_TO_FORWARD_TO: 4,
-    MAX_MEMBERS_TO_FORWARD_TO: 6,
-    MAX_CONCURRENT_POST: 3,
-    DEFAULT_TIMEOUT: 10 * 1000, // 10 seconds
-    SYNC: {
-      MAX: 20
+    ERRORS: {
+        // Technical errors
+        UNKNOWN: { httpCode: 500, uerr: { ucode: 1001, message: "An unknown error occured" } },
+        UNHANDLED: { httpCode: 500, uerr: { ucode: 1002, message: "An unhandled error occured" } },
+        SIGNATURE_DOES_NOT_MATCH: { httpCode: 400, uerr: { ucode: 1003, message: "Signature does not match" } },
+        ALREADY_UP_TO_DATE: { httpCode: 400, uerr: { ucode: 1004, message: "Already up-to-date" } },
+        WRONG_DOCUMENT: common.constants.ERRORS.WRONG_DOCUMENT,
+        SANDBOX_FOR_IDENTITY_IS_FULL: { httpCode: 503, uerr: { ucode: 1007, message: "The identities' sandbox is full. Please retry with another document or retry later." } },
+        SANDBOX_FOR_CERT_IS_FULL: { httpCode: 503, uerr: { ucode: 1008, message: "The certifications' sandbox is full. Please retry with another document or retry later." } },
+        SANDBOX_FOR_MEMERSHIP_IS_FULL: { httpCode: 503, uerr: { ucode: 1009, message: "The memberships' sandbox is full. Please retry with another document or retry later." } },
+        SANDBOX_FOR_TRANSACTION_IS_FULL: { httpCode: 503, uerr: { ucode: 1010, message: "The transactions' sandbox is full. Please retry with another document or retry later." } },
+        NO_POTENTIAL_FORK_AS_NEXT: { httpCode: 503, uerr: { ucode: 1011, message: "No fork block exists in the database as a potential next block." } },
+        INCONSISTENT_DB_MULTI_TXS_SAME_HASH: { httpCode: 503, uerr: { ucode: 1012, message: "Several transactions written with the same hash." } },
+        CLI_CALLERR_RESET: { httpCode: 503, uerr: { ucode: 1013, message: "Bad command: usage is `reset config`, `reset data`, `reset peers`, `reset stats` or `reset all`" } },
+        CLI_CALLERR_CONFIG: { httpCode: 503, uerr: { ucode: 1014, message: "Bad command: usage is `config`." } },
+        // Business errors
+        NO_MATCHING_IDENTITY: { httpCode: 404, uerr: { ucode: 2001, message: "No matching identity" } },
+        UID_ALREADY_USED: { httpCode: 400, uerr: { ucode: 2002, message: "UID already used in the blockchain" } },
+        PUBKEY_ALREADY_USED: { httpCode: 400, uerr: { ucode: 2003, message: "Pubkey already used in the blockchain" } },
+        NO_MEMBER_MATCHING_PUB_OR_UID: { httpCode: 404, uerr: { ucode: 2004, message: "No member matching this pubkey or uid" } },
+        WRONG_SIGNATURE_MEMBERSHIP: { httpCode: 400, uerr: { ucode: 2006, message: "wrong signature for membership" } },
+        ALREADY_RECEIVED_MEMBERSHIP: { httpCode: 400, uerr: { ucode: 2007, message: "Already received membership" } },
+        MEMBERSHIP_A_NON_MEMBER_CANNOT_LEAVE: { httpCode: 400, uerr: { ucode: 2008, message: "A non-member cannot leave" } },
+        NOT_A_MEMBER: { httpCode: 400, uerr: { ucode: 2009, message: "Not a member" } },
+        BLOCK_NOT_FOUND: { httpCode: 404, uerr: { ucode: 2011, message: "Block not found" } },
+        WRONG_UNLOCKER: common.constants.ERRORS.WRONG_UNLOCKER,
+        LOCKTIME_PREVENT: common.constants.ERRORS.LOCKTIME_PREVENT,
+        SOURCE_ALREADY_CONSUMED: common.constants.ERRORS.SOURCE_ALREADY_CONSUMED,
+        WRONG_AMOUNTS: common.constants.ERRORS.WRONG_AMOUNTS,
+        WRONG_OUTPUT_BASE: common.constants.ERRORS.WRONG_OUTPUT_BASE,
+        CANNOT_ROOT_BLOCK_NO_MEMBERS: common.constants.ERRORS.CANNOT_ROOT_BLOCK_NO_MEMBERS,
+        IDENTITY_WRONGLY_SIGNED: common.constants.ERRORS.IDENTITY_WRONGLY_SIGNED,
+        TOO_OLD_IDENTITY: common.constants.ERRORS.TOO_OLD_IDENTITY,
+        NO_IDTY_MATCHING_PUB_OR_UID: { httpCode: 404, uerr: { ucode: 2021, message: "No identity matching this pubkey or uid" } },
+        NEWER_PEER_DOCUMENT_AVAILABLE: { httpCode: 409, uerr: { ucode: 2022, message: "A newer peer document is available" } },
+        PEER_DOCUMENT_ALREADY_KNOWN: { httpCode: 400, uerr: { ucode: 2023, message: "Peer document already known" } },
+        TX_INPUTS_OUTPUTS_NOT_EQUAL: common.constants.ERRORS.TX_INPUTS_OUTPUTS_NOT_EQUAL,
+        TX_OUTPUT_SUM_NOT_EQUALS_PREV_DELTAS: common.constants.ERRORS.TX_OUTPUT_SUM_NOT_EQUALS_PREV_DELTAS,
+        BLOCKSTAMP_DOES_NOT_MATCH_A_BLOCK: common.constants.ERRORS.BLOCKSTAMP_DOES_NOT_MATCH_A_BLOCK,
+        A_TRANSACTION_HAS_A_MAX_SIZE: common.constants.ERRORS.A_TRANSACTION_HAS_A_MAX_SIZE,
+        BLOCK_ALREADY_PROCESSED: { httpCode: 400, uerr: { ucode: 2028, message: 'Already processed' } },
+        TOO_OLD_MEMBERSHIP: common.constants.ERRORS.TOO_OLD_MEMBERSHIP,
+        TX_ALREADY_PROCESSED: { httpCode: 400, uerr: { ucode: 2030, message: "Transaction already processed" } },
+        A_MORE_RECENT_MEMBERSHIP_EXISTS: { httpCode: 400, uerr: { ucode: 2031, message: "A more recent membership already exists" } },
+        MAXIMUM_LEN_OF_OUTPUT: common.constants.ERRORS.MAXIMUM_LEN_OF_OUTPUT,
+        MAXIMUM_LEN_OF_UNLOCK: common.constants.ERRORS.MAXIMUM_LEN_OF_UNLOCK
     },
-    STATUS_INTERVAL: {
-      UPDATE: 2, // Every X blocks
-      MAX: 20 // MAX Y blocks
-    }
-  },
-  PROOF_OF_WORK: {
-    EVALUATION: 1000,
-    UPPER_BOUND: common.constants.PROOF_OF_WORK.UPPER_BOUND.slice()
-  },
-
-  DEFAULT_CURRENCY_NAME: "no_currency",
-
-  CONTRACT: {
-    DEFAULT: {
-      C: 0.007376575,
-      DT: 30.4375 * 24 * 3600,
-      DT_REEVAL: 30.4375 * 24 * 3600,
-      UD0: 100,
-      STEPMAX: 3,
-      SIGDELAY: 3600 * 24 * 365 * 5,
-      SIGPERIOD: 0, // Instant
-      MSPERIOD: 0, // Instant
-      SIGSTOCK: 40,
-      SIGWINDOW: 3600 * 24 * 7, // a week
-      SIGVALIDITY: 3600 * 24 * 365,
-      MSVALIDITY: 3600 * 24 * 365,
-      SIGQTY: 5,
-      X_PERCENT: 0.9,
-      PERCENTROT: 2 / 3,
-      BLOCKSROT: 20,
-      POWDELAY: 0,
-      AVGGENTIME: 16 * 60,
-      DTDIFFEVAL: 10,
-      MEDIANTIMEBLOCKS: 20,
-      IDTYWINDOW: 3600 * 24 * 7, // a week
-      MSWINDOW: 3600 * 24 * 7 // a week
+    DEBUG: {
+        LONG_DAL_PROCESS: 50
     },
-
-    DSEN_P: 1.2 // dSen proportional factor
-  },
-
-  BRANCHES: {
-    DEFAULT_WINDOW_SIZE: 100
-  },
-
-  INVALIDATE_CORE_CACHE: true,
-  WITH_SIGNATURES_AND_POW: true,
-
-  NO_FORK_ALLOWED: false,
-
-  SAFE_FACTOR: 3,
-  BLOCKS_COLLECT_THRESHOLD: 30, // Blocks to collect from memory and persist
-
-  MUTE_LOGS_DURING_UNIT_TESTS: true,
-
-  SANDBOX_SIZE_TRANSACTIONS: 200,
-  SANDBOX_SIZE_IDENTITIES: 5000,
-  SANDBOX_SIZE_CERTIFICATIONS: 12,
-  SANDBOX_SIZE_MEMBERSHIPS: 5000,
-
-  CURRENT_BLOCK_CACHE_DURATION: 10 * 1000, // 30 seconds
-
-  // With `logs` command, the number of tail lines to show
-  NB_INITIAL_LINES_TO_SHOW: 100
+    BMA_REGEXP: common.constants.BMA_REGEXP,
+    IPV4_REGEXP: IPV4_REGEXP,
+    IPV6_REGEXP: IPV6_REGEXP,
+    TIMESTAMP: exact(TIMESTAMP),
+    UDID2_FORMAT: exact(UDID2),
+    PUBLIC_KEY: exact(PUBKEY),
+    DOCUMENTS_VERSION: common.constants.DOCUMENTS_VERSION,
+    BLOCK_GENERATED_VERSION: common.constants.BLOCK_GENERATED_VERSION,
+    LAST_VERSION_FOR_TX: 10,
+    TRANSACTION_VERSION: common.constants.TRANSACTION_VERSION,
+    REVOCATION_FACTOR: common.constants.REVOCATION_FACTOR,
+    FIRST_UNIT_BASE: 0,
+    PEER: common.constants.PEER,
+    NETWORK: {
+        MAX_MEMBERS_TO_FORWARD_TO_FOR_SELF_DOCUMENTS: 10,
+        MAX_NON_MEMBERS_TO_FORWARD_TO_FOR_SELF_DOCUMENTS: 6,
+        MAX_NON_MEMBERS_TO_FORWARD_TO: 4,
+        MAX_MEMBERS_TO_FORWARD_TO: 6,
+        MAX_CONCURRENT_POST: 3,
+        DEFAULT_TIMEOUT: 10 * 1000,
+        SYNC: {
+            MAX: 20
+        },
+        STATUS_INTERVAL: {
+            UPDATE: 2,
+            MAX: 20 // MAX Y blocks
+        }
+    },
+    PROOF_OF_WORK: {
+        EVALUATION: 1000,
+        UPPER_BOUND: common.constants.PROOF_OF_WORK.UPPER_BOUND.slice()
+    },
+    DEFAULT_CURRENCY_NAME: "no_currency",
+    CONTRACT: {
+        DEFAULT: {
+            C: 0.007376575,
+            DT: 30.4375 * 24 * 3600,
+            DT_REEVAL: 30.4375 * 24 * 3600,
+            UD0: 100,
+            STEPMAX: 3,
+            SIGDELAY: 3600 * 24 * 365 * 5,
+            SIGPERIOD: 0,
+            MSPERIOD: 0,
+            SIGSTOCK: 40,
+            SIGWINDOW: 3600 * 24 * 7,
+            SIGVALIDITY: 3600 * 24 * 365,
+            MSVALIDITY: 3600 * 24 * 365,
+            SIGQTY: 5,
+            X_PERCENT: 0.9,
+            PERCENTROT: 2 / 3,
+            BLOCKSROT: 20,
+            POWDELAY: 0,
+            AVGGENTIME: 16 * 60,
+            DTDIFFEVAL: 10,
+            MEDIANTIMEBLOCKS: 20,
+            IDTYWINDOW: 3600 * 24 * 7,
+            MSWINDOW: 3600 * 24 * 7 // a week
+        },
+        DSEN_P: 1.2 // dSen proportional factor
+    },
+    BRANCHES: {
+        DEFAULT_WINDOW_SIZE: 100
+    },
+    INVALIDATE_CORE_CACHE: true,
+    WITH_SIGNATURES_AND_POW: true,
+    NO_FORK_ALLOWED: false,
+    SAFE_FACTOR: 3,
+    BLOCKS_COLLECT_THRESHOLD: 30,
+    MUTE_LOGS_DURING_UNIT_TESTS: true,
+    SANDBOX_SIZE_TRANSACTIONS: 200,
+    SANDBOX_SIZE_IDENTITIES: 5000,
+    SANDBOX_SIZE_CERTIFICATIONS: 12,
+    SANDBOX_SIZE_MEMBERSHIPS: 5000,
+    CURRENT_BLOCK_CACHE_DURATION: 10 * 1000,
+    // With `logs` command, the number of tail lines to show
+    NB_INITIAL_LINES_TO_SHOW: 100
 };
-
-function exact (regexpContent) {
-  return new RegExp("^" + regexpContent + "$");
+function exact(regexpContent) {
+    return new RegExp("^" + regexpContent + "$");
 }
+//# sourceMappingURL=constants.js.map
\ No newline at end of file
diff --git a/app/lib/constants.ts b/app/lib/constants.ts
new file mode 100644
index 0000000000000000000000000000000000000000..92fef4c10be683516d61e2e66fa102113ec7a569
--- /dev/null
+++ b/app/lib/constants.ts
@@ -0,0 +1,176 @@
+"use strict";
+
+const common = require('duniter-common')
+
+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       = common.constants.FORMATS.PUBKEY
+const TIMESTAMP    = common.constants.FORMATS.TIMESTAMP
+
+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}:))$/;
+
+module.exports = {
+
+  TIME_TO_TURN_ON_BRG_107: 1498860000,
+
+  ERROR: {
+
+    PEER: {
+      UNKNOWN_REFERENCE_BLOCK: 'Unknown reference block of peer'
+    },
+
+    BLOCK: {
+      NO_CURRENT_BLOCK: 'No current block'
+    }
+  },
+
+  ERRORS: {
+
+    // Technical errors
+    UNKNOWN:                              { httpCode: 500, uerr: { ucode: 1001, message: "An unknown error occured" }},
+    UNHANDLED:                            { httpCode: 500, uerr: { ucode: 1002, message: "An unhandled error occured" }},
+    SIGNATURE_DOES_NOT_MATCH:             { httpCode: 400, uerr: { ucode: 1003, message: "Signature does not match" }},
+    ALREADY_UP_TO_DATE:                   { httpCode: 400, uerr: { ucode: 1004, message: "Already up-to-date" }},
+    WRONG_DOCUMENT:                       common.constants.ERRORS.WRONG_DOCUMENT,
+    SANDBOX_FOR_IDENTITY_IS_FULL:         { httpCode: 503, uerr: { ucode: 1007, message: "The identities' sandbox is full. Please retry with another document or retry later." }},
+    SANDBOX_FOR_CERT_IS_FULL:             { httpCode: 503, uerr: { ucode: 1008, message: "The certifications' sandbox is full. Please retry with another document or retry later." }},
+    SANDBOX_FOR_MEMERSHIP_IS_FULL:        { httpCode: 503, uerr: { ucode: 1009, message: "The memberships' sandbox is full. Please retry with another document or retry later." }},
+    SANDBOX_FOR_TRANSACTION_IS_FULL:      { httpCode: 503, uerr: { ucode: 1010, message: "The transactions' sandbox is full. Please retry with another document or retry later." }},
+    NO_POTENTIAL_FORK_AS_NEXT:            { httpCode: 503, uerr: { ucode: 1011, message: "No fork block exists in the database as a potential next block." }},
+    INCONSISTENT_DB_MULTI_TXS_SAME_HASH:  { httpCode: 503, uerr: { ucode: 1012, message: "Several transactions written with the same hash." }},
+    CLI_CALLERR_RESET:                    { httpCode: 503, uerr: { ucode: 1013, message: "Bad command: usage is `reset config`, `reset data`, `reset peers`, `reset stats` or `reset all`" }},
+    CLI_CALLERR_CONFIG:                   { httpCode: 503, uerr: { ucode: 1014, message: "Bad command: usage is `config`." }},
+
+    // Business errors
+    NO_MATCHING_IDENTITY:                 { httpCode: 404, uerr: { ucode: 2001, message: "No matching identity" }},
+    UID_ALREADY_USED:                     { httpCode: 400, uerr: { ucode: 2002, message: "UID already used in the blockchain" }},
+    PUBKEY_ALREADY_USED:                  { httpCode: 400, uerr: { ucode: 2003, message: "Pubkey already used in the blockchain" }},
+    NO_MEMBER_MATCHING_PUB_OR_UID:        { httpCode: 404, uerr: { ucode: 2004, message: "No member matching this pubkey or uid" }},
+    WRONG_SIGNATURE_MEMBERSHIP:           { httpCode: 400, uerr: { ucode: 2006, message: "wrong signature for membership" }},
+    ALREADY_RECEIVED_MEMBERSHIP:          { httpCode: 400, uerr: { ucode: 2007, message: "Already received membership" }},
+    MEMBERSHIP_A_NON_MEMBER_CANNOT_LEAVE: { httpCode: 400, uerr: { ucode: 2008, message: "A non-member cannot leave" }},
+    NOT_A_MEMBER:                         { httpCode: 400, uerr: { ucode: 2009, message: "Not a member" }},
+    BLOCK_NOT_FOUND:                      { httpCode: 404, uerr: { ucode: 2011, message: "Block not found" }},
+    WRONG_UNLOCKER:                       common.constants.ERRORS.WRONG_UNLOCKER,
+    LOCKTIME_PREVENT:                     common.constants.ERRORS.LOCKTIME_PREVENT,
+    SOURCE_ALREADY_CONSUMED:              common.constants.ERRORS.SOURCE_ALREADY_CONSUMED,
+    WRONG_AMOUNTS:                        common.constants.ERRORS.WRONG_AMOUNTS,
+    WRONG_OUTPUT_BASE:                    common.constants.ERRORS.WRONG_OUTPUT_BASE,
+    CANNOT_ROOT_BLOCK_NO_MEMBERS:         common.constants.ERRORS.CANNOT_ROOT_BLOCK_NO_MEMBERS,
+    IDENTITY_WRONGLY_SIGNED:              common.constants.ERRORS.IDENTITY_WRONGLY_SIGNED,
+    TOO_OLD_IDENTITY:                     common.constants.ERRORS.TOO_OLD_IDENTITY,
+    NO_IDTY_MATCHING_PUB_OR_UID:          { httpCode: 404, uerr: { ucode: 2021, message: "No identity matching this pubkey or uid" }},
+    NEWER_PEER_DOCUMENT_AVAILABLE:        { httpCode: 409, uerr: { ucode: 2022, message: "A newer peer document is available" }},
+    PEER_DOCUMENT_ALREADY_KNOWN:          { httpCode: 400, uerr: { ucode: 2023, message: "Peer document already known" }},
+    TX_INPUTS_OUTPUTS_NOT_EQUAL:          common.constants.ERRORS.TX_INPUTS_OUTPUTS_NOT_EQUAL,
+    TX_OUTPUT_SUM_NOT_EQUALS_PREV_DELTAS: common.constants.ERRORS.TX_OUTPUT_SUM_NOT_EQUALS_PREV_DELTAS,
+    BLOCKSTAMP_DOES_NOT_MATCH_A_BLOCK:    common.constants.ERRORS.BLOCKSTAMP_DOES_NOT_MATCH_A_BLOCK,
+    A_TRANSACTION_HAS_A_MAX_SIZE:         common.constants.ERRORS.A_TRANSACTION_HAS_A_MAX_SIZE,
+    BLOCK_ALREADY_PROCESSED:              { httpCode: 400, uerr: { ucode: 2028, message: 'Already processed' }},
+    TOO_OLD_MEMBERSHIP:                   common.constants.ERRORS.TOO_OLD_MEMBERSHIP,
+    TX_ALREADY_PROCESSED:                 { httpCode: 400, uerr: { ucode: 2030, message: "Transaction already processed" }},
+    A_MORE_RECENT_MEMBERSHIP_EXISTS:      { httpCode: 400, uerr: { ucode: 2031, message: "A more recent membership already exists" }},
+    MAXIMUM_LEN_OF_OUTPUT:                common.constants.ERRORS.MAXIMUM_LEN_OF_OUTPUT,
+    MAXIMUM_LEN_OF_UNLOCK:                common.constants.ERRORS.MAXIMUM_LEN_OF_UNLOCK
+  },
+
+  DEBUG: {
+    LONG_DAL_PROCESS: 50
+  },
+
+  BMA_REGEXP: common.constants.BMA_REGEXP,
+  IPV4_REGEXP: IPV4_REGEXP,
+  IPV6_REGEXP: IPV6_REGEXP,
+
+  TIMESTAMP: exact(TIMESTAMP),
+  UDID2_FORMAT: exact(UDID2),
+  PUBLIC_KEY: exact(PUBKEY),
+
+  DOCUMENTS_VERSION: common.constants.DOCUMENTS_VERSION,
+  BLOCK_GENERATED_VERSION: common.constants.BLOCK_GENERATED_VERSION,
+  LAST_VERSION_FOR_TX: 10,
+  TRANSACTION_VERSION: common.constants.TRANSACTION_VERSION,
+
+  REVOCATION_FACTOR: common.constants.REVOCATION_FACTOR, // This is protocol fixed value
+  FIRST_UNIT_BASE: 0,
+
+  PEER: common.constants.PEER,
+  NETWORK: {
+    MAX_MEMBERS_TO_FORWARD_TO_FOR_SELF_DOCUMENTS: 10,
+    MAX_NON_MEMBERS_TO_FORWARD_TO_FOR_SELF_DOCUMENTS: 6,
+    MAX_NON_MEMBERS_TO_FORWARD_TO: 4,
+    MAX_MEMBERS_TO_FORWARD_TO: 6,
+    MAX_CONCURRENT_POST: 3,
+    DEFAULT_TIMEOUT: 10 * 1000, // 10 seconds
+    SYNC: {
+      MAX: 20
+    },
+    STATUS_INTERVAL: {
+      UPDATE: 2, // Every X blocks
+      MAX: 20 // MAX Y blocks
+    }
+  },
+  PROOF_OF_WORK: {
+    EVALUATION: 1000,
+    UPPER_BOUND: common.constants.PROOF_OF_WORK.UPPER_BOUND.slice()
+  },
+
+  DEFAULT_CURRENCY_NAME: "no_currency",
+
+  CONTRACT: {
+    DEFAULT: {
+      C: 0.007376575,
+      DT: 30.4375 * 24 * 3600,
+      DT_REEVAL: 30.4375 * 24 * 3600,
+      UD0: 100,
+      STEPMAX: 3,
+      SIGDELAY: 3600 * 24 * 365 * 5,
+      SIGPERIOD: 0, // Instant
+      MSPERIOD: 0, // Instant
+      SIGSTOCK: 40,
+      SIGWINDOW: 3600 * 24 * 7, // a week
+      SIGVALIDITY: 3600 * 24 * 365,
+      MSVALIDITY: 3600 * 24 * 365,
+      SIGQTY: 5,
+      X_PERCENT: 0.9,
+      PERCENTROT: 2 / 3,
+      BLOCKSROT: 20,
+      POWDELAY: 0,
+      AVGGENTIME: 16 * 60,
+      DTDIFFEVAL: 10,
+      MEDIANTIMEBLOCKS: 20,
+      IDTYWINDOW: 3600 * 24 * 7, // a week
+      MSWINDOW: 3600 * 24 * 7 // a week
+    },
+
+    DSEN_P: 1.2 // dSen proportional factor
+  },
+
+  BRANCHES: {
+    DEFAULT_WINDOW_SIZE: 100
+  },
+
+  INVALIDATE_CORE_CACHE: true,
+  WITH_SIGNATURES_AND_POW: true,
+
+  NO_FORK_ALLOWED: false,
+
+  SAFE_FACTOR: 3,
+  BLOCKS_COLLECT_THRESHOLD: 30, // Blocks to collect from memory and persist
+
+  MUTE_LOGS_DURING_UNIT_TESTS: true,
+
+  SANDBOX_SIZE_TRANSACTIONS: 200,
+  SANDBOX_SIZE_IDENTITIES: 5000,
+  SANDBOX_SIZE_CERTIFICATIONS: 12,
+  SANDBOX_SIZE_MEMBERSHIPS: 5000,
+
+  CURRENT_BLOCK_CACHE_DURATION: 10 * 1000, // 30 seconds
+
+  // With `logs` command, the number of tail lines to show
+  NB_INITIAL_LINES_TO_SHOW: 100
+};
+
+function exact (regexpContent:string) {
+  return new RegExp("^" + regexpContent + "$");
+}
diff --git a/app/lib/helpers/merkle.js b/app/lib/helpers/merkle.js
index 8a0da89e9fccd0b16aa314288208761c9ece2485..b887a0e941caf79be77aba0fa38fda052f583080 100644
--- a/app/lib/helpers/merkle.js
+++ b/app/lib/helpers/merkle.js
@@ -1,35 +1,42 @@
 "use strict";
-const co               = require('co');
-
-module.exports = {
-
-  processForURL: (req, merkle, valueCoroutine) => co(function*() {
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.processForURL = (req, merkle, valueCoroutine) => __awaiter(this, void 0, void 0, function* () {
     // Result
     const json = {
-      "depth": merkle.depth,
-      "nodesCount": merkle.nodes,
-      "leavesCount": merkle.levels[merkle.depth].length,
-      "root": merkle.levels[0][0] || ""
+        "depth": merkle.depth,
+        "nodesCount": merkle.nodes,
+        "leavesCount": merkle.levels[merkle.depth].length,
+        "root": merkle.levels[0][0] || ""
     };
     if (req.query.leaves) {
-      // Leaves
-      json.leaves = merkle.leaves();
-      return json;
-    } else if (req.query.leaf) {
-      // Extract of a leaf
-      json.leaves = {};
-      const hashes = [req.query.leaf];
-      // This code is in a loop for historic reasons. Should be set to non-loop style.
-      const values = yield valueCoroutine(hashes);
-      hashes.forEach((hash) => {
-        json.leaf = {
-          "hash": hash,
-          "value": values[hash] || ""
-        };
-      });
-      return json;
-    } else {
-      return json;
+        // Leaves
+        json.leaves = merkle.leaves();
+        return json;
     }
-  })
-}
+    else if (req.query.leaf) {
+        // Extract of a leaf
+        json.leaves = {};
+        const hashes = [req.query.leaf];
+        // This code is in a loop for historic reasons. Should be set to non-loop style.
+        const values = yield valueCoroutine(hashes);
+        hashes.forEach((hash) => {
+            json.leaf = {
+                "hash": hash,
+                "value": values[hash] || ""
+            };
+        });
+        return json;
+    }
+    else {
+        return json;
+    }
+});
+//# sourceMappingURL=merkle.js.map
\ No newline at end of file
diff --git a/app/lib/helpers/merkle.ts b/app/lib/helpers/merkle.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2c5edd38a7ecad8a342890541033e2c8ad293765
--- /dev/null
+++ b/app/lib/helpers/merkle.ts
@@ -0,0 +1,29 @@
+export const processForURL = async (req:any, merkle:any, valueCoroutine:any) => {
+  // Result
+  const json:any = {
+    "depth": merkle.depth,
+    "nodesCount": merkle.nodes,
+    "leavesCount": merkle.levels[merkle.depth].length,
+    "root": merkle.levels[0][0] || ""
+  };
+  if (req.query.leaves) {
+    // Leaves
+    json.leaves = merkle.leaves();
+    return json;
+  } else if (req.query.leaf) {
+    // Extract of a leaf
+    json.leaves = {};
+    const hashes = [req.query.leaf];
+    // This code is in a loop for historic reasons. Should be set to non-loop style.
+    const values = await valueCoroutine(hashes);
+    hashes.forEach((hash) => {
+      json.leaf = {
+        "hash": hash,
+        "value": values[hash] || ""
+      };
+    });
+    return json;
+  } else {
+    return json;
+  }
+}
diff --git a/app/lib/wizard.js b/app/lib/wizard.js
index eb0e115dd814e2745a43873d94a6772c47d573f7..e7e9e8974730e95ea8b6a7c912ce2e56405392e7 100644
--- a/app/lib/wizard.js
+++ b/app/lib/wizard.js
@@ -1,110 +1,105 @@
 "use strict";
-const co        = require('co');
-const constants = require('./constants');
-const async     = require('async');
-const inquirer  = require('inquirer');
-const logger    = require('./logger').NewLogger('wizard');
-
-module.exports = function () {
-  return new Wizard();
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
 };
-
-function Wizard () {
-
-  this.configPoW = function (conf) {
-    return doTasks(['pow'], conf)
-  }
-
-  this.configCurrency = function (conf) {
-    return doTasks(['currency'], conf)
-  }
-
-  this.configUCP = function (conf) {
-    return doTasks(['parameters'], conf)
-  }
+Object.defineProperty(exports, "__esModule", { value: true });
+const constants = require('./constants');
+const async = require('async');
+const inquirer = require('inquirer');
+const logger = require('./logger').NewLogger('wizard');
+class Wizard {
+    static configPoW(conf) {
+        return doTasks(['pow'], conf);
+    }
+    static configCurrency(conf) {
+        return doTasks(['currency'], conf);
+    }
+    static configUCP(conf) {
+        return doTasks(['parameters'], conf);
+    }
 }
-
-function doTasks (todos, conf) {
-  return new Promise((res, rej) => {
-    async.forEachSeries(todos, function(task, callback){
-      tasks[task] && tasks[task](conf, callback);
-    }, (err) => {
-      if (err) return rej(err)
-      return res()
+exports.Wizard = Wizard;
+function doTasks(todos, conf) {
+    return new Promise((res, rej) => {
+        async.forEachSeries(todos, function (task, callback) {
+            tasks[task] && tasks[task](conf, callback);
+        }, (err) => {
+            if (err)
+                return rej(err);
+            return res();
+        });
     });
-  })
 }
-
 const tasks = {
-
-  currency: function (conf, done) {
-    return co(function*() {
-      const answers = yield inquirer.prompt([{
-        type: "input",
-        name: "currency",
-        message: "Currency name",
-        default: conf.currency,
-        validate: function (input) {
-          return input.match(/^[a-zA-Z0-9-_ ]+$/) ? true : false;
-        }
-      }])
-      conf.currency = answers.currency
-      done()
-    })
-  },
-
-  parameters: function (conf, done) {
-    async.waterfall([
-      async.apply(simpleFloat,   "Universal Dividend %growth",                                             "c", conf),
-      async.apply(simpleInteger, "Universal Dividend period (in seconds)",                                 "dt", conf),
-      async.apply(simpleInteger, "First Universal Dividend (UD[0]) amount",                                "ud0", conf),
-      async.apply(simpleInteger, "Delay between 2 certifications of a same issuer",                        "sigPeriod", conf),
-      async.apply(simpleInteger, "Maximum stock of valid certifications per member",                       "sigStock", conf),
-      async.apply(simpleInteger, "Maximum age of a non-written certification",                             "sigWindow", conf),
-      async.apply(simpleInteger, "Certification validity duration",                                        "sigValidity", conf),
-      async.apply(simpleInteger, "Number of valid certifications required to be a member",                 "sigQty", conf),
-      async.apply(simpleInteger, "Maximum age of a non-written identity",                                  "idtyWindow", conf),
-      async.apply(simpleInteger, "Maximum age of a non-written membership",                                "msWindow", conf),
-      async.apply(simpleFloat,   "Percentage of sentries to be reached to match WoT distance rule",        "xpercent", conf),
-      async.apply(simpleInteger, "Membership validity duration",                                           "msValidity", conf),
-      async.apply(simpleInteger, "Number of blocks on which is computed median time",                      "medianTimeBlocks", conf),
-      async.apply(simpleInteger, "The average time for writing 1 block (wished time)",                     "avgGenTime", conf),
-      async.apply(simpleInteger, "Frequency, in number of blocks, to wait for changing common difficulty", "dtDiffEval", conf),
-      async.apply(simpleFloat,   "Weight in percent for previous issuers",                                 "percentRot", conf)
-    ], done);
-  },
-
-  pow: function (conf, done) {
-    async.waterfall([
-      function (next){
-        simpleInteger("Start computation of a new block if none received since (seconds)", "powDelay", conf, next);
-      }
-    ], done);
-  }
+    currency: function (conf, done) {
+        return __awaiter(this, void 0, void 0, function* () {
+            const answers = yield inquirer.prompt([{
+                    type: "input",
+                    name: "currency",
+                    message: "Currency name",
+                    default: conf.currency,
+                    validate: function (input) {
+                        return input.match(/^[a-zA-Z0-9-_ ]+$/) ? true : false;
+                    }
+                }]);
+            conf.currency = answers.currency;
+            done();
+        });
+    },
+    parameters: function (conf, done) {
+        async.waterfall([
+            async.apply(simpleFloat, "Universal Dividend %growth", "c", conf),
+            async.apply(simpleInteger, "Universal Dividend period (in seconds)", "dt", conf),
+            async.apply(simpleInteger, "First Universal Dividend (UD[0]) amount", "ud0", conf),
+            async.apply(simpleInteger, "Delay between 2 certifications of a same issuer", "sigPeriod", conf),
+            async.apply(simpleInteger, "Maximum stock of valid certifications per member", "sigStock", conf),
+            async.apply(simpleInteger, "Maximum age of a non-written certification", "sigWindow", conf),
+            async.apply(simpleInteger, "Certification validity duration", "sigValidity", conf),
+            async.apply(simpleInteger, "Number of valid certifications required to be a member", "sigQty", conf),
+            async.apply(simpleInteger, "Maximum age of a non-written identity", "idtyWindow", conf),
+            async.apply(simpleInteger, "Maximum age of a non-written membership", "msWindow", conf),
+            async.apply(simpleFloat, "Percentage of sentries to be reached to match WoT distance rule", "xpercent", conf),
+            async.apply(simpleInteger, "Membership validity duration", "msValidity", conf),
+            async.apply(simpleInteger, "Number of blocks on which is computed median time", "medianTimeBlocks", conf),
+            async.apply(simpleInteger, "The average time for writing 1 block (wished time)", "avgGenTime", conf),
+            async.apply(simpleInteger, "Frequency, in number of blocks, to wait for changing common difficulty", "dtDiffEval", conf),
+            async.apply(simpleFloat, "Weight in percent for previous issuers", "percentRot", conf)
+        ], done);
+    },
+    pow: function (conf, done) {
+        async.waterfall([
+            function (next) {
+                simpleInteger("Start computation of a new block if none received since (seconds)", "powDelay", conf, next);
+            }
+        ], done);
+    }
 };
-
-function simpleValue (question, property, defaultValue, conf, validation, done) {
-  return co(function*() {
-    const answers = yield inquirer.prompt([{
-      type: "input",
-      name: property,
-      message: question,
-      default: conf[property],
-      validate: validation
-    }])
-    conf[property] = answers[property]
-    done()
-  })
+function simpleValue(question, property, defaultValue, conf, validation, done) {
+    return __awaiter(this, void 0, void 0, function* () {
+        const answers = yield inquirer.prompt([{
+                type: "input",
+                name: property,
+                message: question,
+                default: conf[property],
+                validate: validation
+            }]);
+        conf[property] = answers[property];
+        done();
+    });
 }
-
-function simpleInteger (question, property, conf, done) {
-  simpleValue(question, property, conf[property], conf, function (input) {
-    return input && input.toString().match(/^[0-9]+$/) ? true : false;
-  }, done);
+function simpleInteger(question, property, conf, done) {
+    simpleValue(question, property, conf[property], conf, function (input) {
+        return input && input.toString().match(/^[0-9]+$/) ? true : false;
+    }, done);
 }
-
-function simpleFloat (question, property, conf, done) {
-  simpleValue(question, property, conf[property], conf, function (input) {
-    return input && input.toString().match(/^[0-9]+(\.[0-9]+)?$/) ? true : false;
-  }, done);
+function simpleFloat(question, property, conf, done) {
+    simpleValue(question, property, conf[property], conf, function (input) {
+        return input && input.toString().match(/^[0-9]+(\.[0-9]+)?$/) ? true : false;
+    }, done);
 }
+//# sourceMappingURL=wizard.js.map
\ No newline at end of file
diff --git a/app/lib/wizard.ts b/app/lib/wizard.ts
new file mode 100644
index 0000000000000000000000000000000000000000..249358d4fba11e979cb4889751c8b3fe4028cf31
--- /dev/null
+++ b/app/lib/wizard.ts
@@ -0,0 +1,102 @@
+import {ConfDTO} from "./dto/ConfDTO"
+
+const constants = require('./constants');
+const async     = require('async');
+const inquirer  = require('inquirer');
+const logger    = require('./logger').NewLogger('wizard');
+
+export class Wizard {
+
+  static configPoW(conf:ConfDTO) {
+    return doTasks(['pow'], conf)
+  }
+
+  static configCurrency(conf:ConfDTO) {
+    return doTasks(['currency'], conf)
+  }
+
+  static configUCP(conf:ConfDTO) {
+    return doTasks(['parameters'], conf)
+  }
+}
+
+function doTasks (todos:string[], conf:ConfDTO) {
+  return new Promise((res, rej) => {
+    async.forEachSeries(todos, function(task:any, callback:any){
+      tasks[task] && tasks[task](conf, callback);
+    }, (err:any) => {
+      if (err) return rej(err)
+      return res()
+    });
+  })
+}
+
+const tasks:any = {
+
+  currency: async function (conf:ConfDTO, done:any) {
+      const answers = await inquirer.prompt([{
+        type: "input",
+        name: "currency",
+        message: "Currency name",
+        default: conf.currency,
+        validate: function (input:string) {
+          return input.match(/^[a-zA-Z0-9-_ ]+$/) ? true : false;
+        }
+      }])
+      conf.currency = answers.currency
+      done()
+  },
+
+  parameters: function (conf:ConfDTO, done:any) {
+    async.waterfall([
+      async.apply(simpleFloat,   "Universal Dividend %growth",                                             "c", conf),
+      async.apply(simpleInteger, "Universal Dividend period (in seconds)",                                 "dt", conf),
+      async.apply(simpleInteger, "First Universal Dividend (UD[0]) amount",                                "ud0", conf),
+      async.apply(simpleInteger, "Delay between 2 certifications of a same issuer",                        "sigPeriod", conf),
+      async.apply(simpleInteger, "Maximum stock of valid certifications per member",                       "sigStock", conf),
+      async.apply(simpleInteger, "Maximum age of a non-written certification",                             "sigWindow", conf),
+      async.apply(simpleInteger, "Certification validity duration",                                        "sigValidity", conf),
+      async.apply(simpleInteger, "Number of valid certifications required to be a member",                 "sigQty", conf),
+      async.apply(simpleInteger, "Maximum age of a non-written identity",                                  "idtyWindow", conf),
+      async.apply(simpleInteger, "Maximum age of a non-written membership",                                "msWindow", conf),
+      async.apply(simpleFloat,   "Percentage of sentries to be reached to match WoT distance rule",        "xpercent", conf),
+      async.apply(simpleInteger, "Membership validity duration",                                           "msValidity", conf),
+      async.apply(simpleInteger, "Number of blocks on which is computed median time",                      "medianTimeBlocks", conf),
+      async.apply(simpleInteger, "The average time for writing 1 block (wished time)",                     "avgGenTime", conf),
+      async.apply(simpleInteger, "Frequency, in number of blocks, to wait for changing common difficulty", "dtDiffEval", conf),
+      async.apply(simpleFloat,   "Weight in percent for previous issuers",                                 "percentRot", conf)
+    ], done);
+  },
+
+  pow: function (conf:ConfDTO, done:any) {
+    async.waterfall([
+      function (next:any){
+        simpleInteger("Start computation of a new block if none received since (seconds)", "powDelay", conf, next);
+      }
+    ], done);
+  }
+};
+
+async function simpleValue (question:string, property:string, defaultValue:any, conf:any, validation:any, done:any) {
+    const answers = await inquirer.prompt([{
+      type: "input",
+      name: property,
+      message: question,
+      default: conf[property],
+      validate: validation
+    }])
+    conf[property] = answers[property]
+    done()
+}
+
+function simpleInteger (question:string, property:string, conf:any, done:any) {
+  simpleValue(question, property, conf[property], conf, function (input:string) {
+    return input && input.toString().match(/^[0-9]+$/) ? true : false;
+  }, done);
+}
+
+function simpleFloat (question:string, property:string, conf:any, done:any) {
+  simpleValue(question, property, conf[property], conf, function (input:string) {
+    return input && input.toString().match(/^[0-9]+(\.[0-9]+)?$/) ? true : false;
+  }, done);
+}
diff --git a/app/modules/wizard.ts b/app/modules/wizard.ts
index 943f227419f118c6d80385339992a62ed76f96c4..938b8f4030f21e3c8ce51ae5770100ef2251e057 100644
--- a/app/modules/wizard.ts
+++ b/app/modules/wizard.ts
@@ -1,7 +1,7 @@
 import {ConfDTO} from "../lib/dto/ConfDTO"
+import {Wizard} from "../lib/wizard"
 
 const _ = require('underscore')
-const wizard = require('../lib/wizard');
 const logger = require('../lib/logger').NewLogger('wizard');
 
 module.exports = {
@@ -9,9 +9,9 @@ module.exports = {
 
     wizard: {
       // The wizard itself also defines its personal tasks
-      'currency': (conf:ConfDTO) => wizard().configCurrency(conf),
-      'pow': (conf:ConfDTO) => wizard().configPoW(conf),
-      'parameters': (conf:ConfDTO) => wizard().configUCP(conf)
+      'currency': (conf:ConfDTO) => Wizard.configCurrency(conf),
+      'pow': (conf:ConfDTO) => Wizard.configPoW(conf),
+      'parameters': (conf:ConfDTO) => Wizard.configUCP(conf)
     },
 
     cli: [{
diff --git a/index.js b/index.js
index 07bc3b3454dc725b19ddd7fb3c9e061986c1c5ca..25d669f2334a4672b9ce724523c2d3f52890fc97 100644
--- a/index.js
+++ b/index.js
@@ -8,7 +8,6 @@ const _ = require('underscore');
 const Server = require('./server');
 const directory = require('./app/lib/system/directory');
 const constants = require('./app/lib/constants');
-const wizard = require('./app/lib/wizard');
 const logger = require('./app/lib/logger').NewLogger('duniter');
 
 const configDependency    = require('./app/modules/config');