From 07505ece506d1096a274940c6562ae6f9b07aca9 Mon Sep 17 00:00:00 2001
From: cgeek <cem.moreau@gmail.com>
Date: Sat, 15 Jul 2017 19:39:53 +0200
Subject: [PATCH] [enh] #1037 Migrate SQLite DALs

---
 .eslintignore                                 |   2 +
 .eslintrc                                     |   2 +-
 .gitignore                                    |   4 +-
 app/lib/blockchain/SqlIndex.ts                |  10 +-
 app/lib/computation/QuickSync.ts              |   4 +-
 app/lib/dal/fileDAL.js                        |  36 +--
 app/lib/dal/sqliteDAL/AbstractIndex.js        |  38 ---
 app/lib/dal/sqliteDAL/AbstractIndex.ts        |  48 +++
 app/lib/dal/sqliteDAL/AbstractSQLite.js       | 290 -----------------
 app/lib/dal/sqliteDAL/AbstractSQLite.ts       | 291 ++++++++++++++++++
 app/lib/dal/sqliteDAL/BlockDAL.js             | 158 ----------
 app/lib/dal/sqliteDAL/BlockDAL.ts             | 193 ++++++++++++
 app/lib/dal/sqliteDAL/CertDAL.js              | 113 -------
 app/lib/dal/sqliteDAL/CertDAL.ts              | 144 +++++++++
 app/lib/dal/sqliteDAL/IdentityDAL.js          | 146 ---------
 app/lib/dal/sqliteDAL/IdentityDAL.ts          | 192 ++++++++++++
 app/lib/dal/sqliteDAL/IndexDAL.js             |  10 -
 app/lib/dal/sqliteDAL/MembershipDAL.js        | 116 -------
 app/lib/dal/sqliteDAL/MembershipDAL.ts        | 154 +++++++++
 .../dal/sqliteDAL/{MetaDAL.js => MetaDAL.ts}  | 248 ++++++++-------
 app/lib/dal/sqliteDAL/PeerDAL.js              |  66 ----
 app/lib/dal/sqliteDAL/PeerDAL.ts              |  89 ++++++
 app/lib/dal/sqliteDAL/SandBox.js              |  29 --
 app/lib/dal/sqliteDAL/SandBox.ts              |  30 ++
 app/lib/dal/sqliteDAL/TxsDAL.js               | 187 -----------
 app/lib/dal/sqliteDAL/TxsDAL.ts               | 257 ++++++++++++++++
 app/lib/dal/sqliteDAL/WalletDAL.js            |  47 ---
 app/lib/dal/sqliteDAL/WalletDAL.ts            |  56 ++++
 app/lib/dal/sqliteDAL/index/BIndexDAL.js      | 113 -------
 app/lib/dal/sqliteDAL/index/BIndexDAL.ts      | 117 +++++++
 app/lib/dal/sqliteDAL/index/CIndexDAL.js      | 129 --------
 app/lib/dal/sqliteDAL/index/CIndexDAL.ts      | 138 +++++++++
 app/lib/dal/sqliteDAL/index/IIndexDAL.js      | 145 ---------
 app/lib/dal/sqliteDAL/index/IIndexDAL.ts      | 175 +++++++++++
 app/lib/dal/sqliteDAL/index/MIndexDAL.js      |  72 -----
 app/lib/dal/sqliteDAL/index/MIndexDAL.ts      |  73 +++++
 app/lib/dal/sqliteDAL/index/SIndexDAL.js      | 128 --------
 app/lib/dal/sqliteDAL/index/SIndexDAL.ts      | 129 ++++++++
 app/lib/db/DBTransaction.ts                   |   1 +
 app/lib/dto/ConfDTO.ts                        |   4 +
 app/lib/dto/TransactionDTO.ts                 |  37 ++-
 app/lib/indexer.ts                            |  12 +-
 test/blockchain/basic-blockchain.ts           |   9 +-
 test/blockchain/misc-sql-blockchain.ts        |  15 +-
 44 files changed, 2296 insertions(+), 1961 deletions(-)
 delete mode 100644 app/lib/dal/sqliteDAL/AbstractIndex.js
 create mode 100644 app/lib/dal/sqliteDAL/AbstractIndex.ts
 delete mode 100644 app/lib/dal/sqliteDAL/AbstractSQLite.js
 create mode 100644 app/lib/dal/sqliteDAL/AbstractSQLite.ts
 delete mode 100644 app/lib/dal/sqliteDAL/BlockDAL.js
 create mode 100644 app/lib/dal/sqliteDAL/BlockDAL.ts
 delete mode 100644 app/lib/dal/sqliteDAL/CertDAL.js
 create mode 100644 app/lib/dal/sqliteDAL/CertDAL.ts
 delete mode 100644 app/lib/dal/sqliteDAL/IdentityDAL.js
 create mode 100644 app/lib/dal/sqliteDAL/IdentityDAL.ts
 delete mode 100644 app/lib/dal/sqliteDAL/IndexDAL.js
 delete mode 100644 app/lib/dal/sqliteDAL/MembershipDAL.js
 create mode 100644 app/lib/dal/sqliteDAL/MembershipDAL.ts
 rename app/lib/dal/sqliteDAL/{MetaDAL.js => MetaDAL.ts} (70%)
 delete mode 100644 app/lib/dal/sqliteDAL/PeerDAL.js
 create mode 100644 app/lib/dal/sqliteDAL/PeerDAL.ts
 delete mode 100644 app/lib/dal/sqliteDAL/SandBox.js
 create mode 100644 app/lib/dal/sqliteDAL/SandBox.ts
 delete mode 100644 app/lib/dal/sqliteDAL/TxsDAL.js
 create mode 100644 app/lib/dal/sqliteDAL/TxsDAL.ts
 delete mode 100644 app/lib/dal/sqliteDAL/WalletDAL.js
 create mode 100644 app/lib/dal/sqliteDAL/WalletDAL.ts
 delete mode 100644 app/lib/dal/sqliteDAL/index/BIndexDAL.js
 create mode 100644 app/lib/dal/sqliteDAL/index/BIndexDAL.ts
 delete mode 100644 app/lib/dal/sqliteDAL/index/CIndexDAL.js
 create mode 100644 app/lib/dal/sqliteDAL/index/CIndexDAL.ts
 delete mode 100644 app/lib/dal/sqliteDAL/index/IIndexDAL.js
 create mode 100644 app/lib/dal/sqliteDAL/index/IIndexDAL.ts
 delete mode 100644 app/lib/dal/sqliteDAL/index/MIndexDAL.js
 create mode 100644 app/lib/dal/sqliteDAL/index/MIndexDAL.ts
 delete mode 100644 app/lib/dal/sqliteDAL/index/SIndexDAL.js
 create mode 100644 app/lib/dal/sqliteDAL/index/SIndexDAL.ts

diff --git a/.eslintignore b/.eslintignore
index c9abbdbe3..bd0ff0f1e 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -6,5 +6,7 @@ app/lib/dto/*.js
 app/lib/indexer.js
 app/lib/common.js
 app/lib/dal/drivers/*.js
+app/lib/dal/sqliteDAL/*.js
+app/lib/dal/sqliteDAL/index/*.js
 test/blockchain/*.js
 test/blockchain/lib/*.js
\ No newline at end of file
diff --git a/.eslintrc b/.eslintrc
index 06403faf2..1fe67b099 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -35,7 +35,7 @@
     "comma-dangle": [1],
     "eol-last": [1],
     "no-shadow": [1],
-    "no-unused-vars": ["warning", { "varsIgnorePattern": "should"}],
+    "no-unused-vars": [1, { "varsIgnorePattern": "should"}],
     "space-infix-ops": [1],
     "handle-callback-err": [1],
     "no-extra-semi": [1]
diff --git a/.gitignore b/.gitignore
index 19d6ac634..cc5097572 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,4 +42,6 @@ app/lib/common.js*
 app/lib/db/*.js*
 app/lib/dto/*.js*
 app/lib/indexer.js*
-app/lib/dal/drivers/*.js*
\ No newline at end of file
+app/lib/dal/drivers/*.js*
+app/lib/dal/sqliteDAL/*.js*
+app/lib/dal/sqliteDAL/index/*.js*
\ No newline at end of file
diff --git a/app/lib/blockchain/SqlIndex.ts b/app/lib/blockchain/SqlIndex.ts
index 3ab081d5d..60ca27de5 100644
--- a/app/lib/blockchain/SqlIndex.ts
+++ b/app/lib/blockchain/SqlIndex.ts
@@ -1,7 +1,7 @@
 "use strict"
 import {IndexOperator} from "./interfaces/IndexOperator"
+import {AbstractIndex} from "../dal/sqliteDAL/AbstractIndex";
 
-const IndexDAL = require('../dal/sqliteDAL/IndexDAL')
 const _ = require('underscore')
 
 export class SQLIndex implements IndexOperator {
@@ -19,18 +19,14 @@ export class SQLIndex implements IndexOperator {
         this.indexes[k] = this.definitions[k].handler
       } else {
         // Internal table: managed here
-        const indexTable = new IndexDAL(this.db);
-        const pk = pkFields[k].pk
-        indexTable.table = k
-        indexTable.fields = this.definitions[k].fields
-        indexTable.booleans = this.definitions[k].booleans
+        const indexTable = new AbstractIndex<any>(this.db, k, [], this.definitions[k].fields, [], this.definitions[k].booleans)
         this.indexes[k] = indexTable
         indexTable.init = () => {
           return indexTable.exec('BEGIN;' +
             'CREATE TABLE IF NOT EXISTS ' + indexTable.table + ' (' +
             this.definitions[k].sqlFields.join(',') +
             ');' +
-            'COMMIT;', [])
+            'COMMIT;')
         }
         await indexTable.init()
       }
diff --git a/app/lib/computation/QuickSync.ts b/app/lib/computation/QuickSync.ts
index 261878e4f..3406ff3e7 100644
--- a/app/lib/computation/QuickSync.ts
+++ b/app/lib/computation/QuickSync.ts
@@ -31,7 +31,7 @@ const sync_memoryDAL = {
     }
   },
   sindexDAL: {
-    getAvailableForConditions: null
+    getAvailableForConditions: (conditions:string) => null
   }
 }
 
@@ -90,7 +90,7 @@ export class QuickSynchronizer {
 
   async quickApplyBlocks(blocks:BlockDTO[], to: number | null): Promise<void> {
 
-    sync_memoryDAL.sindexDAL = { getAvailableForConditions: this.dal.sindexDAL.getAvailableForConditions }
+    sync_memoryDAL.sindexDAL = { getAvailableForConditions: (conditions:string) => this.dal.sindexDAL.getAvailableForConditions(conditions) }
     let blocksToSave: BlockDTO[] = [];
 
     for (const block of blocks) {
diff --git a/app/lib/dal/fileDAL.js b/app/lib/dal/fileDAL.js
index ad57c658c..f6fd59cf3 100644
--- a/app/lib/dal/fileDAL.js
+++ b/app/lib/dal/fileDAL.js
@@ -8,6 +8,7 @@ const logger = require('../logger')('filedal');
 const Configuration = require('../entity/configuration');
 const Merkle = require('../entity/merkle');
 const Transaction = require('../entity/transaction');
+const TransactionDTO = require('../dto/TransactionDTO').TransactionDTO
 const constants = require('../constants');
 const ConfDAL = require('./fileDALs/confDAL');
 const StatDAL = require('./fileDALs/statDAL');
@@ -29,20 +30,20 @@ function FileDAL(params) {
 
   // DALs
   this.confDAL = new ConfDAL(rootPath, myFS, null, that, CFSStorage);
-  this.metaDAL = new (require('./sqliteDAL/MetaDAL'))(sqliteDriver);
-  this.peerDAL = new (require('./sqliteDAL/PeerDAL'))(sqliteDriver);
-  this.blockDAL = new (require('./sqliteDAL/BlockDAL'))(sqliteDriver);
-  this.txsDAL = new (require('./sqliteDAL/TxsDAL'))(sqliteDriver);
+  this.metaDAL = new (require('./sqliteDAL/MetaDAL').MetaDAL)(sqliteDriver);
+  this.peerDAL = new (require('./sqliteDAL/PeerDAL').PeerDAL)(sqliteDriver);
+  this.blockDAL = new (require('./sqliteDAL/BlockDAL').BlockDAL)(sqliteDriver);
+  this.txsDAL = new (require('./sqliteDAL/TxsDAL').TxsDAL)(sqliteDriver);
   this.statDAL = new StatDAL(rootPath, myFS, null, that, CFSStorage);
-  this.idtyDAL = new (require('./sqliteDAL/IdentityDAL'))(sqliteDriver);
-  this.certDAL = new (require('./sqliteDAL/CertDAL'))(sqliteDriver);
-  this.msDAL = new (require('./sqliteDAL/MembershipDAL'))(sqliteDriver);
-  this.walletDAL = new (require('./sqliteDAL/WalletDAL'))(sqliteDriver);
-  this.bindexDAL = new (require('./sqliteDAL/index/BIndexDAL'))(sqliteDriver);
-  this.mindexDAL = new (require('./sqliteDAL/index/MIndexDAL'))(sqliteDriver);
-  this.iindexDAL = new (require('./sqliteDAL/index/IIndexDAL'))(sqliteDriver);
-  this.sindexDAL = new (require('./sqliteDAL/index/SIndexDAL'))(sqliteDriver);
-  this.cindexDAL = new (require('./sqliteDAL/index/CIndexDAL'))(sqliteDriver);
+  this.idtyDAL = new (require('./sqliteDAL/IdentityDAL').IdentityDAL)(sqliteDriver);
+  this.certDAL = new (require('./sqliteDAL/CertDAL').CertDAL)(sqliteDriver);
+  this.msDAL = new (require('./sqliteDAL/MembershipDAL').MembershipDAL)(sqliteDriver);
+  this.walletDAL = new (require('./sqliteDAL/WalletDAL').WalletDAL)(sqliteDriver);
+  this.bindexDAL = new (require('./sqliteDAL/index/BIndexDAL').BIndexDAL)(sqliteDriver);
+  this.mindexDAL = new (require('./sqliteDAL/index/MIndexDAL').MIndexDAL)(sqliteDriver);
+  this.iindexDAL = new (require('./sqliteDAL/index/IIndexDAL').IIndexDAL)(sqliteDriver);
+  this.sindexDAL = new (require('./sqliteDAL/index/SIndexDAL').SIndexDAL)(sqliteDriver);
+  this.cindexDAL = new (require('./sqliteDAL/index/CIndexDAL').CIndexDAL)(sqliteDriver);
 
   this.newDals = {
     'metaDAL': that.metaDAL,
@@ -527,7 +528,7 @@ function FileDAL(params) {
     block.wrong = false;
     yield [
       that.saveBlockInFile(block),
-      that.saveTxsInFiles(block.transactions, {block_number: block.number, time: block.medianTime, currency: block.currency })
+      that.saveTxsInFiles(block.transactions, block.number, block.medianTime)
     ];
   });
 
@@ -591,14 +592,13 @@ function FileDAL(params) {
 
   this.saveSideBlockInFile = (block) => that.writeSideFileOfBlock(block);
 
-  this.saveTxsInFiles = (txs, extraProps) => {
+  this.saveTxsInFiles = (txs, block_number, medianTime) => {
     return Q.all(txs.map((tx) => co(function*() {
-      _.extend(tx, extraProps);
       const sp = tx.blockstamp.split('-');
       tx.blockstampTime = (yield that.getBlockByNumberAndHash(sp[0], sp[1])).medianTime;
       const txEntity = new Transaction(tx);
       txEntity.computeAllHashes();
-      return that.txsDAL.addLinked(txEntity);
+      return that.txsDAL.addLinked(TransactionDTO.fromJSONObject(txEntity), block_number, medianTime);
     })));
   };
 
@@ -628,7 +628,7 @@ function FileDAL(params) {
 
   this.registerNewCertification = (cert) => that.certDAL.saveNewCertification(cert);
 
-  this.saveTransaction = (tx) => that.txsDAL.addPending(tx);
+  this.saveTransaction = (tx) => that.txsDAL.addPending(TransactionDTO.fromJSONObject(tx))
 
   this.getTransactionsHistory = (pubkey) => co(function*() {
     const history = {
diff --git a/app/lib/dal/sqliteDAL/AbstractIndex.js b/app/lib/dal/sqliteDAL/AbstractIndex.js
deleted file mode 100644
index 1078a8257..000000000
--- a/app/lib/dal/sqliteDAL/AbstractIndex.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * Created by cgeek on 22/08/15.
- */
-
-const _ = require('underscore');
-const co = require('co');
-const indexer = require('../../indexer').Indexer
-
-module.exports = AbstractIndex;
-
-function AbstractIndex() {
-
-  "use strict";
-
-  const that = this;
-
-  this.getWrittenOn = (blockstamp) => that.query('SELECT * FROM ' + that.table + ' WHERE written_on = ?', [blockstamp]);
-
-  this.trimRecords = (belowNumber) => co(function*() {
-    const belowRecords = yield that.query('SELECT COUNT(*) as nbRecords, pub FROM ' + that.table + ' ' +
-      'WHERE CAST(written_on as int) < ? ' +
-      'GROUP BY pub ' +
-      'HAVING nbRecords > 1', [belowNumber]);
-    const reducedByPub = indexer.DUP_HELPERS.reduceBy(belowRecords, ['pub']);
-    for (const record of reducedByPub) {
-      const recordsOfPub = yield that.query('SELECT * FROM ' + that.table + ' WHERE pub = ?', [record.pub]);
-      const toReduce = _.filter(recordsOfPub, (rec) => parseInt(rec.written_on) < belowNumber);
-      if (toReduce.length) {
-        // Clean the records in the DB
-        yield that.exec('DELETE FROM ' + that.table + ' WHERE pub = \'' + record.pub + '\'');
-        const nonReduced = _.filter(recordsOfPub, (rec) => parseInt(rec.written_on) >= belowNumber);
-        const reduced = indexer.DUP_HELPERS.reduce(toReduce);
-        // Persist
-        yield that.insertBatch([reduced].concat(nonReduced));
-      }
-    }
-  });
-}
diff --git a/app/lib/dal/sqliteDAL/AbstractIndex.ts b/app/lib/dal/sqliteDAL/AbstractIndex.ts
new file mode 100644
index 000000000..6c4e073e7
--- /dev/null
+++ b/app/lib/dal/sqliteDAL/AbstractIndex.ts
@@ -0,0 +1,48 @@
+import {AbstractSQLite, BeforeSaveHook} from "./AbstractSQLite";
+import {SQLiteDriver} from "../drivers/SQLiteDriver";
+import {IndexEntry, Indexer} from "../../indexer";
+
+const _ = require('underscore');
+
+export class AbstractIndex<T extends IndexEntry> extends AbstractSQLite<T> {
+
+  constructor(
+    driver:SQLiteDriver,
+    table: string,
+    pkFields: string[] = [],
+    fields: string[] = [],
+    arrays: string[] = [],
+    booleans: string[] = [],
+    bigintegers: string[] = [],
+    transientFields: string[] = [],
+    beforeSaveHook: BeforeSaveHook<T> | null = null
+  ) {
+    super(driver, table, pkFields, fields, arrays, booleans, bigintegers, transientFields, beforeSaveHook)
+  }
+
+  public async init() {}
+
+  getWrittenOn(blockstamp:string) {
+    return this.query('SELECT * FROM ' + this.table + ' WHERE written_on = ?', [blockstamp])
+  }
+
+  async trimRecords(belowNumber:number) {
+    const belowRecords:T[] = await this.query('SELECT COUNT(*) as nbRecords, pub FROM ' + this.table + ' ' +
+      'WHERE CAST(written_on as int) < ? ' +
+      'GROUP BY pub ' +
+      'HAVING nbRecords > 1', [belowNumber]);
+    const reducedByPub = Indexer.DUP_HELPERS.reduceBy(belowRecords, ['pub']);
+    for (const record of reducedByPub) {
+      const recordsOfPub = await this.query('SELECT * FROM ' + this.table + ' WHERE pub = ?', [record.pub]);
+      const toReduce = _.filter(recordsOfPub, (rec:T) => parseInt(rec.written_on) < belowNumber);
+      if (toReduce.length) {
+        // Clean the records in the DB
+        await this.exec('DELETE FROM ' + this.table + ' WHERE pub = \'' + record.pub + '\'');
+        const nonReduced = _.filter(recordsOfPub, (rec:T) => parseInt(rec.written_on) >= belowNumber);
+        const reduced = Indexer.DUP_HELPERS.reduce(toReduce);
+        // Persist
+        await this.insertBatch([reduced].concat(nonReduced));
+      }
+    }
+  }
+}
diff --git a/app/lib/dal/sqliteDAL/AbstractSQLite.js b/app/lib/dal/sqliteDAL/AbstractSQLite.js
deleted file mode 100644
index 2cdeb954d..000000000
--- a/app/lib/dal/sqliteDAL/AbstractSQLite.js
+++ /dev/null
@@ -1,290 +0,0 @@
-/**
- * Created by cgeek on 22/08/15.
- */
-
-const _ = require('underscore');
-const co = require('co');
-const colors = require('colors');
-const logger = require('../../logger')('sqlite');
-
-module.exports = AbstractSQLite;
-
-function AbstractSQLite(driver) {
-
-  "use strict";
-
-  const that = this;
-
-  this.ASC = false;
-  this.DESC = true;
-  this.arrays = [];
-  this.booleans = [];
-  this.bigintegers = [];
-  this.translated = {};
-
-  this.query = (sql, params) => co(function *() {
-    try {
-      //logger.trace(sql, JSON.stringify(params || []));
-      const start = new Date();
-      const res = yield driver.executeAll(sql, params || []);
-      const duration = (new Date()) - start;
-      const entities = res.map(toEntity);
-      // Display result
-      let msg = sql + ' | %s\t==> %s rows in %s ms';
-      if (duration <= 2) {
-        msg = colors.green(msg);
-      } else if(duration <= 5) {
-        msg = colors.yellow(msg);
-      } else if (duration <= 10) {
-        msg = colors.magenta(msg);
-      } else if (duration <= 100) {
-        msg = colors.red(msg);
-      }
-      logger.query(msg, JSON.stringify(params || []), entities.length, duration);
-      return entities;
-    } catch (e) {
-      logger.error('ERROR >> %s', sql, JSON.stringify(params || []), e.stack || e.message || e);
-      throw e;
-    }
-  });
-
-  this.cleanData = () => this.query("DELETE FROM " + this.table);
-
-  this.sqlListAll = () => this.query("SELECT * FROM " + this.table);
-
-  this.sqlDeleteAll = () => this.exec("DELETE FROM " + this.table);
-
-  this.sqlFind = (obj, sortObj) => co(function *() {
-    const conditions = toConditionsArray(obj).join(' and ');
-    const values = toParams(obj);
-    const sortKeys = _.keys(sortObj);
-    const sort = sortKeys.length ? ' ORDER BY ' + sortKeys.map((k) => "`" + k + "` " + (sortObj[k] ? 'DESC' : 'ASC')).join(',') : '';
-    return that.query('SELECT * FROM ' + that.table + ' WHERE ' + conditions + sort, values);
-  });
-
-  this.sqlFindOne = (obj, sortObj) => co(function *() {
-    const res = yield that.sqlFind(obj, sortObj);
-    return res[0];
-  });
-
-  this.sqlFindLikeAny = (obj, sort) => co(function *() {
-    const keys = _.keys(obj);
-    return that.query('SELECT * FROM ' + that.table + ' WHERE ' + keys.map((k) => 'UPPER(`' + k + '`) like ?').join(' or '), keys.map((k) => obj[k].toUpperCase()), sort);
-  });
-
-  this.sqlRemoveWhere = (obj) => co(function *() {
-    const keys = _.keys(obj);
-    return that.query('DELETE FROM ' + that.table + ' WHERE ' + keys.map((k) => '`' + k + '` = ?').join(' and '), keys.map((k) => obj[k]));
-  });
-
-  this.sqlExisting = (entity) => that.getEntity(entity);
-
-  this.saveEntity = (entity) => co(function *() {
-    let toSave = entity;
-    if (that.beforeSaveHook) {
-      that.beforeSaveHook(toSave);
-    }
-    const existing = yield that.getEntity(toSave);
-    if (existing) {
-      toSave = toRow(toSave);
-      const valorizations = that.fields.map((field) => '`' + field + '` = ?').join(', ');
-      const conditions = getPKFields().map((field) => '`' + field + '` = ?').join(' and ');
-      const setValues = that.fields.map((field) => toSave[field]);
-      const condValues = getPKFields().map((k) => toSave[k]);
-      return that.query('UPDATE ' + that.table + ' SET ' + valorizations + ' WHERE ' + conditions, setValues.concat(condValues));
-    }
-    yield that.insert(toSave);
-  });
-
-  this.insert = (entity) => co(function *() {
-    const row = toRow(entity);
-    const values = that.fields.map((f) => row[f]);
-    yield that.query(that.getInsertQuery(), values);
-  });
-
-  this.getEntity = (entity) => co(function *() {
-    const conditions = getPKFields().map((field) => '`' + field + '` = ?').join(' and ');
-    const params = toParams(entity, getPKFields());
-    return (yield that.query('SELECT * FROM ' + that.table + ' WHERE ' + conditions, params))[0];
-  });
-
-  this.deleteEntity = (entity) => co(function *() {
-    const toSave = toRow(entity);
-    if (that.beforeSaveHook) {
-      that.beforeSaveHook(toSave);
-    }
-    const conditions = getPKFields().map((field) => '`' + field + '` = ?').join(' and ');
-    const condValues = getPKFields().map((k) => toSave[k]);
-    return that.query('DELETE FROM ' + that.table + ' WHERE ' + conditions, condValues);
-  });
-
-  this.exec = (sql) => co(function *() {
-    try {
-      // logger.trace(sql);
-      return driver.executeSql(sql);
-    } catch (e) {
-      logger.error('ERROR >> %s', sql);
-      throw e;
-    }
-  });
-
-  this.getInsertQuery = () =>
-    "INSERT INTO " + that.table + " (" + getFields(that.fields).map(f => '`' + f + '`').join(',') + ") VALUES (" + "?,".repeat(that.fields.length - 1) + "?);";
-
-  this.getInsertHead = () => {
-    const valuesKeys = getFields(that.fields);
-    return 'INSERT INTO ' + that.table + " (" + valuesKeys.map(f => '`' + f + '`').join(',') + ") VALUES ";
-  };
-
-  this.getInsertValue = (toSave) => {
-    if (that.beforeSaveHook) {
-      that.beforeSaveHook(toSave);
-    }
-    const row = toRow(toSave);
-    const valuesKeys = getFields(that.fields);
-    const values = valuesKeys.map((field) => escapeToSQLite(row[field]));
-    return "(" + values.join(',') + ")";
-  };
-
-  this.toInsertValues = (entity) => {
-    const row = toRow(entity);
-    const values = that.fields.map((f) => row[f]);
-    const formatted = values.map(escapeToSQLite);
-    return "(" + formatted.join(',') + ")";
-  };
-
-  /**
-   * Make a batch insert.
-   * @param records The records to insert as a batch.
-   */
-  this.insertBatch = (records) => co(function *() {
-    const queries = [];
-    if (records.length) {
-      const insert = that.getInsertHead();
-      const values = records.map((src) => that.getInsertValue(src));
-      queries.push(insert + '\n' + values.join(',\n') + ';');
-    }
-    if (queries.length) {
-      return that.exec(queries.join('\n'));
-    }
-  });
-
-  function toConditionsArray(obj) {
-    return _.keys(obj).map((k) => {
-      if (obj[k].$lte !== undefined) {
-        return '`' + k + '` <= ?';
-      } else if (obj[k].$gte !== undefined) {
-        return '`' + k + '` >= ?';
-      } else if (obj[k].$gt !== undefined) {
-        return '`' + k + '` > ?';
-      }  else if (obj[k].$lt !== undefined) {
-        return '`' + k + '` < ?';
-      }  else if (obj[k].$null !== undefined) {
-        return '`' + k + '` IS ' + (!obj[k].$null ? 'NOT' : '') + ' NULL';
-      }  else if (obj[k].$contains !== undefined) {
-        return '`' + k + '` LIKE ?';
-      } else {
-        return '`' + k + '` = ?';
-      }
-    });
-  }
-
-  const toParams = (obj, fields) => {
-    let params = [];
-    (fields || _.keys(obj)).forEach((f) => {
-      if (obj[f].$null === undefined) {
-        let pValue;
-        if      (obj[f].$lte  !== undefined)      { pValue = obj[f].$lte;  }
-        else if (obj[f].$gte  !== undefined)      { pValue = obj[f].$gte;  }
-        else if (obj[f].$gt   !== undefined)      { pValue = obj[f].$gt;   }
-        else if (obj[f].$lt   !== undefined)      { pValue = obj[f].$lt;   }
-        else if (obj[f].$null !== undefined)      { pValue = obj[f].$null; }
-        else if (obj[f].$contains !== undefined) { pValue = "%" + obj[f].$contains + "%"; }
-        else if (~that.bigintegers.indexOf(f) && typeof obj[f] !== "string") {
-          pValue = String(obj[f]);
-        } else {
-          pValue = obj[f];
-        }
-        params.push(pValue);
-      }
-    });
-    return params;
-  };
-
-  const escapeToSQLite = (val) => {
-    if (typeof val == "boolean") {
-      // SQLite specific: true => 1, false => 0
-      if (val !== null && val !== undefined) {
-        return val ? 1 : 0;
-      } else {
-        return null;
-      }
-    }
-    else if (typeof val == "string") {
-      return "'" + val.replace(/'/g, "\\'") + "'";
-    }
-    else if (val === undefined) {
-      return "null";
-    } else {
-      return JSON.stringify(val);
-    }
-  };
-
-  const getPKFields = () => getFields(that.pkFields);
-
-  const getFields = (fields) => fields.map((f) => getField(f));
-
-  const getField = (f) => that.translated[f] || f;
-
-  function toEntity(row) {
-    for (const arr of that.arrays) {
-      row[arr] = row[arr] ? JSON.parse(row[arr]) : [];
-    }
-    // Big integers are stored as strings to avoid data loss
-    for (const bigint of that.bigintegers) {
-      if (row[bigint] !== null && row[bigint] !== undefined) {
-        row[bigint] = parseInt(row[bigint]);
-      }
-    }
-    // Translate some DB fields to obj fields
-    let toTranslate = that.translated || {};
-    let toDBFields = _.keys(toTranslate);
-    for (const objField of toDBFields) {
-      row[objField] = row[toTranslate[objField]];
-    }
-    // Booleans
-    for (const f of that.booleans) {
-      row[f] = row[f] !== null ? Boolean(row[f]) : null;
-    }
-    // Transient
-    for (const f of (that.transientFields || [])) {
-      row[f] = row[f];
-    }
-    return row;
-  }
-
-  function toRow(entity) {
-    let row = {};
-    for (const f of that.fields) {
-      row[f] = entity[f]
-    }
-    for (const arr of that.arrays) {
-      row[arr] = JSON.stringify(row[arr] || []);
-    }
-    // Big integers are stored as strings to avoid data loss
-    for (const bigint of that.bigintegers) {
-      if (entity[bigint] === null || entity[bigint] === undefined) {
-        row[bigint] = null;
-      } else {
-        row[bigint] = String(entity[bigint]);
-      }
-    }
-    // Translate some obj fields to DB field name (because of DB keywords)
-    let toTranslate = that.translated || {};
-    let toDBFields = _.keys(toTranslate);
-    for (const objField of toDBFields) {
-      row[toTranslate[objField]] = row[objField];
-    }
-    return row;
-  }
-}
diff --git a/app/lib/dal/sqliteDAL/AbstractSQLite.ts b/app/lib/dal/sqliteDAL/AbstractSQLite.ts
new file mode 100644
index 000000000..b74dcf022
--- /dev/null
+++ b/app/lib/dal/sqliteDAL/AbstractSQLite.ts
@@ -0,0 +1,291 @@
+import {SQLiteDriver} from "../drivers/SQLiteDriver"
+/**
+ * Created by cgeek on 22/08/15.
+ */
+
+const _ = require('underscore');
+const co = require('co');
+const colors = require('colors');
+const logger = require('../../logger')('sqlite');
+
+export interface BeforeSaveHook<T> {
+  (t:T): void
+}
+
+export abstract class AbstractSQLite<T> {
+
+  constructor(
+    private driver:SQLiteDriver,
+    public readonly table: string,
+    private pkFields: string[] = [],
+    protected fields: string[] = [],
+    private arrays: string[] = [],
+    private booleans: string[] = [],
+    private bigintegers: string[] = [],
+    private transientFields: string[] = [],
+    private beforeSaveHook: BeforeSaveHook<T> | null = null
+  ) {
+  }
+
+  async query(sql:string, params: any[] = []): Promise<T[]> {
+    try {
+      //logger.trace(sql, JSON.stringify(params || []));
+      const start = Date.now()
+      const res = await this.driver.executeAll(sql, params || []);
+      const duration = Date.now() - start;
+      const entities = res.map((t:T) => this.toEntity(t))
+      // Display result
+      let msg = sql + ' | %s\t==> %s rows in %s ms';
+      if (duration <= 2) {
+        msg = colors.green(msg);
+      } else if(duration <= 5) {
+        msg = colors.yellow(msg);
+      } else if (duration <= 10) {
+        msg = colors.magenta(msg);
+      } else if (duration <= 100) {
+        msg = colors.red(msg);
+      }
+      logger.query(msg, JSON.stringify(params || []), entities.length, duration);
+      return entities;
+    } catch (e) {
+      logger.error('ERROR >> %s', sql, JSON.stringify(params || []), e.stack || e.message || e);
+      throw e;
+    }
+  }
+
+  cleanData(): Promise<void> {
+    return this.exec("DELETE FROM " + this.table)
+  }
+
+  sqlListAll(): Promise<T[]> {
+    return this.query("SELECT * FROM " + this.table)
+  }
+
+  sqlDeleteAll() {
+    return this.cleanData()
+  }
+
+  sqlFind(obj:any, sortObj:any = {}): Promise<T[]> {
+    const conditions = this.toConditionsArray(obj).join(' and ');
+    const values = this.toParams(obj);
+    const sortKeys: string[] = _.keys(sortObj);
+    const sort = sortKeys.length ? ' ORDER BY ' + sortKeys.map((k) => "`" + k + "` " + (sortObj[k] ? 'DESC' : 'ASC')).join(',') : '';
+    return this.query('SELECT * FROM ' + this.table + ' WHERE ' + conditions + sort, values);
+  }
+
+  async sqlFindOne(obj:any, sortObj:any = null): Promise<T> {
+    const res = await this.sqlFind(obj, sortObj)
+    return res[0]
+  }
+
+  sqlFindLikeAny(obj:any): Promise<T[]> {
+    const keys:string[] = _.keys(obj);
+    return this.query('SELECT * FROM ' + this.table + ' WHERE ' + keys.map((k) => 'UPPER(`' + k + '`) like ?').join(' or '), keys.map((k) => obj[k].toUpperCase()))
+  }
+
+  async sqlRemoveWhere(obj:any): Promise<void> {
+    const keys:string[] = _.keys(obj);
+    await this.query('DELETE FROM ' + this.table + ' WHERE ' + keys.map((k) => '`' + k + '` = ?').join(' and '), keys.map((k) => obj[k]))
+  }
+
+  sqlExisting(entity:T): Promise<T> {
+    return this.getEntity(entity)
+  }
+
+  async saveEntity(entity:any): Promise<void> {
+    let toSave:any = entity;
+    if (this.beforeSaveHook) {
+      this.beforeSaveHook(toSave);
+    }
+    const existing = await this.getEntity(toSave);
+    if (existing) {
+      toSave = this.toRow(toSave);
+      const valorizations = this.fields.map((field) => '`' + field + '` = ?').join(', ');
+      const conditions = this.getPKFields().map((field) => '`' + field + '` = ?').join(' and ');
+      const setValues = this.fields.map((field) => toSave[field]);
+      const condValues = this.getPKFields().map((k) => toSave[k]);
+      await this.query('UPDATE ' + this.table + ' SET ' + valorizations + ' WHERE ' + conditions, setValues.concat(condValues));
+      return
+    }
+    await this.insert(toSave);
+  }
+
+  async insert(entity:T): Promise<void> {
+    const row = this.toRow(entity);
+    const values = this.fields.map((f) => row[f]);
+    await this.query(this.getInsertQuery(), values)
+  }
+
+  async getEntity(entity:any): Promise<T> {
+    const conditions = this.getPKFields().map((field) => '`' + field + '` = ?').join(' and ');
+    const params = this.toParams(entity, this.getPKFields());
+    return (await this.query('SELECT * FROM ' + this.table + ' WHERE ' + conditions, params))[0];
+  }
+
+  async deleteEntity(entity:T): Promise<void> {
+    const toSave = this.toRow(entity);
+    if (this.beforeSaveHook) {
+      this.beforeSaveHook(toSave);
+    }
+    const conditions = this.getPKFields().map((field) => '`' + field + '` = ?').join(' and ');
+    const condValues = this.getPKFields().map((k) => toSave[k]);
+    await this.query('DELETE FROM ' + this.table + ' WHERE ' + conditions, condValues)
+  }
+
+  exec(sql:string): Promise<void> {
+    try {
+      //console.warn(sql);
+      return this.driver.executeSql(sql);
+    } catch (e) {
+      //console.error('ERROR >> %s', sql);
+      throw e;
+    }
+  }
+
+  getInsertQuery(): string {
+    return "INSERT INTO " + this.table + " (" + this.fields.map(f => '`' + f + '`').join(',') + ") VALUES (" + "?,".repeat(this.fields.length - 1) + "?);"
+  }
+
+  getInsertHead(): string {
+    const valuesKeys = this.fields
+    return 'INSERT INTO ' + this.table + " (" + valuesKeys.map(f => '`' + f + '`').join(',') + ") VALUES ";
+  }
+
+  getInsertValue(toSave:T): string {
+    if (this.beforeSaveHook) {
+      this.beforeSaveHook(toSave);
+    }
+    const row = this.toRow(toSave);
+    const valuesKeys = this.fields
+    const values = valuesKeys.map((field) => this.escapeToSQLite(row[field]));
+    return "(" + values.join(',') + ")";
+  }
+
+  toInsertValues(entity:T): string {
+    const row = this.toRow(entity);
+    const values = this.fields.map((f) => row[f]);
+    const formatted = values.map((s:string) => this.escapeToSQLite(s))
+    return "(" + formatted.join(',') + ")";
+  }
+
+  /**
+   * Make a batch insert.
+   * @param records The records to insert as a batch.
+   */
+  async insertBatch(records:T[]): Promise<void> {
+    const queries = [];
+    if (records.length) {
+      const insert = this.getInsertHead();
+      const values = records.map((src) => this.getInsertValue(src));
+      queries.push(insert + '\n' + values.join(',\n') + ';');
+    }
+    if (queries.length) {
+      await this.exec(queries.join('\n'))
+    }
+  }
+
+  private toConditionsArray(obj:any): string[] {
+    return _.keys(obj).map((k:string) => {
+      if (obj[k].$lte !== undefined) {
+        return '`' + k + '` <= ?';
+      } else if (obj[k].$gte !== undefined) {
+        return '`' + k + '` >= ?';
+      } else if (obj[k].$gt !== undefined) {
+        return '`' + k + '` > ?';
+      }  else if (obj[k].$lt !== undefined) {
+        return '`' + k + '` < ?';
+      }  else if (obj[k].$null !== undefined) {
+        return '`' + k + '` IS ' + (!obj[k].$null ? 'NOT' : '') + ' NULL';
+      }  else if (obj[k].$contains !== undefined) {
+        return '`' + k + '` LIKE ?';
+      } else {
+        return '`' + k + '` = ?';
+      }
+    });
+  }
+
+  private toParams(obj:any, fields:string[] | null = null): any[] {
+    let params:any[] = [];
+    (fields || _.keys(obj)).forEach((f:string) => {
+      if (obj[f].$null === undefined) {
+        let pValue;
+        if      (obj[f].$lte  !== undefined)      { pValue = obj[f].$lte;  }
+        else if (obj[f].$gte  !== undefined)      { pValue = obj[f].$gte;  }
+        else if (obj[f].$gt   !== undefined)      { pValue = obj[f].$gt;   }
+        else if (obj[f].$lt   !== undefined)      { pValue = obj[f].$lt;   }
+        else if (obj[f].$null !== undefined)      { pValue = obj[f].$null; }
+        else if (obj[f].$contains !== undefined) { pValue = "%" + obj[f].$contains + "%"; }
+        else if (~this.bigintegers.indexOf(f) && typeof obj[f] !== "string") {
+          pValue = String(obj[f]);
+        } else {
+          pValue = obj[f];
+        }
+        params.push(pValue);
+      }
+    });
+    return params;
+  }
+
+  private escapeToSQLite(val:string): any {
+    if (typeof val == "boolean") {
+      // SQLite specific: true => 1, false => 0
+      if (val !== null && val !== undefined) {
+        return val ? 1 : 0;
+      } else {
+        return null;
+      }
+    }
+    else if (typeof val == "string") {
+      return "'" + val.replace(/'/g, "\\'") + "'";
+    }
+    else if (val === undefined) {
+      return "null";
+    } else {
+      return JSON.stringify(val);
+    }
+  }
+
+  private getPKFields(): string[] {
+    return this.pkFields
+  }
+
+  private toEntity(row:any): T {
+    for (const arr of this.arrays) {
+      row[arr] = row[arr] ? JSON.parse(row[arr]) : [];
+    }
+    // Big integers are stored as strings to avoid data loss
+    for (const bigint of this.bigintegers) {
+      if (row[bigint] !== null && row[bigint] !== undefined) {
+        row[bigint] = parseInt(row[bigint]);
+      }
+    }
+    // Booleans
+    for (const f of this.booleans) {
+      row[f] = row[f] !== null ? Boolean(row[f]) : null;
+    }
+    // Transient
+    for (const f of (this.transientFields || [])) {
+      row[f] = row[f];
+    }
+    return row;
+  }
+
+  private toRow(entity:any): any {
+    let row:any = {};
+    for (const f of this.fields) {
+      row[f] = entity[f]
+    }
+    for (const arr of this.arrays) {
+      row[arr] = JSON.stringify(row[arr] || []);
+    }
+    // Big integers are stored as strings to avoid data loss
+    for (const bigint of this.bigintegers) {
+      if (entity[bigint] === null || entity[bigint] === undefined) {
+        row[bigint] = null;
+      } else {
+        row[bigint] = String(entity[bigint]);
+      }
+    }
+    return row;
+  }
+}
diff --git a/app/lib/dal/sqliteDAL/BlockDAL.js b/app/lib/dal/sqliteDAL/BlockDAL.js
deleted file mode 100644
index dce074db5..000000000
--- a/app/lib/dal/sqliteDAL/BlockDAL.js
+++ /dev/null
@@ -1,158 +0,0 @@
-/**
- * Created by cgeek on 22/08/15.
- */
-
-const Q = require('q');
-const co = require('co');
-const constants = require('../../constants');
-const AbstractSQLite = require('./AbstractSQLite');
-
-module.exports = BlockDAL;
-
-const IS_FORK = true;
-const IS_NOT_FORK = false;
-
-function BlockDAL(driver) {
-
-  "use strict";
-
-  AbstractSQLite.call(this, driver);
-
-  let current = null;
-  let that = this;
-
-  this.table = 'block';
-  this.fields = ['fork', 'hash', 'inner_hash', 'signature', 'currency', 'issuer', 'issuersCount', 'issuersFrame', 'issuersFrameVar', 'parameters', 'previousHash', 'previousIssuer', 'version', 'membersCount', 'monetaryMass', 'UDTime', 'medianTime', 'dividend', 'unitbase', 'time', 'powMin', 'number', 'nonce', 'transactions', 'certifications', 'identities', 'joiners', 'actives', 'leavers', 'revoked', 'excluded', 'len'];
-  this.arrays = ['identities','certifications','actives','revoked','excluded','leavers','joiners','transactions'];
-  this.bigintegers = ['monetaryMass'];
-  this.booleans = ['wrong'];
-  this.pkFields = ['number','hash'];
-
-  this.init = () => co(function *() {
-    return that.exec('BEGIN;' +
-      'CREATE TABLE IF NOT EXISTS ' + that.table + ' (' +
-      'fork BOOLEAN NOT NULL,' +
-      'hash VARCHAR(64) NOT NULL,' +
-      'inner_hash VARCHAR(64) NOT NULL,' +
-      'signature VARCHAR(100) NOT NULL,' +
-      'currency VARCHAR(50) NOT NULL,' +
-      'issuer VARCHAR(50) NOT NULL,' +
-      'parameters VARCHAR(255),' +
-      'previousHash VARCHAR(64),' +
-      'previousIssuer VARCHAR(50),' +
-      'version INTEGER NOT NULL,' +
-      'membersCount INTEGER NOT NULL,' +
-      'monetaryMass VARCHAR(100) DEFAULT \'0\',' +
-      'UDTime DATETIME,' +
-      'medianTime DATETIME NOT NULL,' +
-      'dividend INTEGER DEFAULT \'0\',' +
-      'unitbase INTEGER NULL,' +
-      'time DATETIME NOT NULL,' +
-      'powMin INTEGER NOT NULL,' +
-      'number INTEGER NOT NULL,' +
-      'nonce INTEGER NOT NULL,' +
-      'transactions TEXT,' +
-      'certifications TEXT,' +
-      'identities TEXT,' +
-      'joiners TEXT,' +
-      'actives TEXT,' +
-      'leavers TEXT,' +
-      'revoked TEXT,' +
-      'excluded TEXT,' +
-      'created DATETIME DEFAULT NULL,' +
-      'updated DATETIME DEFAULT NULL,' +
-      'PRIMARY KEY (number,hash)' +
-      ');' +
-      'CREATE INDEX IF NOT EXISTS idx_block_hash ON block (hash);' +
-      'CREATE INDEX IF NOT EXISTS idx_block_fork ON block (fork);' +
-      'COMMIT;', []);
-  });
-
-  this.cleanCache = () => current = null;
-
-  /**
-   * Periodically cleans the current block cache.
-   * It seems the cache is not always correct and may stuck the node, so it is preferable to reset it periodically.
-   */
-  setInterval(this.cleanCache, constants.CURRENT_BLOCK_CACHE_DURATION);
-
-  this.getCurrent = () => co(function *() {
-    if (!current) {
-      current = (yield that.query('SELECT * FROM block WHERE NOT fork ORDER BY number DESC LIMIT 1'))[0];
-    }
-    return Q(current);
-  });
-
-  this.getBlock = (number) => co(function *() {
-    return (yield that.query('SELECT * FROM block WHERE number = ? and NOT fork', [parseInt(number)]))[0];
-  });
-
-  this.getAbsoluteBlock = (number, hash) => co(function *() {
-    return (yield that.query('SELECT * FROM block WHERE number = ? and hash = ?', [parseInt(number), hash]))[0];
-  });
-
-  this.getBlocks = (start, end) => {
-    return that.query('SELECT * FROM block WHERE number BETWEEN ? and ? and NOT fork ORDER BY number ASC', [start, end]);
-  };
-
-  this.lastBlockWithDividend = () => co(function *() {
-    return (yield that.query('SELECT * FROM block WHERE dividend > 0 and NOT fork ORDER BY number DESC LIMIT 1'))[0];
-  });
-
-  this.lastBlockOfIssuer = (issuer) => co(function *() {
-    return (yield that.query('SELECT * FROM block WHERE issuer = ? and NOT fork ORDER BY number DESC LIMIT 1', [issuer]))[0];
-  });
-
-  this.getCountOfBlocksIssuedBy = (issuer) => co(function *() {
-    let res = yield that.query('SELECT COUNT(*) as quantity FROM block WHERE issuer = ? and NOT fork', [issuer]);
-    return res[0].quantity;
-  });
-
-  this.getForkBlocks = () => {
-    return that.query('SELECT * FROM block WHERE fork ORDER BY number');
-  };
-
-  this.getDividendBlocks = () => {
-    return that.query('SELECT * FROM block WHERE dividend IS NOT NULL ORDER BY number');
-  };
-
-  this.saveBunch = (blocks) => co(function *() {
-    let queries = "INSERT INTO block (" + that.fields.join(',') + ") VALUES ";
-    for (let i = 0, len = blocks.length; i < len; i++) {
-      let block = blocks[i];
-      queries += that.toInsertValues(block);
-      if (i + 1 < len) {
-        queries += ",\n";
-      }
-    }
-    yield that.exec(queries);
-    that.cleanCache();
-  });
-
-  this.saveBlock = (block) => co(function *() {
-    let saved = yield saveBlockAs(block, IS_NOT_FORK);
-    if (!current || current.number < block.number) {
-      current = block;
-    }
-    return saved;
-  });
-
-  this.saveSideBlock = (block) =>
-    saveBlockAs(block, IS_FORK);
-
-  function saveBlockAs(block, fork) {
-    return co(function *() {
-      block.fork = fork;
-      return yield that.saveEntity(block);
-    });
-  }
-
-  this.setSideBlock = (number, previousBlock) => co(function *() {
-    yield that.query('UPDATE block SET fork = ? WHERE number = ?', [true, number]);
-    current = previousBlock;
-  });
-
-  this.getNextForkBlocks = (number, hash) => {
-    return that.query('SELECT * FROM block WHERE fork AND number = ? AND previousHash like ? ORDER BY number', [number + 1, hash]);
-  };
-}
diff --git a/app/lib/dal/sqliteDAL/BlockDAL.ts b/app/lib/dal/sqliteDAL/BlockDAL.ts
new file mode 100644
index 000000000..35b38d241
--- /dev/null
+++ b/app/lib/dal/sqliteDAL/BlockDAL.ts
@@ -0,0 +1,193 @@
+import {AbstractSQLite} from "./AbstractSQLite";
+import {SQLiteDriver} from "../drivers/SQLiteDriver";
+const Q = require('q');
+const constants = require('../../constants');
+
+const IS_FORK = true;
+const IS_NOT_FORK = false;
+
+export interface DBBlock {
+  fork: boolean
+  hash: string
+  inner_hash: string
+  signature: string
+  currency: string
+  issuer: string
+  parameters: string
+  previousHash: string
+  previousIssuer: string
+  version: string
+  membersCount: string
+  monetaryMass: string
+  UDTime: string
+  medianTime: string
+  dividend: string
+  unitbase: string
+  time: string
+  powMin: string
+  number: string
+  nonce: string
+  transactions: string
+  certifications: string
+  identities: string
+  joiners: string
+  actives: string
+  leavers: string
+  revoked: string
+  excluded: string
+  created: string
+  updated: string
+}
+
+export class BlockDAL extends AbstractSQLite<DBBlock> {
+
+  private current: any
+
+  constructor(driver:SQLiteDriver) {
+    super(
+      driver,
+      'block',
+      // PK fields
+      ['number','hash'],
+      // Fields
+      ['fork', 'hash', 'inner_hash', 'signature', 'currency', 'issuer', 'issuersCount', 'issuersFrame', 'issuersFrameVar', 'parameters', 'previousHash', 'previousIssuer', 'version', 'membersCount', 'monetaryMass', 'UDTime', 'medianTime', 'dividend', 'unitbase', 'time', 'powMin', 'number', 'nonce', 'transactions', 'certifications', 'identities', 'joiners', 'actives', 'leavers', 'revoked', 'excluded', 'len'],
+      // Arrays
+      ['identities','certifications','actives','revoked','excluded','leavers','joiners','transactions'],
+      // Booleans
+      ['wrong'],
+      // BigIntegers
+      ['monetaryMass'],
+      // Transient
+      []
+    )
+
+    /**
+     * Periodically cleans the current block cache.
+     * It seems the cache is not always correct and may stuck the node, so it is preferable to reset it periodically.
+     */
+    setInterval(this.cleanCache, constants.CURRENT_BLOCK_CACHE_DURATION);
+  }
+
+  async init() {
+    await this.exec('BEGIN;' +
+      'CREATE TABLE IF NOT EXISTS ' + this.table + ' (' +
+      'fork BOOLEAN NOT NULL,' +
+      'hash VARCHAR(64) NOT NULL,' +
+      'inner_hash VARCHAR(64) NOT NULL,' +
+      'signature VARCHAR(100) NOT NULL,' +
+      'currency VARCHAR(50) NOT NULL,' +
+      'issuer VARCHAR(50) NOT NULL,' +
+      'parameters VARCHAR(255),' +
+      'previousHash VARCHAR(64),' +
+      'previousIssuer VARCHAR(50),' +
+      'version INTEGER NOT NULL,' +
+      'membersCount INTEGER NOT NULL,' +
+      'monetaryMass VARCHAR(100) DEFAULT \'0\',' +
+      'UDTime DATETIME,' +
+      'medianTime DATETIME NOT NULL,' +
+      'dividend INTEGER DEFAULT \'0\',' +
+      'unitbase INTEGER NULL,' +
+      'time DATETIME NOT NULL,' +
+      'powMin INTEGER NOT NULL,' +
+      'number INTEGER NOT NULL,' +
+      'nonce INTEGER NOT NULL,' +
+      'transactions TEXT,' +
+      'certifications TEXT,' +
+      'identities TEXT,' +
+      'joiners TEXT,' +
+      'actives TEXT,' +
+      'leavers TEXT,' +
+      'revoked TEXT,' +
+      'excluded TEXT,' +
+      'created DATETIME DEFAULT NULL,' +
+      'updated DATETIME DEFAULT NULL,' +
+      'PRIMARY KEY (number,hash)' +
+      ');' +
+      'CREATE INDEX IF NOT EXISTS idx_block_hash ON block (hash);' +
+      'CREATE INDEX IF NOT EXISTS idx_block_fork ON block (fork);' +
+      'COMMIT;')
+  }
+
+  cleanCache() {
+    this.current = null
+  }
+
+  async getCurrent() {
+    if (!this.current) {
+      this.current = (await this.query('SELECT * FROM block WHERE NOT fork ORDER BY number DESC LIMIT 1'))[0];
+    }
+    return Q(this.current);
+  }
+
+  async getBlock(number:string | number) {
+    return (await this.query('SELECT * FROM block WHERE number = ? and NOT fork', [parseInt(String(number))]))[0];
+  }
+
+  async getAbsoluteBlock(number:number, hash:string) {
+    return (await this.query('SELECT * FROM block WHERE number = ? and hash = ?', [number, hash]))[0];
+  }
+
+  getBlocks(start:number, end:number) {
+    return this.query('SELECT * FROM block WHERE number BETWEEN ? and ? and NOT fork ORDER BY number ASC', [start, end]);
+  }
+
+  async lastBlockWithDividend() {
+    return (await this.query('SELECT * FROM block WHERE dividend > 0 and NOT fork ORDER BY number DESC LIMIT 1'))[0];
+  }
+
+  async lastBlockOfIssuer(issuer:string) {
+    return (await this.query('SELECT * FROM block WHERE issuer = ? and NOT fork ORDER BY number DESC LIMIT 1', [issuer]))[0]
+  }
+
+  async getCountOfBlocksIssuedBy(issuer:string) {
+    let res: any = await this.query('SELECT COUNT(*) as quantity FROM block WHERE issuer = ? and NOT fork', [issuer]);
+    return res[0].quantity;
+  }
+
+  getForkBlocks() {
+    return this.query('SELECT * FROM block WHERE fork ORDER BY number');
+  }
+
+  getDividendBlocks() {
+    return this.query('SELECT * FROM block WHERE dividend IS NOT NULL ORDER BY number');
+  }
+
+  async saveBunch(blocks:DBBlock[]) {
+    let queries = "INSERT INTO block (" + this.fields.join(',') + ") VALUES ";
+    for (let i = 0, len = blocks.length; i < len; i++) {
+      let block = blocks[i];
+      queries += this.toInsertValues(block);
+      if (i + 1 < len) {
+        queries += ",\n";
+      }
+    }
+    await this.exec(queries);
+    this.cleanCache();
+  }
+
+  async saveBlock(block:DBBlock) {
+    let saved = await this.saveBlockAs(block, IS_NOT_FORK);
+    if (!this.current || this.current.number < block.number) {
+      this.current = block;
+    }
+    return saved;
+  }
+
+  saveSideBlock(block:DBBlock) {
+    return this.saveBlockAs(block, IS_FORK)
+  }
+
+  private async saveBlockAs(block:DBBlock, fork:boolean) {
+    block.fork = fork;
+    return await this.saveEntity(block);
+  }
+
+  async setSideBlock(number:number, previousBlock:DBBlock) {
+    await this.query('UPDATE block SET fork = ? WHERE number = ?', [true, number]);
+    this.current = previousBlock;
+  }
+
+  getNextForkBlocks(number:number, hash:string) {
+    return this.query('SELECT * FROM block WHERE fork AND number = ? AND previousHash like ? ORDER BY number', [number + 1, hash]);
+  }
+}
diff --git a/app/lib/dal/sqliteDAL/CertDAL.js b/app/lib/dal/sqliteDAL/CertDAL.js
deleted file mode 100644
index 7a2c773db..000000000
--- a/app/lib/dal/sqliteDAL/CertDAL.js
+++ /dev/null
@@ -1,113 +0,0 @@
-/**
- * Created by cgeek on 22/08/15.
- */
-
-const Q = require('q');
-const co = require('co');
-const AbstractSQLite = require('./AbstractSQLite');
-const constants = require('../../constants');
-const SandBox = require('./SandBox');
-
-module.exports = CertDAL;
-
-function CertDAL(driver) {
-
-  "use strict";
-
-  AbstractSQLite.call(this, driver);
-
-  const that = this;
-
-  this.table = 'cert';
-  this.fields = [
-    'linked',
-    'written',
-    'written_block',
-    'written_hash',
-    'sig',
-    'block_number',
-    'block_hash',
-    'target',
-    'to',
-    'from',
-    'block',
-    'expired',
-    'expires_on'
-  ];
-  this.arrays = [];
-  this.booleans = ['linked', 'written'];
-  this.pkFields = ['from','target','sig'];
-  this.translated = {};
-
-  this.init = () => co(function *() {
-    return that.exec('BEGIN;' +
-      'CREATE TABLE IF NOT EXISTS ' + that.table + ' (' +
-      '`from` VARCHAR(50) NOT NULL,' +
-      '`to` VARCHAR(50) NOT NULL,' +
-      'target CHAR(64) NOT NULL,' +
-      'sig VARCHAR(100) NOT NULL,' +
-      'block_number INTEGER NOT NULL,' +
-      'block_hash VARCHAR(64),' +
-      'block INTEGER NOT NULL,' +
-      'linked BOOLEAN NOT NULL,' +
-      'written BOOLEAN NOT NULL,' +
-      'written_block INTEGER,' +
-      'written_hash VARCHAR(64),' +
-      'expires_on INTEGER NULL,' +
-      'PRIMARY KEY (`from`, target, sig, written_block)' +
-      ');' +
-      'CREATE INDEX IF NOT EXISTS idx_cert_from ON cert (`from`);' +
-      'CREATE INDEX IF NOT EXISTS idx_cert_target ON cert (target);' +
-      'CREATE INDEX IF NOT EXISTS idx_cert_linked ON cert (linked);' +
-      'COMMIT;', []);
-  });
-
-  this.beforeSaveHook = function(entity) {
-    entity.written = entity.written || !!(entity.written_hash);
-  };
-
-  this.getToTarget = (hash) => this.sqlFind({
-    target: hash
-  });
-
-  this.getFromPubkeyCerts = (pubkey) => this.sqlFind({
-    from: pubkey
-  });
-
-  this.getNotLinked = () => this.sqlFind({
-    linked: false
-  });
-
-  this.getNotLinkedToTarget = (hash) => this.sqlFind({
-    target: hash,
-    linked: false
-  });
-
-  this.saveNewCertification = (cert) => this.saveEntity(cert);
-
-  this.existsGivenCert = (cert) => Q(this.sqlExisting(cert));
-
-  this.deleteCert = (cert) => this.deleteEntity(cert);
-
-  this.trimExpiredCerts = (medianTime) => this.exec('DELETE FROM ' + this.table + ' WHERE expires_on IS NULL OR expires_on < ' + medianTime);
-
-  /**************************
-   * SANDBOX STUFF
-   */
-
-  this.getSandboxForKey = (pub) => {
-    const getRecorded = () => that.query('SELECT * FROM cert WHERE `from` = ? ORDER BY block_number ASC LIMIT ' + constants.SANDBOX_SIZE_CERTIFICATIONS, [pub])
-    const compare = (compared, reference) => {
-      if (compared.block_number < reference.block_number) {
-        return -1
-      }
-      else if (compared.block_number > reference.block_number) {
-        return 1
-      }
-      else {
-        return 0
-      }
-    }
-    return new SandBox(constants.SANDBOX_SIZE_CERTIFICATIONS, getRecorded, compare)
-  }
-}
diff --git a/app/lib/dal/sqliteDAL/CertDAL.ts b/app/lib/dal/sqliteDAL/CertDAL.ts
new file mode 100644
index 000000000..39e324471
--- /dev/null
+++ b/app/lib/dal/sqliteDAL/CertDAL.ts
@@ -0,0 +1,144 @@
+import {SQLiteDriver} from "../drivers/SQLiteDriver";
+import {AbstractSQLite} from "./AbstractSQLite";
+import {SandBox} from "./SandBox";
+
+const constants = require('../../constants');
+
+export interface DBCert {
+  linked:boolean
+  written:boolean
+  written_block:null
+  written_hash:null
+  sig:string
+  block_number:number
+  block_hash:string
+  target:string
+  to:string
+  from:string
+  block:number
+  expired: boolean | null
+  expires_on: number
+}
+
+export class CertDAL extends AbstractSQLite<DBCert> {
+
+  constructor(driver:SQLiteDriver) {
+    super(
+      driver,
+      'cert',
+      // PK fields
+      ['from','target','sig'],
+      // Fields
+      [
+        'linked',
+        'written',
+        'written_block',
+        'written_hash',
+        'sig',
+        'block_number',
+        'block_hash',
+        'target',
+        'to',
+        'from',
+        'block',
+        'expired',
+        'expires_on'
+      ],
+      // Arrays
+      [],
+      // Booleans
+      ['linked', 'written'],
+      // BigIntegers
+      [],
+      // Transient
+      [],
+      (entity:DBCert) => {
+        entity.written = entity.written || !!(entity.written_hash)
+      }
+    )
+  }
+
+  async init() {
+    await this.exec('BEGIN;' +
+      'CREATE TABLE IF NOT EXISTS ' + this.table + ' (' +
+      '`from` VARCHAR(50) NOT NULL,' +
+      '`to` VARCHAR(50) NOT NULL,' +
+      'target CHAR(64) NOT NULL,' +
+      'sig VARCHAR(100) NOT NULL,' +
+      'block_number INTEGER NOT NULL,' +
+      'block_hash VARCHAR(64),' +
+      'block INTEGER NOT NULL,' +
+      'linked BOOLEAN NOT NULL,' +
+      'written BOOLEAN NOT NULL,' +
+      'written_block INTEGER,' +
+      'written_hash VARCHAR(64),' +
+      'expires_on INTEGER NULL,' +
+      'PRIMARY KEY (`from`, target, sig, written_block)' +
+      ');' +
+      'CREATE INDEX IF NOT EXISTS idx_cert_from ON cert (`from`);' +
+      'CREATE INDEX IF NOT EXISTS idx_cert_target ON cert (target);' +
+      'CREATE INDEX IF NOT EXISTS idx_cert_linked ON cert (linked);' +
+      'COMMIT;')
+  }
+
+  getToTarget(hash:string) {
+    return this.sqlFind({
+      target: hash
+    })
+  }
+
+  getFromPubkeyCerts(pubkey:string) {
+    return this.sqlFind({
+      from: pubkey
+    })
+  }
+
+  getNotLinked() {
+    return this.sqlFind({
+      linked: false
+    })
+  }
+
+  getNotLinkedToTarget(hash:string) {
+    return this.sqlFind({
+      target: hash,
+      linked: false
+    })
+  }
+
+  saveNewCertification(cert:DBCert) {
+    return this.saveEntity(cert)
+  }
+
+  existsGivenCert(cert:DBCert) {
+    return this.sqlExisting(cert)
+  }
+
+  deleteCert(cert:DBCert) {
+    return this.deleteEntity(cert)
+  }
+
+  async trimExpiredCerts(medianTime:number) {
+    await this.exec('DELETE FROM ' + this.table + ' WHERE expires_on IS NULL OR expires_on < ' + medianTime)
+  }
+
+  /**************************
+   * SANDBOX STUFF
+   */
+
+  getSandboxForKey = (pub:string) => {
+    const getRecorded = () => this.query('SELECT * FROM cert WHERE `from` = ? ORDER BY block_number ASC LIMIT ' + constants.SANDBOX_SIZE_CERTIFICATIONS, [pub])
+    const compare = (compared:DBCert, reference:DBCert) => {
+      if (compared.block_number < reference.block_number) {
+        return -1
+      }
+      else if (compared.block_number > reference.block_number) {
+        return 1
+      }
+      else {
+        return 0
+      }
+    }
+    return new SandBox(constants.SANDBOX_SIZE_CERTIFICATIONS, getRecorded, compare)
+  }
+}
diff --git a/app/lib/dal/sqliteDAL/IdentityDAL.js b/app/lib/dal/sqliteDAL/IdentityDAL.js
deleted file mode 100644
index a0562427e..000000000
--- a/app/lib/dal/sqliteDAL/IdentityDAL.js
+++ /dev/null
@@ -1,146 +0,0 @@
-/**
- * Created by cgeek on 22/08/15.
- */
-
-const co = require('co');
-const constants = require('../../constants');
-const AbstractSQLite = require('./AbstractSQLite');
-const SandBox = require('./SandBox');
-
-module.exports = IdentityDAL;
-
-function IdentityDAL(driver) {
-
-  "use strict";
-
-  AbstractSQLite.call(this, driver);
-
-  const that = this;
-
-  this.table = 'idty';
-  this.fields = [
-    'revoked',
-    'revoked_on',
-    'revocation_sig',
-    'currentMSN',
-    'currentINN',
-    'buid',
-    'member',
-    'kick',
-    'leaving',
-    'wasMember',
-    'pubkey',
-    'uid',
-    'sig',
-    'hash',
-    'written',
-    'wotb_id',
-    'expired',
-    'expires_on',
-    'removed'
-  ];
-  this.arrays = [];
-  this.booleans = ['revoked', 'member', 'kick', 'leaving', 'wasMember', 'written', 'removed'];
-  this.pkFields = ['pubkey', 'uid', 'hash'];
-  this.transientFields = ['certsCount', 'ref_block'];
-  this.translated = {};
-
-  this.init = () => co(function *() {
-    return that.exec('BEGIN;' +
-      'CREATE TABLE IF NOT EXISTS ' + that.table + ' (' +
-      'revoked BOOLEAN NOT NULL,' +
-      'currentMSN INTEGER NULL,' +
-      'currentINN INTEGER NULL,' +
-      'buid VARCHAR(100) NOT NULL,' +
-      'member BOOLEAN NOT NULL,' +
-      'kick BOOLEAN NOT NULL,' +
-      'leaving BOOLEAN NULL,' +
-      'wasMember BOOLEAN NOT NULL,' +
-      'pubkey VARCHAR(50) NOT NULL,' +
-      'uid VARCHAR(255) NOT NULL,' +
-      'sig VARCHAR(100) NOT NULL,' +
-      'revocation_sig VARCHAR(100) NULL,' +
-      'hash VARCHAR(64) NOT NULL,' +
-      'written BOOLEAN NULL,' +
-      'wotb_id INTEGER NULL,' +
-      'expires_on INTEGER NULL,' +
-      'PRIMARY KEY (pubkey,uid,hash)' +
-      ');' +
-      'CREATE INDEX IF NOT EXISTS idx_idty_pubkey ON idty (pubkey);' +
-      'CREATE INDEX IF NOT EXISTS idx_idty_uid ON idty (uid);' +
-      'CREATE INDEX IF NOT EXISTS idx_idty_kick ON idty (kick);' +
-      'CREATE INDEX IF NOT EXISTS idx_idty_member ON idty (member);' +
-      'CREATE INDEX IF NOT EXISTS idx_idty_wasMember ON idty (wasMember);' +
-      'CREATE INDEX IF NOT EXISTS idx_idty_hash ON idty (hash);' +
-      'CREATE INDEX IF NOT EXISTS idx_idty_written ON idty (written);' +
-      'CREATE INDEX IF NOT EXISTS idx_idty_currentMSN ON idty (currentMSN);' +
-      'CREATE INDEX IF NOT EXISTS idx_idty_currentINN ON idty (currentINN);' +
-      'COMMIT;', []);
-  });
-
-  this.revokeIdentity = (pubkey) => this.exec('DELETE FROM ' + this.table + ' WHERE pubkey = \'' + pubkey + '\'');
-
-  this.removeUnWrittenWithPubkey = (pubkey) => this.sqlRemoveWhere({
-    pubkey: pubkey,
-    written: false
-  });
-
-  this.removeUnWrittenWithUID = (uid) => this.sqlRemoveWhere({
-    uid: uid,
-    written: false
-  });
-
-  this.getByHash = (hash) => this.sqlFindOne({
-    hash: hash
-  });
-
-  this.saveIdentity = (idty) =>
-    this.saveEntity(idty);
-
-  this.deleteByHash = (hash) => this.exec('UPDATE ' + this.table + ' SET removed = 1 where hash = \'' + hash + '\'');
-
-  this.getToRevoke = () => that.sqlFind({
-    revocation_sig: { $null: false },
-    revoked: false,
-    wasMember: true
-  });
-
-  this.getPendingIdentities = () => that.sqlFind({
-    revocation_sig: { $null: false },
-    revoked: false
-  });
-
-  this.searchThoseMatching = (search) => that.sqlFindLikeAny({
-    pubkey: "%" + search + "%",
-    uid: "%" + search + "%"
-  });
-
-  this.trimExpiredIdentities = (medianTime) => this.exec('DELETE FROM ' + this.table + ' WHERE (expires_on IS NULL AND revocation_sig IS NULL) OR expires_on < ' + medianTime);
-
-  /**************************
-   * SANDBOX STUFF
-   */
-
-  this.getSandboxIdentities = () => that.query('SELECT * FROM sandbox_idty LIMIT ' + (that.sandbox.maxSize), []);
-
-  this.sandbox = new SandBox(constants.SANDBOX_SIZE_IDENTITIES, this.getSandboxIdentities.bind(this), (compared, reference) => {
-    if (compared.certsCount < reference.certsCount) {
-      return -1;
-    }
-    else if (compared.certsCount > reference.certsCount) {
-      return 1;
-    }
-    else if (compared.ref_block < reference.ref_block) {
-      return -1;
-    }
-    else if (compared.ref_block > reference.ref_block) {
-      return 1;
-    }
-    else {
-      return 0;
-    }
-  });
-
-  this.getSandboxRoom = () => this.sandbox.getSandboxRoom();
-  this.setSandboxSize = (maxSize) => this.sandbox.maxSize = maxSize;
-}
diff --git a/app/lib/dal/sqliteDAL/IdentityDAL.ts b/app/lib/dal/sqliteDAL/IdentityDAL.ts
new file mode 100644
index 000000000..173d737f2
--- /dev/null
+++ b/app/lib/dal/sqliteDAL/IdentityDAL.ts
@@ -0,0 +1,192 @@
+import {AbstractSQLite} from "./AbstractSQLite";
+import {SQLiteDriver} from "../drivers/SQLiteDriver";
+import {SandBox} from "./SandBox";
+const constants = require('../../constants');
+
+export interface DBIdentity {
+  revoked: boolean
+  currentMSN: null
+  currentINN: null
+  buid: string
+  member: boolean
+  kick: boolean
+  leaving: boolean | null
+  wasMember: boolean
+  pubkey: string
+  uid: string
+  sig: string
+  revocation_sig: string | null
+  hash: string
+  written: boolean
+  wotb_id: number | null
+  expires_on: number,
+  certsCount: number,
+  ref_block: number
+}
+
+export class IdentityDAL extends AbstractSQLite<DBIdentity> {
+
+  constructor(driver:SQLiteDriver) {
+    super(
+      driver,
+      'idty',
+      // PK fields
+      ['pubkey', 'uid', 'hash'],
+      // Fields
+      [
+        'revoked',
+        'revoked_on',
+        'revocation_sig',
+        'currentMSN',
+        'currentINN',
+        'buid',
+        'member',
+        'kick',
+        'leaving',
+        'wasMember',
+        'pubkey',
+        'uid',
+        'sig',
+        'hash',
+        'written',
+        'wotb_id',
+        'expired',
+        'expires_on',
+        'removed'
+      ],
+      // Arrays
+      [],
+      // Booleans
+      ['revoked', 'member', 'kick', 'leaving', 'wasMember', 'written', 'removed'],
+      // BigIntegers
+      [],
+      // Transient
+      ['certsCount', 'ref_block']
+    )
+  }
+
+  async init() {
+    await this.exec('BEGIN;' +
+      'CREATE TABLE IF NOT EXISTS ' + this.table + ' (' +
+      'revoked BOOLEAN NOT NULL,' +
+      'currentMSN INTEGER NULL,' +
+      'currentINN INTEGER NULL,' +
+      'buid VARCHAR(100) NOT NULL,' +
+      'member BOOLEAN NOT NULL,' +
+      'kick BOOLEAN NOT NULL,' +
+      'leaving BOOLEAN NULL,' +
+      'wasMember BOOLEAN NOT NULL,' +
+      'pubkey VARCHAR(50) NOT NULL,' +
+      'uid VARCHAR(255) NOT NULL,' +
+      'sig VARCHAR(100) NOT NULL,' +
+      'revocation_sig VARCHAR(100) NULL,' +
+      'hash VARCHAR(64) NOT NULL,' +
+      'written BOOLEAN NULL,' +
+      'wotb_id INTEGER NULL,' +
+      'expires_on INTEGER NULL,' +
+      'PRIMARY KEY (pubkey,uid,hash)' +
+      ');' +
+      'CREATE INDEX IF NOT EXISTS idx_idty_pubkey ON idty (pubkey);' +
+      'CREATE INDEX IF NOT EXISTS idx_idty_uid ON idty (uid);' +
+      'CREATE INDEX IF NOT EXISTS idx_idty_kick ON idty (kick);' +
+      'CREATE INDEX IF NOT EXISTS idx_idty_member ON idty (member);' +
+      'CREATE INDEX IF NOT EXISTS idx_idty_wasMember ON idty (wasMember);' +
+      'CREATE INDEX IF NOT EXISTS idx_idty_hash ON idty (hash);' +
+      'CREATE INDEX IF NOT EXISTS idx_idty_written ON idty (written);' +
+      'CREATE INDEX IF NOT EXISTS idx_idty_currentMSN ON idty (currentMSN);' +
+      'CREATE INDEX IF NOT EXISTS idx_idty_currentINN ON idty (currentINN);' +
+      'COMMIT;')
+  }
+
+  revokeIdentity(pubkey:string) {
+    return this.exec('DELETE FROM ' + this.table + ' WHERE pubkey = \'' + pubkey + '\'')
+  }
+
+  removeUnWrittenWithPubkey(pubkey:string) {
+    return this.sqlRemoveWhere({
+      pubkey: pubkey,
+      written: false
+    })
+  }
+
+  removeUnWrittenWithUID(uid:string) {
+    return this.sqlRemoveWhere({
+      uid: uid,
+      written: false
+    })
+  }
+
+  getByHash(hash:string) {
+    return this.sqlFindOne({
+      hash: hash
+    })
+  }
+
+  saveIdentity(idty:DBIdentity) {
+    return this.saveEntity(idty)
+  }
+
+  async deleteByHash(hash:string) {
+    await this.exec('UPDATE ' + this.table + ' SET removed = 1 where hash = \'' + hash + '\'')
+  }
+
+  getToRevoke() {
+    return this.sqlFind({
+      revocation_sig: { $null: false },
+      revoked: false,
+      wasMember: true
+    })
+  }
+
+  getPendingIdentities() {
+    return this.sqlFind({
+      revocation_sig: { $null: false },
+      revoked: false
+    })
+  }
+
+  searchThoseMatching(search:string) {
+    return this.sqlFindLikeAny({
+      pubkey: "%" + search + "%",
+      uid: "%" + search + "%"
+    })
+  }
+
+  async trimExpiredIdentities(medianTime:number) {
+    await this.exec('DELETE FROM ' + this.table + ' WHERE (expires_on IS NULL AND revocation_sig IS NULL) OR expires_on < ' + medianTime)
+  }
+
+  /**************************
+   * SANDBOX STUFF
+   */
+
+  getSandboxIdentities() {
+    return this.query('SELECT * FROM sandbox_idty LIMIT ' + (this.sandbox.maxSize), [])
+  }
+
+  sandbox = new SandBox(constants.SANDBOX_SIZE_IDENTITIES, this.getSandboxIdentities.bind(this), (compared:DBIdentity, reference:DBIdentity) => {
+    if (compared.certsCount < reference.certsCount) {
+      return -1;
+    }
+    else if (compared.certsCount > reference.certsCount) {
+      return 1;
+    }
+    else if (compared.ref_block < reference.ref_block) {
+      return -1;
+    }
+    else if (compared.ref_block > reference.ref_block) {
+      return 1;
+    }
+    else {
+      return 0;
+    }
+  });
+
+  getSandboxRoom() {
+    return this.sandbox.getSandboxRoom()
+  }
+
+  setSandboxSize(maxSize:number) {
+    this.sandbox.maxSize = maxSize
+  }
+}
diff --git a/app/lib/dal/sqliteDAL/IndexDAL.js b/app/lib/dal/sqliteDAL/IndexDAL.js
deleted file mode 100644
index 55f089ddf..000000000
--- a/app/lib/dal/sqliteDAL/IndexDAL.js
+++ /dev/null
@@ -1,10 +0,0 @@
-"use strict";
-
-const AbstractSQLite = require('./AbstractSQLite')
-const AbstractIndex = require('./AbstractIndex')
-
-module.exports = function IndexDAL(driver) {
-
-  AbstractSQLite.call(this, driver);
-  AbstractIndex.call(this);
-}
diff --git a/app/lib/dal/sqliteDAL/MembershipDAL.js b/app/lib/dal/sqliteDAL/MembershipDAL.js
deleted file mode 100644
index e3f5564a7..000000000
--- a/app/lib/dal/sqliteDAL/MembershipDAL.js
+++ /dev/null
@@ -1,116 +0,0 @@
-/**
- * Created by cgeek on 22/08/15.
- */
-
-const co = require('co');
-const _ = require('underscore');
-const AbstractSQLite = require('./AbstractSQLite');
-const constants = require('../../constants');
-const SandBox = require('./SandBox');
-
-module.exports = MembershipDAL;
-
-function MembershipDAL(driver) {
-
-  "use strict";
-
-  AbstractSQLite.call(this, driver);
-
-  const that = this;
-
-  this.table = 'membership';
-  this.fields = [
-    'membership',
-    'issuer',
-    'number',
-    'blockNumber',
-    'blockHash',
-    'userid',
-    'certts',
-    'block',
-    'fpr',
-    'idtyHash',
-    'written',
-    'written_number',
-    'expires_on',
-    'signature',
-    'expired'
-  ];
-  this.arrays = [];
-  this.booleans = ['written'];
-  this.pkFields = ['issuer','signature'];
-  this.translated = {};
-
-  this.init = () => co(function *() {
-    return that.exec('BEGIN;' +
-      'CREATE TABLE IF NOT EXISTS membership (' +
-      'membership CHAR(2) NOT NULL,' +
-      'issuer VARCHAR(50) NOT NULL,' +
-      'number INTEGER NOT NULL,' +
-      'blockNumber INTEGER,' +
-      'blockHash VARCHAR(64) NOT NULL,' +
-      'userid VARCHAR(255) NOT NULL,' +
-      'certts VARCHAR(100) NOT NULL,' +
-      'block INTEGER,' +
-      'fpr VARCHAR(64),' +
-      'idtyHash VARCHAR(64),' +
-      'written BOOLEAN NOT NULL,' +
-      'written_number INTEGER,' +
-      'expires_on INTEGER NULL,' +
-      'signature VARCHAR(50),' +
-      'PRIMARY KEY (issuer,signature)' +
-      ');' +
-      'CREATE INDEX IF NOT EXISTS idx_mmembership_idtyHash ON membership (idtyHash);' +
-      'CREATE INDEX IF NOT EXISTS idx_mmembership_membership ON membership (membership);' +
-      'CREATE INDEX IF NOT EXISTS idx_mmembership_written ON membership (written);' +
-      'COMMIT;', []);
-  });
-
-  this.getMembershipsOfIssuer = (issuer) => this.sqlFind({
-    issuer: issuer
-  });
-
-  this.getPendingINOfTarget = (hash) => this.sqlFind({
-    idtyHash: hash,
-    membership: 'IN'
-  });
-
-  this.getPendingIN = () => this.sqlFind({
-    membership: 'IN'
-  });
-
-  this.getPendingOUT = () => this.sqlFind({
-    membership: 'OUT'
-  });
-
-  this.savePendingMembership = (ms) => {
-    ms.membership = ms.membership.toUpperCase();
-    ms.written = false;
-    return this.saveEntity(_.pick(ms, 'membership', 'issuer', 'number', 'blockNumber', 'blockHash', 'userid', 'certts', 'block', 'fpr', 'idtyHash', 'expires_on', 'written', 'written_number', 'signature'));
-  };
-
-  this.deleteMS = (ms) => this.deleteEntity(ms);
-
-  this.trimExpiredMemberships = (medianTime) => this.exec('DELETE FROM ' + this.table + ' WHERE expires_on IS NULL OR expires_on < ' + medianTime);
-
-  /**************************
-   * SANDBOX STUFF
-   */
-
-  this.getSandboxMemberships = () => that.query('SELECT * FROM sandbox_memberships LIMIT ' + (that.sandbox.maxSize), []);
-
-  this.sandbox = new SandBox(constants.SANDBOX_SIZE_MEMBERSHIPS, this.getSandboxMemberships.bind(this), (compared, reference) => {
-    if (compared.block_number < reference.block_number) {
-      return -1;
-    }
-    else if (compared.block_number > reference.block_number) {
-      return 1;
-    }
-    else {
-      return 0;
-    }
-  });
-
-  this.getSandboxRoom = () => this.sandbox.getSandboxRoom();
-  this.setSandboxSize = (maxSize) => this.sandbox.maxSize = maxSize;
-}
diff --git a/app/lib/dal/sqliteDAL/MembershipDAL.ts b/app/lib/dal/sqliteDAL/MembershipDAL.ts
new file mode 100644
index 000000000..61ce346e9
--- /dev/null
+++ b/app/lib/dal/sqliteDAL/MembershipDAL.ts
@@ -0,0 +1,154 @@
+import {SQLiteDriver} from "../drivers/SQLiteDriver";
+import {AbstractSQLite} from "./AbstractSQLite";
+import {SandBox} from "./SandBox";
+const _ = require('underscore');
+const constants = require('../../constants');
+
+export interface DBMembership {
+  membership: string
+  issuer: string
+  number: number
+  blockNumber: number
+  blockHash: string
+  userid: string
+  certts: string
+  block: string
+  fpr: string
+  idtyHash: string
+  written: boolean
+  written_number: number | null
+  expires_on: number
+  signature: string
+  expired: boolean | null,
+  block_number: number
+}
+
+export class MembershipDAL extends AbstractSQLite<DBMembership> {
+
+  constructor(driver:SQLiteDriver) {
+    super(
+      driver,
+      'membership',
+      // PK fields
+      ['issuer','signature'],
+      // Fields
+      [
+        'membership',
+        'issuer',
+        'number',
+        'blockNumber',
+        'blockHash',
+        'userid',
+        'certts',
+        'block',
+        'fpr',
+        'idtyHash',
+        'written',
+        'written_number',
+        'expires_on',
+        'signature',
+        'expired'
+      ],
+      // Arrays
+      [],
+      // Booleans
+      ['written'],
+      // BigIntegers
+      [],
+      // Transient
+      []
+    )
+  }
+
+  async init() {
+    await this.exec('BEGIN;' +
+      'CREATE TABLE IF NOT EXISTS membership (' +
+      'membership CHAR(2) NOT NULL,' +
+      'issuer VARCHAR(50) NOT NULL,' +
+      'number INTEGER NOT NULL,' +
+      'blockNumber INTEGER,' +
+      'blockHash VARCHAR(64) NOT NULL,' +
+      'userid VARCHAR(255) NOT NULL,' +
+      'certts VARCHAR(100) NOT NULL,' +
+      'block INTEGER,' +
+      'fpr VARCHAR(64),' +
+      'idtyHash VARCHAR(64),' +
+      'written BOOLEAN NOT NULL,' +
+      'written_number INTEGER,' +
+      'expires_on INTEGER NULL,' +
+      'signature VARCHAR(50),' +
+      'PRIMARY KEY (issuer,signature)' +
+      ');' +
+      'CREATE INDEX IF NOT EXISTS idx_mmembership_idtyHash ON membership (idtyHash);' +
+      'CREATE INDEX IF NOT EXISTS idx_mmembership_membership ON membership (membership);' +
+      'CREATE INDEX IF NOT EXISTS idx_mmembership_written ON membership (written);' +
+      'COMMIT;')
+  }
+
+  getMembershipsOfIssuer(issuer:string) {
+    return this.sqlFind({
+      issuer: issuer
+    })
+  }
+
+  getPendingINOfTarget(hash:string) {
+    return this.sqlFind({
+      idtyHash: hash,
+      membership: 'IN'
+    })
+  }
+
+  getPendingIN() {
+    return this.sqlFind({
+      membership: 'IN'
+    })
+  }
+
+  getPendingOUT() {
+    return this.sqlFind({
+      membership: 'OUT'
+    })
+  }
+
+  savePendingMembership(ms:DBMembership) {
+    ms.membership = ms.membership.toUpperCase();
+    ms.written = false;
+    return this.saveEntity(_.pick(ms, 'membership', 'issuer', 'number', 'blockNumber', 'blockHash', 'userid', 'certts', 'block', 'fpr', 'idtyHash', 'expires_on', 'written', 'written_number', 'signature'))
+  }
+
+  async deleteMS(ms:DBMembership) {
+    await this.deleteEntity(ms)
+  }
+
+  async trimExpiredMemberships(medianTime:number) {
+    await this.exec('DELETE FROM ' + this.table + ' WHERE expires_on IS NULL OR expires_on < ' + medianTime)
+  }
+
+  /**************************
+   * SANDBOX STUFF
+   */
+
+  getSandboxMemberships() {
+    return this.query('SELECT * FROM sandbox_memberships LIMIT ' + (this.sandbox.maxSize), [])
+  }
+
+  sandbox = new SandBox(constants.SANDBOX_SIZE_MEMBERSHIPS, this.getSandboxMemberships.bind(this), (compared:DBMembership, reference:DBMembership) => {
+    if (compared.block_number < reference.block_number) {
+      return -1;
+    }
+    else if (compared.block_number > reference.block_number) {
+      return 1;
+    }
+    else {
+      return 0;
+    }
+  });
+
+  getSandboxRoom() {
+    return this.sandbox.getSandboxRoom()
+  }
+
+  setSandboxSize(maxSize:number) {
+    this.sandbox.maxSize = maxSize
+  }
+}
diff --git a/app/lib/dal/sqliteDAL/MetaDAL.js b/app/lib/dal/sqliteDAL/MetaDAL.ts
similarity index 70%
rename from app/lib/dal/sqliteDAL/MetaDAL.js
rename to app/lib/dal/sqliteDAL/MetaDAL.ts
index 122e71c47..f19f58acf 100644
--- a/app/lib/dal/sqliteDAL/MetaDAL.js
+++ b/app/lib/dal/sqliteDAL/MetaDAL.ts
@@ -1,36 +1,54 @@
-"use strict";
-
-/**
- * Created by cgeek on 22/08/15.
- */
-
-const co = require('co');
+import {AbstractSQLite} from "./AbstractSQLite";
+import {SQLiteDriver} from "../drivers/SQLiteDriver";
+import {ConfDTO} from "../../dto/ConfDTO";
+import {SindexEntry} from "../../indexer";
+import {hashf} from "../../common";
+import {TransactionDTO} from "../../dto/TransactionDTO";
+import {BlockDAL} from "./BlockDAL";
+import {IdentityDAL} from "./IdentityDAL";
+import {SIndexDAL} from "./index/SIndexDAL";
+import {WalletDAL} from "./WalletDAL";
+import {MIndexDAL} from "./index/MIndexDAL";
+
+const _ = require('underscore')
 const logger = require('../../logger')('metaDAL');
-const AbstractSQLite = require('./AbstractSQLite');
 const common = require('duniter-common');
-const hashf = require('duniter-common').hashf;
 const rawer = require('duniter-common').rawer;
 const constants = require('./../../constants');
 
-module.exports = MetaDAL;
-
-function MetaDAL(driver) {
-
-  AbstractSQLite.call(this, driver);
-
-  const that = this;
+export interface DBMeta {
+  id: number,
+  version: number
+}
 
-  this.table = 'meta';
-  this.fields = [
-    'id',
-    'version'
-  ];
-  this.arrays = [];
-  this.booleans = [];
-  this.pkFields = ['version'];
-  this.translated = {};
+export class MetaDAL extends AbstractSQLite<DBMeta> {
+
+  driverCopy:SQLiteDriver
+
+  constructor(driver:SQLiteDriver) {
+    super(
+      driver,
+      'meta',
+      // PK fields
+      ['version'],
+      // Fields
+      [
+        'id',
+        'version'
+      ],
+      // Arrays
+      [],
+      // Booleans
+      [],
+      // BigIntegers
+      [],
+      // Transient
+      []
+    )
+    this.driverCopy = driver
+  }
 
-  const migrations = {
+  private migrations:any = {
 
     // Test
     0: 'BEGIN; COMMIT;',
@@ -50,16 +68,13 @@ function MetaDAL(driver) {
     2: 'BEGIN; ALTER TABLE txs ADD COLUMN received INTEGER NULL; COMMIT;',
 
     // Update wrong recipients field (was not filled in)
-    3: () => co(function*() {
-    }),
+    3: async () => {},
 
     // Migrates wrong unitbases
-    4: () => co(function*() {
-    }),
+    4: async () => {},
 
     // Migrates wrong monetary masses
-    5: () => co(function*() {
-    }),
+    5: async () => {},
 
     6: 'BEGIN; ALTER TABLE idty ADD COLUMN expired INTEGER NULL; COMMIT;',
     7: 'BEGIN; ALTER TABLE cert ADD COLUMN expired INTEGER NULL; COMMIT;',
@@ -74,11 +89,11 @@ function MetaDAL(driver) {
     'ALTER TABLE block ADD COLUMN issuersFrameVar INTEGER NULL;' +
     'ALTER TABLE block ADD COLUMN issuersCount INTEGER NULL;' +
     'COMMIT;',
-    12: () => co(function *() {
-      let blockDAL = new (require('./BlockDAL'))(driver);
-      yield blockDAL.exec('ALTER TABLE block ADD COLUMN len INTEGER NULL;');
-      yield blockDAL.exec('ALTER TABLE txs ADD COLUMN len INTEGER NULL;');
-    }),
+    12: async () => {
+      let blockDAL = new BlockDAL(this.driverCopy)
+      await blockDAL.exec('ALTER TABLE block ADD COLUMN len INTEGER NULL;');
+      await blockDAL.exec('ALTER TABLE txs ADD COLUMN len INTEGER NULL;');
+    },
     13: 'BEGIN; ALTER TABLE txs ADD COLUMN blockstampTime INTEGER NULL; COMMIT;',
     14: 'BEGIN; ' +
       
@@ -109,25 +124,24 @@ function MetaDAL(driver) {
       'ORDER BY block_number DESC;' +
     'COMMIT;',
 
-    15: () => co(function *() {
-      let idtyDAL = new (require('./IdentityDAL'))(driver);
-      yield idtyDAL.exec('ALTER TABLE idty ADD COLUMN revoked_on INTEGER NULL');
-    }),
+    15: async () => {
+      let idtyDAL = new IdentityDAL(this.driverCopy)
+      await idtyDAL.exec('ALTER TABLE idty ADD COLUMN revoked_on INTEGER NULL');
+    },
 
-    16: () => co(function *() {
-    }),
+    16: async () => {},
 
-    17: () => co(function *() {
-      let blockDAL = new (require('./BlockDAL'))(driver);
-      let sindexDAL = new (require('./index/SIndexDAL'))(driver);
-      const blocks = yield blockDAL.query('SELECT * FROM block WHERE NOT fork');
+    17: async () => {
+      let blockDAL = new BlockDAL(this.driverCopy)
+      let sindexDAL = new SIndexDAL(this.driverCopy)
+      const blocks = await blockDAL.query('SELECT * FROM block WHERE NOT fork');
       const Block = require('../../../lib/entity/block');
       const Identity = require('../../../lib/entity/identity');
-      const amountsPerKey = {};
+      const amountsPerKey:any = {};
       const members = [];
       for (const block of blocks) {
         const b = new Block(block);
-        const amountsInForBlockPerKey = {};
+        const amountsInForBlockPerKey:any = {};
         for (const idty of b.identities) {
           members.push(Identity.statics.fromInline(idty).pubkey);
         }
@@ -141,7 +155,7 @@ function MetaDAL(driver) {
         const txs = b.getTransactions();
         for (let i = 0; i < txs.length; i++) {
           const tx = txs[i];
-          tx.hash = hashf(rawer.getTransaction(b.transactions[i])).toUpperCase();
+          tx.hash = hashf(rawer.getTransaction(b.transactions[i]))
           for (const input of tx.inputs) {
             input.tx = tx.hash;
             input.block = b;
@@ -169,10 +183,10 @@ function MetaDAL(driver) {
         }
       }
       const keysToSee = Object.keys(amountsPerKey);
-      const sourcesMovements = [];
+      const sourcesMovements: SindexEntry[] = [];
       for (const key of keysToSee) {
-        const allCreates = {};
-        const allUpdates = {};
+        const allCreates: any = {};
+        const allUpdates: any = {};
         const amounts = amountsPerKey[key];
         let balance = 0;
         for (let j = 0; j < amounts.length; j++) {
@@ -210,17 +224,23 @@ function MetaDAL(driver) {
           }
         }
         let amountMissing = 0;
-        yield Object.values(allCreates).map((src) => co(function*() {
-          const exist = yield sindexDAL.getSource(src.identifier, src.pos);
+        await Promise.all(_.values(allCreates).map(async (src:any) => {
+          const exist = await sindexDAL.getSource(src.identifier, src.pos);
           if (!exist || exist.consumed) {
             amountMissing += src.amount;
             const block = src.block;
             sourcesMovements.push({
+              index: common.constants.I_INDEX,
               op: common.constants.IDX_CREATE,
               tx: src.tx,
               identifier: src.identifier,
               pos: src.pos,
+              unlock: null,
+              age: 0,
+              txObj: TransactionDTO.mock(),
+              created_on: null,
               written_on: [block.number, block.hash].join('-'),
+              writtenOn: block.number,
               written_time: block.medianTime,
               locktime: src.locktime,
               amount: src.amount,
@@ -229,17 +249,17 @@ function MetaDAL(driver) {
               consumed: false
             });
           }
-        }));
+        }))
         let amountNotDestroyed = 0;
-        yield Object.values(allUpdates).map((src) => co(function*() {
-          const exist = yield sindexDAL.getSource(src.identifier, src.pos);
+        await _.values(allUpdates).map(async (src:any) => {
+          const exist = await sindexDAL.getSource(src.identifier, src.pos);
           if (exist && !exist.consumed) {
             amountNotDestroyed += src.amount;
           }
-        }));
+        })
       }
-      yield sindexDAL.insertBatch(sourcesMovements);
-    }),
+      await sindexDAL.insertBatch(sourcesMovements);
+    },
 
     18: 'BEGIN;' +
       // Add a `massReeval` column
@@ -254,39 +274,39 @@ function MetaDAL(driver) {
     /**
      * Feeds the table of wallets with balances
      */
-    20: () => co(function*() {
-      let walletDAL = new (require('./WalletDAL'))(driver);
-      let sindexDAL = new (require('./index/SIndexDAL'))(driver);
-      const conditions = yield sindexDAL.query('SELECT DISTINCT(conditions) FROM s_index')
+    20: async () => {
+      let walletDAL = new WalletDAL(this.driverCopy)
+      let sindexDAL = new SIndexDAL(this.driverCopy)
+      const conditions = await sindexDAL.query('SELECT DISTINCT(conditions) FROM s_index')
       for (const row of conditions) {
         const wallet = {
           conditions: row.conditions,
           balance: 0
         }
-        const amountsRemaining = yield sindexDAL.getAvailableForConditions(row.conditions)
-        wallet.balance = amountsRemaining.reduce((sum, src) => sum + src.amount * Math.pow(10, src.base), 0)
-        yield walletDAL.saveWallet(wallet)
+        const amountsRemaining = await sindexDAL.getAvailableForConditions(row.conditions)
+        wallet.balance = amountsRemaining.reduce((sum:number, src:SindexEntry) => sum + src.amount * Math.pow(10, src.base), 0)
+        await walletDAL.saveWallet(wallet)
       }
-    }),
+    },
 
     /**
      * Feeds the m_index.chainable_on
      */
-    21: (conf) => co(function*() {
-      let blockDAL = new (require('./BlockDAL'))(driver);
-      let mindexDAL = new (require('./index/MIndexDAL'))(driver);
-      yield mindexDAL.exec('ALTER TABLE m_index ADD COLUMN chainable_on INTEGER NULL;')
-      const memberships = yield mindexDAL.query('SELECT * FROM m_index WHERE op = ?', [common.constants.IDX_CREATE])
+    21: async (conf:ConfDTO) => {
+      let blockDAL = new BlockDAL(this.driverCopy)
+      let mindexDAL = new MIndexDAL(this.driverCopy)
+      await mindexDAL.exec('ALTER TABLE m_index ADD COLUMN chainable_on INTEGER NULL;')
+      const memberships = await mindexDAL.query('SELECT * FROM m_index WHERE op = ?', [common.constants.IDX_CREATE])
       for (const ms of memberships) {
-        const reference = yield blockDAL.getBlock(parseInt(ms.written_on.split('-')[0]))
+        const reference = await blockDAL.getBlock(parseInt(ms.written_on.split('-')[0]))
         const updateQuery = 'UPDATE m_index SET chainable_on = ' + (reference.medianTime + conf.msPeriod) + ' WHERE pub = \'' + ms.pub + '\' AND op = \'CREATE\''
-        yield mindexDAL.exec(updateQuery)
+        await mindexDAL.exec(updateQuery)
       }
-    }),
+    },
 
     // Replay the wallet table feeding, because of a potential bug
-    22: function resetWallets() {
-      return migrations[20]()
+    22: () => {
+      return this.migrations[20]()
     },
 
     23: 'BEGIN;' +
@@ -306,64 +326,60 @@ function MetaDAL(driver) {
     'COMMIT;'
   };
 
-  this.init = () => co(function *() {
-    return that.exec('BEGIN;' +
-      'CREATE TABLE IF NOT EXISTS ' + that.table + ' (' +
+  async init() {
+    await this.exec('BEGIN;' +
+      'CREATE TABLE IF NOT EXISTS ' + this.table + ' (' +
       'id INTEGER NOT NULL,' +
       'version INTEGER NOT NULL,' +
       'PRIMARY KEY (id)' +
       ');' +
-      'COMMIT;', []);
-  });
+      'COMMIT;')
+  }
 
-  function executeMigration(migration, conf) {
-    return co(function *() {
-      try {
-        if (typeof migration == "string") {
+  private async executeMigration(migration: any[], conf:ConfDTO) {
+    try {
+      if (typeof migration == "string") {
 
-          // Simple SQL script to pass
-          yield that.exec(migration);
+        // Simple SQL script to pass
+        await this.exec(migration);
 
-        } else if (typeof migration == "function") {
+      } else if (typeof migration == "function") {
 
-          // JS function to execute
-          yield migration(conf);
+        // JS function to execute
+        await migration(conf);
 
-        }
-      } catch (e) {
-        logger.warn('An error occured during DB migration, continue.', e);
       }
-    });
+    } catch (e) {
+      logger.warn('An error occured during DB migration, continue.', e);
+    }
   }
 
-  this.upgradeDatabase = (conf) => co(function *() {
-    let version = yield that.getVersion();
-    while(migrations[version]) {
-      yield executeMigration(migrations[version], conf);
+  async upgradeDatabase(conf:ConfDTO) {
+    let version = await this.getVersion();
+    while(this.migrations[version]) {
+      await this.executeMigration(this.migrations[version], conf);
       // Automated increment
-      yield that.exec('UPDATE meta SET version = version + 1');
+      await this.exec('UPDATE meta SET version = version + 1');
       version++;
     }
-  });
-
-  this.upgradeDatabaseVersions = (versions) => co(function *() {
-    for (const version of versions) {
-      logger.debug("Upgrading from to v%s...", version, version + 1);
-      yield executeMigration(migrations[version]);
-    }
-  });
+  }
 
-  this.getRow = () => that.sqlFindOne({ id: 1 });
+  getRow() {
+    return this.sqlFindOne({ id: 1 })
+  }
 
-  this.getVersion = () => co(function *() {
+  async getVersion() {
     try {
-      const row = yield that.getRow();
+      const row = await this.getRow()
       return row.version;
     } catch(e) {
-      yield that.exec('INSERT INTO ' + that.table + ' VALUES (1,0);');
+      await this.exec('INSERT INTO ' + this.table + ' VALUES (1,0);')
       return 0;
     }
-  });
+  }
 
-  this.cleanData = null; // Never clean data of this table
+  cleanData() {
+    // Never clean data of this table
+    return Promise.resolve()
+  }
 }
diff --git a/app/lib/dal/sqliteDAL/PeerDAL.js b/app/lib/dal/sqliteDAL/PeerDAL.js
deleted file mode 100644
index f65ec06cd..000000000
--- a/app/lib/dal/sqliteDAL/PeerDAL.js
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * Created by cgeek on 22/08/15.
- */
-
-const co = require('co');
-const AbstractSQLite = require('./AbstractSQLite');
-
-module.exports = PeerDAL;
-
-function PeerDAL(driver) {
-
-  "use strict";
-
-  AbstractSQLite.call(this, driver);
-
-  const that = this;
-
-  this.table = 'peer';
-  this.fields = [
-    'version',
-    'currency',
-    'status',
-    'statusTS',
-    'hash',
-    'first_down',
-    'last_try',
-    'pubkey',
-    'block',
-    'signature',
-    'endpoints',
-    'raw'
-  ];
-  this.arrays = ['endpoints'];
-  this.booleans = [];
-  this.pkFields = ['pubkey'];
-  this.translated = {};
-
-  this.init = () => co(function *() {
-    return that.exec('BEGIN;' +
-      'CREATE TABLE IF NOT EXISTS ' + that.table + ' (' +
-      'version INTEGER NOT NULL,' +
-      'currency VARCHAR(50) NOT NULL,' +
-      'status VARCHAR(10),' +
-      'statusTS INTEGER NOT NULL,' +
-      'hash CHAR(64),' +
-      'first_down INTEGER,' +
-      'last_try INTEGER,' +
-      'pubkey VARCHAR(50) NOT NULL,' +
-      'block VARCHAR(60) NOT NULL,' +
-      'signature VARCHAR(100),' +
-      'endpoints TEXT NOT NULL,' +
-      'raw TEXT,' +
-      'PRIMARY KEY (pubkey)' +
-      ');' +
-      'CREATE INDEX IF NOT EXISTS idx_link_source ON peer (pubkey);' +
-      'COMMIT;', []);
-  });
-
-  this.listAll = () => this.sqlListAll();
-
-  this.getPeer = (pubkey) => this.sqlFindOne({ pubkey: pubkey });
-
-  this.savePeer = (peer) => this.saveEntity(peer);
-
-  this.removeAll = () => this.sqlDeleteAll();
-}
diff --git a/app/lib/dal/sqliteDAL/PeerDAL.ts b/app/lib/dal/sqliteDAL/PeerDAL.ts
new file mode 100644
index 000000000..299ec9b6e
--- /dev/null
+++ b/app/lib/dal/sqliteDAL/PeerDAL.ts
@@ -0,0 +1,89 @@
+import {SQLiteDriver} from "../drivers/SQLiteDriver";
+import {AbstractSQLite} from "./AbstractSQLite";
+
+export interface DBPeer {
+  version: number
+  currency: string
+  status: string
+  statusTS: number
+  hash: string
+  first_down: number | null
+  last_try: number | null
+  pubkey: string
+  block: string
+  signature: string 
+  endpoints: string
+  raw: string
+}
+
+export class PeerDAL extends AbstractSQLite<DBPeer> {
+
+  constructor(driver:SQLiteDriver) {
+    super(
+      driver,
+      'peer',
+      // PK fields
+      ['pubkey'],
+      // Fields
+      [
+        'version',
+        'currency',
+        'status',
+        'statusTS',
+        'hash',
+        'first_down',
+        'last_try',
+        'pubkey',
+        'block',
+        'signature',
+        'endpoints',
+        'raw'
+      ],
+      // Arrays
+      ['endpoints'],
+      // Booleans
+      [],
+      // BigIntegers
+      [],
+      // Transient
+      []
+    )
+  }
+
+  async init() {
+    await this.exec('BEGIN;' +
+      'CREATE TABLE IF NOT EXISTS ' + this.table + ' (' +
+      'version INTEGER NOT NULL,' +
+      'currency VARCHAR(50) NOT NULL,' +
+      'status VARCHAR(10),' +
+      'statusTS INTEGER NOT NULL,' +
+      'hash CHAR(64),' +
+      'first_down INTEGER,' +
+      'last_try INTEGER,' +
+      'pubkey VARCHAR(50) NOT NULL,' +
+      'block VARCHAR(60) NOT NULL,' +
+      'signature VARCHAR(100),' +
+      'endpoints TEXT NOT NULL,' +
+      'raw TEXT,' +
+      'PRIMARY KEY (pubkey)' +
+      ');' +
+      'CREATE INDEX IF NOT EXISTS idx_link_source ON peer (pubkey);' +
+      'COMMIT;')
+  }
+
+  listAll() {
+    return this.sqlListAll()
+  }
+
+  getPeer(pubkey:string) {
+    return this.sqlFindOne({ pubkey: pubkey })
+  }
+
+  savePeer(peer:DBPeer) {
+    return this.saveEntity(peer)
+  }
+
+  async removeAll() {
+    await this.sqlDeleteAll()
+  }
+}
diff --git a/app/lib/dal/sqliteDAL/SandBox.js b/app/lib/dal/sqliteDAL/SandBox.js
deleted file mode 100644
index 4e7d836ee..000000000
--- a/app/lib/dal/sqliteDAL/SandBox.js
+++ /dev/null
@@ -1,29 +0,0 @@
-"use strict";
-
-const co = require('co');
-
-module.exports = SandBox;
-
-function SandBox(maxSize, findElements, compareElements) {
-
-  const that = this;
-  this.maxSize = maxSize || 10;
-  
-  this.acceptNewSandBoxEntry = (element, pubkey) => co(function *() {
-    if (element.pubkey === pubkey) {
-      return true;
-    }
-    const elements = yield findElements();
-    if (elements.length < that.maxSize) {
-      return true;
-    }
-    const lowestElement = elements[elements.length - 1];
-    const comparison = compareElements(element, lowestElement);
-    return comparison > 0;
-  });
-
-  this.getSandboxRoom = () => co(function *() {
-    const elems = yield findElements();
-    return that.maxSize - elems.length;
-  });
-}
diff --git a/app/lib/dal/sqliteDAL/SandBox.ts b/app/lib/dal/sqliteDAL/SandBox.ts
new file mode 100644
index 000000000..c84f9a87f
--- /dev/null
+++ b/app/lib/dal/sqliteDAL/SandBox.ts
@@ -0,0 +1,30 @@
+export class SandBox<T> {
+
+  maxSize:number
+  
+  constructor(
+    maxSize:number,
+    public findElements:() => Promise<T[]>,
+    public compareElements:(t1:T, t2:T) => number
+  ) {
+    this.maxSize = maxSize || 10
+  }
+  
+  async acceptNewSandBoxEntry(element:any, pubkey:string) {
+    if (element.pubkey === pubkey) {
+      return true;
+    }
+    const elements = await this.findElements()
+    if (elements.length < this.maxSize) {
+      return true;
+    }
+    const lowestElement:T = elements[elements.length - 1];
+    const comparison = this.compareElements(element, lowestElement)
+    return comparison > 0;
+  }
+
+  async getSandboxRoom() {
+    const elems = await this.findElements()
+    return this.maxSize - elems.length;
+  }
+}
diff --git a/app/lib/dal/sqliteDAL/TxsDAL.js b/app/lib/dal/sqliteDAL/TxsDAL.js
deleted file mode 100644
index 2a2f907a1..000000000
--- a/app/lib/dal/sqliteDAL/TxsDAL.js
+++ /dev/null
@@ -1,187 +0,0 @@
-/**
- * Created by cgeek on 22/08/15.
- */
-
-const _ = require('underscore');
-const Q = require('q');
-const co = require('co');
-const moment = require('moment');
-const constants = require('../../constants');
-const Transaction = require('../../entity/transaction');
-const AbstractSQLite = require('./AbstractSQLite');
-const SandBox = require('./SandBox');
-
-module.exports = TxsDAL;
-
-function TxsDAL(driver) {
-
-  "use strict";
-
-  AbstractSQLite.call(this, driver);
-
-  const that = this;
-
-  this.table = 'txs';
-  this.fields = [
-    'hash',
-    'block_number',
-    'version',
-    'currency',
-    'comment',
-    'blockstamp',
-    'blockstampTime',
-    'locktime',
-    'received',
-    'time',
-    'written',
-    'removed',
-    'inputs',
-    'unlocks',
-    'outputs',
-    'issuers',
-    'signatures',
-    'recipients',
-    'output_base',
-    'output_amount'
-  ];
-  this.arrays = ['inputs','unlocks','outputs','issuers','signatures','recipients'];
-  this.booleans = ['written','removed'];
-  this.pkFields = ['hash'];
-  this.translated = {};
-
-  this.init = () => co(function *() {
-    return that.exec('BEGIN;' +
-      'CREATE TABLE IF NOT EXISTS ' + that.table + ' (' +
-      'hash CHAR(64) NOT NULL,' +
-      'block_number INTEGER,' +
-      'locktime INTEGER NOT NULL,' +
-      'version INTEGER NOT NULL,' +
-      'currency VARCHAR(50) NOT NULL,' +
-      'comment VARCHAR(255) NOT NULL,' +
-      'time DATETIME,' +
-      'inputs TEXT NOT NULL,' +
-      'unlocks TEXT NOT NULL,' +
-      'outputs TEXT NOT NULL,' +
-      'issuers TEXT NOT NULL,' +
-      'signatures TEXT NOT NULL,' +
-      'recipients TEXT NOT NULL,' +
-      'written BOOLEAN NOT NULL,' +
-      'removed BOOLEAN NOT NULL,' +
-      'PRIMARY KEY (hash)' +
-      ');' +
-      'CREATE INDEX IF NOT EXISTS idx_txs_issuers ON txs (issuers);' +
-      'CREATE INDEX IF NOT EXISTS idx_txs_written ON txs (written);' +
-      'CREATE INDEX IF NOT EXISTS idx_txs_removed ON txs (removed);' +
-      'CREATE INDEX IF NOT EXISTS idx_txs_hash ON txs (hash);' +
-      'COMMIT;', []);
-  });
-
-  this.getAllPending = (versionMin) => this.sqlFind({
-    written: false,
-    removed: false,
-    version: { $gte: versionMin }
-  });
-
-  this.getTX = (hash) => this.sqlFindOne({
-    hash: hash
-  });
-
-  this.removeTX = (hash) => co(function *() {
-    const tx = yield that.sqlFindOne({
-      hash: hash
-    });
-    if (tx) {
-      tx.removed = true;
-      return that.saveEntity(tx);
-    }
-    return Q(tx);
-  });
-
-  this.addLinked = (tx) => {
-    tx.written = true;
-    tx.removed = false;
-    tx.hash = tx.getHash(true);
-    tx.recipients = Transaction.statics.outputs2recipients(tx);
-    return that.saveEntity(tx);
-  };
-
-  this.addPending = (tx) => {
-    tx.received = moment().unix();
-    tx.written = false;
-    tx.removed = false;
-    tx.hash = tx.getHash(true);
-    tx.recipients = Transaction.statics.outputs2recipients(tx);
-    return this.saveEntity(tx);
-  };
-
-  this.getLinkedWithIssuer = (pubkey) => this.sqlFind({
-    issuers: { $contains: pubkey },
-    written: true
-  });
-
-  this.getLinkedWithRecipient = (pubkey) => co(function*() {
-    const rows = yield that.sqlFind({
-      recipients: { $contains: pubkey },
-      written: true
-    });
-    // Which does not contains the key as issuer
-    return _.filter(rows, (row) => row.issuers.indexOf(pubkey) === -1);
-  });
-
-  this.getPendingWithIssuer = (pubkey) => this.sqlFind({
-    issuers: { $contains: pubkey },
-    written: false,
-    removed: false
-  });
-
-  this.getPendingWithRecipient = (pubkey) => this.sqlFind({
-    recipients: { $contains: pubkey },
-    written: false,
-    removed: false
-  });
-
-  this.insertBatchOfTxs = (txs) => co(function *() {
-    // // Be sure the recipients field are correctly updated
-    Transaction.statics.setRecipients(txs);
-    const queries = [];
-    const insert = that.getInsertHead();
-    const values = txs.map((cert) => that.getInsertValue(cert));
-    if (txs.length) {
-      queries.push(insert + '\n' + values.join(',\n') + ';');
-    }
-    if (queries.length) {
-      return that.exec(queries.join('\n'));
-    }
-  });
-
-  this.trimExpiredNonWrittenTxs = (limitTime) => that.exec("DELETE FROM txs WHERE NOT written AND blockstampTime <= " + limitTime)
-
-  this.getTransactionByExtendedHash = (hash) => that.query("SELECT * FROM txs WHERE hash = ? OR v4_hash = ? OR v5_hash = ?", [hash, hash, hash]);
-
-  /**************************
-   * SANDBOX STUFF
-   */
-
-  this.getSandboxTxs = () => that.query('SELECT * FROM sandbox_txs LIMIT ' + (that.sandbox.maxSize), []);
-
-  this.sandbox = new SandBox(constants.SANDBOX_SIZE_TRANSACTIONS, this.getSandboxTxs.bind(this), (compared, reference) => {
-    if (compared.output_base < reference.output_base) {
-      return -1;
-    }
-    else if (compared.output_base > reference.output_base) {
-      return 1;
-    }
-    else if (compared.output_amount > reference.output_amount) {
-      return -1;
-    }
-    else if (compared.output_amount < reference.output_amount) {
-      return 1;
-    }
-    else {
-      return 0;
-    }
-  });
-
-  this.getSandboxRoom = () => this.sandbox.getSandboxRoom();
-  this.setSandboxSize = (maxSize) => this.sandbox.maxSize = maxSize;
-}
diff --git a/app/lib/dal/sqliteDAL/TxsDAL.ts b/app/lib/dal/sqliteDAL/TxsDAL.ts
new file mode 100644
index 000000000..1d2a542b0
--- /dev/null
+++ b/app/lib/dal/sqliteDAL/TxsDAL.ts
@@ -0,0 +1,257 @@
+import {AbstractSQLite} from "./AbstractSQLite";
+import {SQLiteDriver} from "../drivers/SQLiteDriver";
+import {TransactionDTO} from "../../dto/TransactionDTO";
+import {SandBox} from "./SandBox";
+
+const _ = require('underscore');
+const moment = require('moment');
+const constants = require('../../constants');
+const Transaction = require('../../entity/transaction');
+
+export class DBTx {
+  hash: string
+  block_number: number | null
+  locktime: number
+  version: number
+  currency: string
+  comment: string
+  blockstamp: string
+  blockstampTime: number | null
+  time: number | null
+  inputs: string[]
+  unlocks: string[]
+  outputs: string[]
+  issuers: string[]
+  signatures: string[]
+  recipients: string[]
+  written: boolean
+  removed: boolean
+  received: boolean
+  output_base: number
+  output_amount: number
+
+  static fromTransactionDTO(tx:TransactionDTO) {
+    const dbTx = new DBTx()
+    dbTx.hash = tx.hash
+    dbTx.locktime = tx.locktime
+    dbTx.version = tx.version
+    dbTx.currency = tx.currency
+    dbTx.blockstamp = tx.blockstamp
+    dbTx.blockstampTime = tx.blockstampTime
+    dbTx.comment = tx.comment || ""
+    dbTx.inputs = tx.inputs
+    dbTx.unlocks = tx.unlocks
+    dbTx.outputs = tx.outputs
+    dbTx.issuers = tx.issuers
+    dbTx.signatures = tx.signatures
+    dbTx.recipients = tx.outputsAsRecipients()
+    dbTx.written = false
+    dbTx.removed = false
+    dbTx.output_base = tx.outputs.reduce((sum, output) => sum + parseInt(output.split(':')[0]), 0)
+    dbTx.output_amount = tx.outputs.reduce((maxBase, output) => Math.max(maxBase, parseInt(output.split(':')[1])), 0)
+    return dbTx
+  }
+}
+
+export class TxsDAL extends AbstractSQLite<DBTx> {
+
+  constructor(driver:SQLiteDriver) {
+    super(
+      driver,
+      'txs',
+      // PK fields
+      ['hash'],
+      // Fields
+      [
+        'hash',
+        'block_number',
+        'version',
+        'currency',
+        'comment',
+        'blockstamp',
+        'blockstampTime',
+        'locktime',
+        'received',
+        'time',
+        'written',
+        'removed',
+        'inputs',
+        'unlocks',
+        'outputs',
+        'issuers',
+        'signatures',
+        'recipients',
+        'output_base',
+        'output_amount'
+      ],
+      // Arrays
+      ['inputs','unlocks','outputs','issuers','signatures','recipients'],
+      // Booleans
+      ['written','removed'],
+      // BigIntegers
+      [],
+      // Transient
+      []
+    )
+  }
+
+  async init() {
+    await this.exec('BEGIN;' +
+      'CREATE TABLE IF NOT EXISTS ' + this.table + ' (' +
+      'hash CHAR(64) NOT NULL,' +
+      'block_number INTEGER,' +
+      'locktime INTEGER NOT NULL,' +
+      'version INTEGER NOT NULL,' +
+      'currency VARCHAR(50) NOT NULL,' +
+      'comment VARCHAR(255) NOT NULL,' +
+      'time DATETIME,' +
+      'inputs TEXT NOT NULL,' +
+      'unlocks TEXT NOT NULL,' +
+      'outputs TEXT NOT NULL,' +
+      'issuers TEXT NOT NULL,' +
+      'signatures TEXT NOT NULL,' +
+      'recipients TEXT NOT NULL,' +
+      'written BOOLEAN NOT NULL,' +
+      'removed BOOLEAN NOT NULL,' +
+      'PRIMARY KEY (hash)' +
+      ');' +
+      'CREATE INDEX IF NOT EXISTS idx_txs_issuers ON txs (issuers);' +
+      'CREATE INDEX IF NOT EXISTS idx_txs_written ON txs (written);' +
+      'CREATE INDEX IF NOT EXISTS idx_txs_removed ON txs (removed);' +
+      'CREATE INDEX IF NOT EXISTS idx_txs_hash ON txs (hash);' +
+      'COMMIT;')
+  }
+
+  getAllPending(versionMin:number): Promise<DBTx[]> {
+    return this.sqlFind({
+      written: false,
+      removed: false,
+      version: { $gte: versionMin }
+    })
+  }
+
+  getTX(hash:string): Promise<DBTx> {
+    return this.sqlFindOne({
+      hash: hash
+    })
+  }
+
+  async removeTX(hash:string) {
+    const tx = await this.sqlFindOne({
+      hash: hash
+    });
+    if (tx) {
+      tx.removed = true;
+      return this.saveEntity(tx);
+    }
+    return tx
+  }
+
+  addLinked(tx:TransactionDTO, block_number:number, time:number) {
+    const dbTx = DBTx.fromTransactionDTO(tx)
+    dbTx.block_number = block_number
+    dbTx.time = time
+    dbTx.received = moment().unix()
+    dbTx.written = true
+    dbTx.removed = false
+    dbTx.hash = tx.getHash()
+    return this.saveEntity(dbTx)
+  }
+
+  addPending(tx:TransactionDTO) {
+    const dbTx = DBTx.fromTransactionDTO(tx)
+    dbTx.received = moment().unix()
+    dbTx.written = false
+    dbTx.removed = false
+    dbTx.hash = tx.getHash()
+    return this.saveEntity(dbTx)
+  }
+
+  getLinkedWithIssuer(pubkey:string) {
+    return this.sqlFind({
+      issuers: { $contains: pubkey },
+      written: true
+    })
+  }
+
+  async getLinkedWithRecipient(pubkey:string) {
+    const rows = await this.sqlFind({
+      recipients: { $contains: pubkey },
+      written: true
+    })
+    // Which does not contains the key as issuer
+    return _.filter(rows, (row:DBTx) => row.issuers.indexOf(pubkey) === -1);
+  }
+
+  getPendingWithIssuer(pubkey:string) {
+    return this.sqlFind({
+      issuers: { $contains: pubkey },
+      written: false,
+      removed: false
+    })
+  }
+
+  getPendingWithRecipient(pubkey:string) {
+    return this.sqlFind({
+      recipients: { $contains: pubkey },
+      written: false,
+      removed: false
+    })
+  }
+
+  insertBatchOfTxs(txs:DBTx[]) {
+    // // Be sure the recipients field are correctly updated
+    Transaction.statics.setRecipients(txs);
+    const queries = [];
+    const insert = this.getInsertHead();
+    const values = txs.map((cert) => this.getInsertValue(cert));
+    if (txs.length) {
+      queries.push(insert + '\n' + values.join(',\n') + ';');
+    }
+    if (queries.length) {
+      this.exec(queries.join('\n'));
+    }
+  }
+
+  trimExpiredNonWrittenTxs(limitTime:number) {
+    return this.exec("DELETE FROM txs WHERE NOT written AND blockstampTime <= " + limitTime)
+  }
+
+  getTransactionByExtendedHash(hash:string) {
+    return this.query("SELECT * FROM txs WHERE hash = ? OR v4_hash = ? OR v5_hash = ?", [hash, hash, hash])
+  }
+
+  /**************************
+   * SANDBOX STUFF
+   */
+
+  getSandboxTxs() {
+    return this.query('SELECT * FROM sandbox_txs LIMIT ' + (this.sandbox.maxSize), [])
+  }
+
+  sandbox = new SandBox(constants.SANDBOX_SIZE_TRANSACTIONS, this.getSandboxTxs.bind(this), (compared:DBTx, reference:DBTx) => {
+    if (compared.output_base < reference.output_base) {
+      return -1;
+    }
+    else if (compared.output_base > reference.output_base) {
+      return 1;
+    }
+    else if (compared.output_amount > reference.output_amount) {
+      return -1;
+    }
+    else if (compared.output_amount < reference.output_amount) {
+      return 1;
+    }
+    else {
+      return 0;
+    }
+  })
+
+  getSandboxRoom() {
+    return this.sandbox.getSandboxRoom()
+  }
+
+  setSandboxSize(maxSize:number) {
+    this.sandbox.maxSize = maxSize
+  }
+}
diff --git a/app/lib/dal/sqliteDAL/WalletDAL.js b/app/lib/dal/sqliteDAL/WalletDAL.js
deleted file mode 100644
index 88c5eb215..000000000
--- a/app/lib/dal/sqliteDAL/WalletDAL.js
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * Created by cgeek on 22/08/15.
- */
-
-const co = require('co');
-const AbstractSQLite = require('./AbstractSQLite');
-
-module.exports = WalletDAL;
-
-/**
- * Facility table saving the current state of a wallet.
- * @param driver SQL driver for making SQL requests.
- * @constructor
- */
-function WalletDAL(driver) {
-
-  "use strict";
-
-  AbstractSQLite.call(this, driver);
-
-  const that = this;
-
-  this.table = 'wallet';
-  this.fields = [
-    'conditions',
-    'balance'
-  ];
-  this.arrays = [];
-  this.booleans = [];
-  this.pkFields = ['conditions'];
-  this.translated = {};
-
-  this.init = () => co(function *() {
-    return that.exec('BEGIN;' +
-      'CREATE TABLE IF NOT EXISTS ' + that.table + ' (' +
-      'conditions TEXT NOT NULL,' +
-      'balance INTEGER NOT NULL,' +
-      'PRIMARY KEY (conditions)' +
-      ');' +
-      'CREATE INDEX IF NOT EXISTS wallet_balance ON wallet(balance);' +
-      'COMMIT;', []);
-  });
-
-  this.getWallet = (conditions) => this.sqlFindOne({ conditions });
-
-  this.saveWallet = (wallet) => this.saveEntity(wallet);
-}
diff --git a/app/lib/dal/sqliteDAL/WalletDAL.ts b/app/lib/dal/sqliteDAL/WalletDAL.ts
new file mode 100644
index 000000000..86c9f31b4
--- /dev/null
+++ b/app/lib/dal/sqliteDAL/WalletDAL.ts
@@ -0,0 +1,56 @@
+import {SQLiteDriver} from "../drivers/SQLiteDriver";
+import {AbstractSQLite} from "./AbstractSQLite";
+
+export interface DBWallet {
+  conditions: string
+  balance: number
+}
+
+/**
+ * Facility table saving the current state of a wallet.
+ * @param driver SQL driver for making SQL requests.
+ * @constructor
+ */
+export class WalletDAL extends AbstractSQLite<DBWallet> {
+
+  constructor(driver:SQLiteDriver) {
+    super(
+      driver,
+      'wallet',
+      // PK fields
+      ['conditions'],
+      // Fields
+      [
+        'conditions',
+        'balance'
+      ],
+      // Arrays
+      [],
+      // Booleans
+      [],
+      // BigIntegers
+      ['monetaryMass'],
+      // Transient
+      []
+    )
+  }
+
+  async init() {
+    await this.exec('BEGIN;' +
+      'CREATE TABLE IF NOT EXISTS ' + this.table + ' (' +
+      'conditions TEXT NOT NULL,' +
+      'balance INTEGER NOT NULL,' +
+      'PRIMARY KEY (conditions)' +
+      ');' +
+      'CREATE INDEX IF NOT EXISTS wallet_balance ON wallet(balance);' +
+      'COMMIT;')
+  }
+
+  getWallet(conditions:string) {
+    return this.sqlFindOne({ conditions })
+  }
+
+  saveWallet(wallet:DBWallet) {
+    return this.saveEntity(wallet)
+  }
+}
diff --git a/app/lib/dal/sqliteDAL/index/BIndexDAL.js b/app/lib/dal/sqliteDAL/index/BIndexDAL.js
deleted file mode 100644
index bee032011..000000000
--- a/app/lib/dal/sqliteDAL/index/BIndexDAL.js
+++ /dev/null
@@ -1,113 +0,0 @@
-/**
- * Created by cgeek on 22/08/15.
- */
-
-const co = require('co');
-const AbstractSQLite = require('./../AbstractSQLite');
-
-module.exports = BIndexDAL;
-
-function BIndexDAL(driver) {
-
-  "use strict";
-
-  AbstractSQLite.call(this, driver);
-
-  const that = this;
-
-  this.table = 'b_index';
-  this.fields = [
-    'version',
-    'bsize',
-    'hash',
-    'issuer',
-    'time',
-    'number',
-    'membersCount',
-    'issuersCount',
-    'issuersFrame',
-    'issuersFrameVar',
-    'issuerDiff',
-    'avgBlockSize',
-    'medianTime',
-    'dividend',
-    'mass',
-    'massReeval',
-    'unitBase',
-    'powMin',
-    'udTime',
-    'udReevalTime',
-    'diffNumber',
-    'speed'
-  ];
-  this.arrays = [];
-  this.bigintegers = ['mass', 'massReeval'];
-  this.booleans = ['leaving'];
-  this.pkFields = ['number'];
-  this.translated = {};
-
-  this.init = () => co(function *() {
-    return that.exec('BEGIN;' +
-      'CREATE TABLE IF NOT EXISTS ' + that.table + ' (' +
-      'version INTEGER NOT NULL,' +
-      'bsize INTEGER NOT NULL,' +
-      'hash VARCHAR(64) NOT NULL,' +
-      'issuer VARCHAR(50) NOT NULL,' +
-      'time INTEGER NOT NULL,' +
-      'number INTEGER NOT NULL,' +
-      'membersCount INTEGER NOT NULL,' +
-      'issuersCount INTEGER NOT NULL,' +
-      'issuersFrame INTEGER NOT NULL,' +
-      'issuersFrameVar INTEGER NOT NULL,' +
-      'issuerDiff INTEGER NULL,' +
-      'avgBlockSize INTEGER NOT NULL,' +
-      'medianTime INTEGER NOT NULL,' +
-      'dividend INTEGER NOT NULL,' +
-      'mass VARCHAR(100) NOT NULL,' +
-      'unitBase INTEGER NOT NULL,' +
-      'powMin INTEGER NOT NULL,' +
-      'udTime INTEGER NOT NULL,' +
-      'udReevalTime INTEGER NOT NULL,' +
-      'diffNumber INTEGER NOT NULL,' +
-      'speed FLOAT NOT NULL,' +
-      'PRIMARY KEY (number)' +
-      ');' +
-      'CREATE INDEX IF NOT EXISTS idx_bindex_number ON b_index (number);' +
-      'CREATE INDEX IF NOT EXISTS idx_bindex_issuer ON b_index (issuer);' +
-      'COMMIT;', []);
-  });
-
-  /**
-   * Get HEAD~n
-   * @param n Position
-   */
-  this.head = (n) => co(function*() {
-    if (!n) {
-      throw "Cannot read HEAD~0, which is the incoming block"
-    }
-    const headRecords = yield that.query('SELECT * FROM ' + that.table + ' ORDER BY number DESC LIMIT 1 OFFSET ?', [n - 1]);
-    return headRecords[0];
-  });
-
-  /**
-   * Get the last record available in bindex
-   */
-  this.tail = () => co(function*() {
-    const tailRecords = yield that.query('SELECT * FROM ' + that.table + ' ORDER BY number ASC LIMIT 1', []);
-    return tailRecords[0];
-  });
-
-  /**
-   * Get HEAD~n..m
-   * @param n
-   * @param m
-   */
-  this.range = (n, m) => co(function*() {
-    const count = m - n + 1;
-    return that.query('SELECT * FROM ' + that.table + ' ORDER BY number DESC LIMIT ? OFFSET ?', [count, n - 1]);
-  });
-
-  this.removeBlock = (number) => that.exec('DELETE FROM ' + that.table + ' WHERE number = ' + number);
-
-  this.trimBlocks = (maxnumber) => that.exec('DELETE FROM ' + that.table + ' WHERE number < ' + maxnumber);
-}
diff --git a/app/lib/dal/sqliteDAL/index/BIndexDAL.ts b/app/lib/dal/sqliteDAL/index/BIndexDAL.ts
new file mode 100644
index 000000000..24de1d84d
--- /dev/null
+++ b/app/lib/dal/sqliteDAL/index/BIndexDAL.ts
@@ -0,0 +1,117 @@
+import {AbstractSQLite} from "../AbstractSQLite";
+import {DBHead} from "../../../db/DBHead";
+import {SQLiteDriver} from "../../drivers/SQLiteDriver";
+
+export class BIndexDAL extends AbstractSQLite<DBHead> {
+
+  constructor(driver:SQLiteDriver) {
+    super(
+      driver,
+      'b_index',
+      // PK fields
+      ['number'],
+      // Fields
+      [
+        'version',
+        'bsize',
+        'hash',
+        'issuer',
+        'time',
+        'number',
+        'membersCount',
+        'issuersCount',
+        'issuersFrame',
+        'issuersFrameVar',
+        'issuerDiff',
+        'avgBlockSize',
+        'medianTime',
+        'dividend',
+        'mass',
+        'massReeval',
+        'unitBase',
+        'powMin',
+        'udTime',
+        'udReevalTime',
+        'diffNumber',
+        'speed'
+      ],
+      // Arrays
+      [],
+      // Booleans
+      ['leaving'],
+      // BigIntegers
+      ['mass', 'massReeval'],
+      // Transient
+      []
+    )
+  }
+
+  async init() {
+    await this.exec('BEGIN;' +
+      'CREATE TABLE IF NOT EXISTS ' + this.table + ' (' +
+      'version INTEGER NOT NULL,' +
+      'bsize INTEGER NOT NULL,' +
+      'hash VARCHAR(64) NOT NULL,' +
+      'issuer VARCHAR(50) NOT NULL,' +
+      'time INTEGER NOT NULL,' +
+      'number INTEGER NOT NULL,' +
+      'membersCount INTEGER NOT NULL,' +
+      'issuersCount INTEGER NOT NULL,' +
+      'issuersFrame INTEGER NOT NULL,' +
+      'issuersFrameVar INTEGER NOT NULL,' +
+      'issuerDiff INTEGER NULL,' +
+      'avgBlockSize INTEGER NOT NULL,' +
+      'medianTime INTEGER NOT NULL,' +
+      'dividend INTEGER NOT NULL,' +
+      'mass VARCHAR(100) NOT NULL,' +
+      'unitBase INTEGER NOT NULL,' +
+      'powMin INTEGER NOT NULL,' +
+      'udTime INTEGER NOT NULL,' +
+      'udReevalTime INTEGER NOT NULL,' +
+      'diffNumber INTEGER NOT NULL,' +
+      'speed FLOAT NOT NULL,' +
+      'PRIMARY KEY (number)' +
+      ');' +
+      'CREATE INDEX IF NOT EXISTS idx_bindex_number ON b_index (number);' +
+      'CREATE INDEX IF NOT EXISTS idx_bindex_issuer ON b_index (issuer);' +
+      'COMMIT;')
+  }
+
+  /**
+   * Get HEAD~n
+   * @param n Position
+   */
+  async head(n:number) {
+    if (!n) {
+      throw "Cannot read HEAD~0, which is the incoming block"
+    }
+    const headRecords = await this.query('SELECT * FROM ' + this.table + ' ORDER BY number DESC LIMIT 1 OFFSET ?', [n - 1]);
+    return headRecords[0];
+  }
+
+  /**
+   * Get the last record available in bindex
+   */
+  async tail() {
+    const tailRecords = await this.query('SELECT * FROM ' + this.table + ' ORDER BY number ASC LIMIT 1', []);
+    return tailRecords[0];
+  }
+
+  /**
+   * Get HEAD~n..m
+   * @param n
+   * @param m
+   */
+  range(n:number, m:number) {
+    const count = m - n + 1;
+    return this.query('SELECT * FROM ' + this.table + ' ORDER BY number DESC LIMIT ? OFFSET ?', [count, n - 1]);
+  }
+
+  removeBlock(number:number) {
+    return this.exec('DELETE FROM ' + this.table + ' WHERE number = ' + number)
+  }
+
+  trimBlocks(maxnumber:number) {
+    return this.exec('DELETE FROM ' + this.table + ' WHERE number < ' + maxnumber)
+  }
+}
diff --git a/app/lib/dal/sqliteDAL/index/CIndexDAL.js b/app/lib/dal/sqliteDAL/index/CIndexDAL.js
deleted file mode 100644
index dde0e9394..000000000
--- a/app/lib/dal/sqliteDAL/index/CIndexDAL.js
+++ /dev/null
@@ -1,129 +0,0 @@
-/**
- * Created by cgeek on 22/08/15.
- */
-
-const co = require('co');
-const constants = require('./../../../constants');
-const common = require('duniter-common');
-const indexer         = require('../../../indexer').Indexer
-const AbstractSQLite = require('./../AbstractSQLite');
-const AbstractIndex = require('./../AbstractIndex');
-
-module.exports = CIndexDAL;
-
-function CIndexDAL(driver) {
-
-  "use strict";
-
-  AbstractSQLite.call(this, driver);
-  AbstractIndex.call(this, driver);
-
-  const that = this;
-
-  this.table = 'c_index';
-  this.fields = [
-    'op',
-    'issuer',
-    'receiver',
-    'created_on',
-    'written_on',
-    'writtenOn',
-    'sig',
-    'expires_on',
-    'expired_on',
-    'chainable_on',
-    'from_wid',
-    'to_wid'
-  ];
-  this.arrays = [];
-  this.bigintegers = [];
-  this.booleans = [];
-  this.pkFields = ['op', 'issuer', 'receiver', 'written_on'];
-  this.translated = {};
-
-  this.init = () => co(function *() {
-    return that.exec('BEGIN;' +
-      'CREATE TABLE IF NOT EXISTS ' + that.table + ' (' +
-      'op VARCHAR(10) NOT NULL,' +
-      'issuer VARCHAR(50) NOT NULL,' +
-      'receiver VARCHAR(50) NOT NULL,' +
-      'created_on VARCHAR(80) NOT NULL,' +
-      'written_on VARCHAR(80) NOT NULL,' +
-      'sig VARCHAR(100) NULL,' +
-      'expires_on INTEGER NULL,' +
-      'expired_on INTEGER NULL,' +
-      'chainable_on INTEGER NULL,' +
-      'from_wid INTEGER NULL,' +
-      'to_wid INTEGER NULL,' +
-      'PRIMARY KEY (op,issuer,receiver,written_on)' +
-      ');' +
-      'CREATE INDEX IF NOT EXISTS idx_cindex_issuer ON c_index (issuer);' +
-      'CREATE INDEX IF NOT EXISTS idx_cindex_receiver ON c_index (receiver);' +
-      'CREATE INDEX IF NOT EXISTS idx_cindex_chainable_on ON c_index (chainable_on);' +
-      'COMMIT;', []);
-  });
-
-  this.reducablesFrom = (from) => co(function*() {
-    const reducables = yield that.query('SELECT * FROM ' + that.table + ' WHERE issuer = ? ORDER BY CAST(written_on as integer) ASC', [from]);
-    return indexer.DUP_HELPERS.reduceBy(reducables, ['issuer', 'receiver', 'created_on']);
-  });
-
-  this.trimExpiredCerts = (belowNumber) => co(function*() {
-    const toDelete = yield that.query('SELECT * FROM ' + that.table + ' WHERE expired_on > ? AND CAST(written_on as int) < ?', [0, belowNumber]);
-    for (const row of toDelete) {
-      yield that.exec("DELETE FROM " + that.table + " " +
-        "WHERE issuer like '" + row.issuer + "' " +
-        "AND receiver = '" + row.receiver + "' " +
-        "AND created_on like '" + row.created_on + "'");
-    }
-  });
-
-  this.getWrittenOn = (blockstamp) => that.sqlFind({ written_on: blockstamp });
-
-  this.findExpired = (medianTime) => that.query('SELECT * FROM ' + that.table + ' c1 WHERE expires_on <= ? ' +
-    'AND NOT EXISTS (' +
-    ' SELECT * FROM c_index c2' +
-    ' WHERE c1.issuer = c2.issuer' +
-    ' AND c1.receiver = c2.receiver' +
-    ' AND c1.created_on = c2.created_on' +
-    ' AND c2.op = ?' +
-    ')', [medianTime, common.constants.IDX_UPDATE]);
-
-  this.getValidLinksTo = (receiver) => that.query('SELECT * FROM ' + that.table + ' c1 ' +
-    'WHERE c1.receiver = ? ' +
-    'AND c1.expired_on = 0 ' +
-    'AND NOT EXISTS (' +
-    ' SELECT * FROM c_index c2' +
-    ' WHERE c1.issuer = c2.issuer' +
-    ' AND c1.receiver = c2.receiver' +
-    ' AND c1.created_on = c2.created_on' +
-    ' AND c2.op = ?' +
-    ')', [receiver, common.constants.IDX_UPDATE]);
-
-  this.getValidLinksFrom = (issuer) => that.query('SELECT * FROM ' + that.table + ' c1 ' +
-    'WHERE c1.issuer = ? ' +
-    'AND c1.expired_on = 0 ' +
-    'AND NOT EXISTS (' +
-    ' SELECT * FROM c_index c2' +
-    ' WHERE c1.issuer = c2.issuer' +
-    ' AND c1.receiver = c2.receiver' +
-    ' AND c1.created_on = c2.created_on' +
-    ' AND c2.op = ?' +
-    ')', [issuer, common.constants.IDX_UPDATE]);
-
-  this.existsNonReplayableLink = (issuer, receiver) => co(function*() {
-    const results = yield that.query('SELECT * FROM ' + that.table + ' c1 ' +
-      'WHERE c1.issuer = ? ' +
-      'AND c1.receiver = ? ' +
-      'AND NOT EXISTS (' +
-      ' SELECT * FROM c_index c2' +
-      ' WHERE c1.issuer = c2.issuer' +
-      ' AND c1.receiver = c2.receiver' +
-      ' AND c1.created_on = c2.created_on' +
-      ' AND c2.op = ?' +
-      ')', [issuer, receiver, common.constants.IDX_UPDATE]);
-    return results.length > 0;
-  });
-
-  this.removeBlock = (blockstamp) => that.exec('DELETE FROM ' + that.table + ' WHERE written_on = \'' + blockstamp + '\'');
-}
diff --git a/app/lib/dal/sqliteDAL/index/CIndexDAL.ts b/app/lib/dal/sqliteDAL/index/CIndexDAL.ts
new file mode 100644
index 000000000..60c0bf938
--- /dev/null
+++ b/app/lib/dal/sqliteDAL/index/CIndexDAL.ts
@@ -0,0 +1,138 @@
+import {AbstractIndex} from "../AbstractIndex";
+import {SQLiteDriver} from "../../drivers/SQLiteDriver";
+import {CindexEntry} from "../../../indexer";
+
+const constants = require('./../../../constants');
+const common = require('duniter-common');
+const indexer         = require('../../../indexer').Indexer
+
+export class CIndexDAL extends AbstractIndex<CindexEntry> {
+
+  constructor(driver:SQLiteDriver) {
+    super(
+      driver,
+      'c_index',
+      // PK fields
+      ['op', 'issuer', 'receiver', 'written_on'],
+      // Fields
+      [
+        'op',
+        'issuer',
+        'receiver',
+        'created_on',
+        'written_on',
+        'writtenOn',
+        'sig',
+        'expires_on',
+        'expired_on',
+        'chainable_on',
+        'from_wid',
+        'to_wid'
+      ],
+      // Arrays
+      [],
+      // Booleans
+      [],
+      // BigIntegers
+      [],
+      // Transient
+      []
+    )
+  }
+
+  async init() {
+    await this.exec('BEGIN;' +
+      'CREATE TABLE IF NOT EXISTS ' + this.table + ' (' +
+      'op VARCHAR(10) NOT NULL,' +
+      'issuer VARCHAR(50) NOT NULL,' +
+      'receiver VARCHAR(50) NOT NULL,' +
+      'created_on VARCHAR(80) NOT NULL,' +
+      'written_on VARCHAR(80) NOT NULL,' +
+      'sig VARCHAR(100) NULL,' +
+      'expires_on INTEGER NULL,' +
+      'expired_on INTEGER NULL,' +
+      'chainable_on INTEGER NULL,' +
+      'from_wid INTEGER NULL,' +
+      'to_wid INTEGER NULL,' +
+      'PRIMARY KEY (op,issuer,receiver,written_on)' +
+      ');' +
+      'CREATE INDEX IF NOT EXISTS idx_cindex_issuer ON c_index (issuer);' +
+      'CREATE INDEX IF NOT EXISTS idx_cindex_receiver ON c_index (receiver);' +
+      'CREATE INDEX IF NOT EXISTS idx_cindex_chainable_on ON c_index (chainable_on);' +
+      'COMMIT;')
+  }
+
+  async reducablesFrom(from:string) {
+    const reducables = await this.query('SELECT * FROM ' + this.table + ' WHERE issuer = ? ORDER BY CAST(written_on as integer) ASC', [from]);
+    return indexer.DUP_HELPERS.reduceBy(reducables, ['issuer', 'receiver', 'created_on']);
+  }
+
+  async trimExpiredCerts(belowNumber:number) {
+    const toDelete = await this.query('SELECT * FROM ' + this.table + ' WHERE expired_on > ? AND CAST(written_on as int) < ?', [0, belowNumber])
+    for (const row of toDelete) {
+      await this.exec("DELETE FROM " + this.table + " " +
+        "WHERE issuer like '" + row.issuer + "' " +
+        "AND receiver = '" + row.receiver + "' " +
+        "AND created_on like '" + row.created_on + "'");
+    }
+  }
+
+  getWrittenOn(blockstamp:string) {
+    return this.sqlFind({ written_on: blockstamp })
+  }
+
+  findExpired(medianTime:number) {
+    return this.query('SELECT * FROM ' + this.table + ' c1 WHERE expires_on <= ? ' +
+      'AND NOT EXISTS (' +
+      ' SELECT * FROM c_index c2' +
+      ' WHERE c1.issuer = c2.issuer' +
+      ' AND c1.receiver = c2.receiver' +
+      ' AND c1.created_on = c2.created_on' +
+      ' AND c2.op = ?' +
+      ')', [medianTime, common.constants.IDX_UPDATE])
+  }
+
+  getValidLinksTo(receiver:string) {
+    return this.query('SELECT * FROM ' + this.table + ' c1 ' +
+      'WHERE c1.receiver = ? ' +
+      'AND c1.expired_on = 0 ' +
+      'AND NOT EXISTS (' +
+      ' SELECT * FROM c_index c2' +
+      ' WHERE c1.issuer = c2.issuer' +
+      ' AND c1.receiver = c2.receiver' +
+      ' AND c1.created_on = c2.created_on' +
+      ' AND c2.op = ?' +
+      ')', [receiver, common.constants.IDX_UPDATE])
+  }
+
+  getValidLinksFrom(issuer:string) {
+    return this.query('SELECT * FROM ' + this.table + ' c1 ' +
+      'WHERE c1.issuer = ? ' +
+      'AND c1.expired_on = 0 ' +
+      'AND NOT EXISTS (' +
+      ' SELECT * FROM c_index c2' +
+      ' WHERE c1.issuer = c2.issuer' +
+      ' AND c1.receiver = c2.receiver' +
+      ' AND c1.created_on = c2.created_on' +
+      ' AND c2.op = ?' +
+      ')', [issuer, common.constants.IDX_UPDATE])
+  }
+
+  async existsNonReplayableLink(issuer:string, receiver:string) {
+    const results = await this.query('SELECT * FROM ' + this.table + ' c1 ' +
+      'WHERE c1.issuer = ? ' +
+      'AND c1.receiver = ? ' +
+      'AND NOT EXISTS (' +
+      ' SELECT * FROM c_index c2' +
+      ' WHERE c1.issuer = c2.issuer' +
+      ' AND c1.receiver = c2.receiver' +
+      ' AND c1.created_on = c2.created_on' +
+      ' AND c2.op = ?' +
+      ')', [issuer, receiver, common.constants.IDX_UPDATE]);
+    return results.length > 0;
+  }
+
+  removeBlock(blockstamp:string) {
+    return this.exec('DELETE FROM ' + this.table + ' WHERE written_on = \'' + blockstamp + '\'')
+  }
+}
diff --git a/app/lib/dal/sqliteDAL/index/IIndexDAL.js b/app/lib/dal/sqliteDAL/index/IIndexDAL.js
deleted file mode 100644
index 4030b5905..000000000
--- a/app/lib/dal/sqliteDAL/index/IIndexDAL.js
+++ /dev/null
@@ -1,145 +0,0 @@
-/**
- * Created by cgeek on 22/08/15.
- */
-
-const co = require('co');
-const _ = require('underscore');
-const indexer         = require('../../../indexer').Indexer
-const AbstractSQLite = require('./../AbstractSQLite');
-const AbstractIndex = require('./../AbstractIndex');
-
-module.exports = IIndexDAL;
-
-function IIndexDAL(driver) {
-
-  "use strict";
-
-  AbstractSQLite.call(this, driver);
-  AbstractIndex.call(this);
-
-  const that = this;
-
-  this.table = 'i_index';
-  this.fields = [
-    'op',
-    'uid',
-    'pub',
-    'hash',
-    'sig',
-    'created_on',
-    'written_on',
-    'writtenOn',
-    'member',
-    'wasMember',
-    'kick',
-    'wotb_id'
-  ];
-  this.arrays = [];
-  this.bigintegers = [];
-  this.booleans = ['member', 'wasMember', 'kick'];
-  this.pkFields = ['op', 'pub', 'created_on', 'written_on'];
-  this.translated = {};
-
-  this.init = () => co(function *() {
-    return that.exec('BEGIN;' +
-      'CREATE TABLE IF NOT EXISTS ' + that.table + ' (' +
-      'op VARCHAR(10) NOT NULL,' +
-      'uid VARCHAR(100) NULL,' +
-      'pub VARCHAR(50) NOT NULL,' +
-      'hash VARCHAR(80) NULL,' +
-      'sig VARCHAR(80) NULL,' +
-      'created_on VARCHAR(80) NULL,' +
-      'written_on VARCHAR(80) NOT NULL,' +
-      'member BOOLEAN NULL,' +
-      'wasMember BOOLEAN NULL,' +
-      'kick BOOLEAN NULL,' +
-      'wotb_id INTEGER NULL,' +
-      'PRIMARY KEY (op,pub,created_on,written_on)' +
-      ');' +
-      'CREATE INDEX IF NOT EXISTS idx_iindex_pub ON i_index (pub);' +
-      'COMMIT;', []);
-  });
-
-  this.getMembers = () => co(function*() {
-    // All those who has been subject to, or who are currently subject to kicking. Make one result per pubkey.
-    const pubkeys = yield that.query('SELECT DISTINCT(pub) FROM ' + that.table);
-    // We get the full representation for each member
-    const reduced = yield pubkeys.map((entry) => co(function*() {
-      const reducable = yield that.reducable(entry.pub);
-      return indexer.DUP_HELPERS.reduce(reducable);
-    }));
-    // Filter on those to be kicked, return their pubkey
-    const filtered = _.filter(reduced, (entry) => entry.member);
-    return filtered.map(toCorrectEntity);
-  });
-
-  this.getMembersPubkeys = () => this.query('SELECT i1.pub ' +
-    'FROM i_index i1 ' +
-    'WHERE i1.member ' +
-    'AND CAST(i1.written_on as int) = (' +
-    ' SELECT MAX(CAST(i2.written_on as int)) ' +
-    ' FROM i_index i2 ' +
-    ' WHERE i1.pub = i2.pub ' +
-    ' AND i2.member IS NOT NULL' +
-    ')')
-
-  this.getLatestMember = () => co(function*() {
-    const max_wotb_id = (yield that.query('SELECT MAX(wotb_id) as max_wotb_id FROM ' + that.table))[0].max_wotb_id;
-    return entityOrNull('wotb_id', max_wotb_id);
-  });
-
-  this.getToBeKickedPubkeys = () => co(function*() {
-    // All those who has been subject to, or who are currently subject to kicking. Make one result per pubkey.
-    const reducables = indexer.DUP_HELPERS.reduceBy(yield that.sqlFind({ kick: true }), ['pub']);
-    // We get the full representation for each member
-    const reduced = yield reducables.map((entry) => co(function*() {
-      const reducable = yield that.reducable(entry.pub);
-      return indexer.DUP_HELPERS.reduce(reducable);
-    }));
-    // Filter on those to be kicked, return their pubkey
-    return _.filter(reduced, (entry) => entry.kick).map((entry) => entry.pub);
-  });
-
-  this.searchThoseMatching = (search) => co(function*() {
-    const reducables = indexer.DUP_HELPERS.reduceBy(yield that.sqlFindLikeAny({
-        pub: "%" + search + "%",
-        uid: "%" + search + "%"
-      }), ['pub']);
-    // We get the full representation for each member
-    return yield reducables.map((entry) => co(function*() {
-      return toCorrectEntity(indexer.DUP_HELPERS.reduce(yield that.reducable(entry.pub)));
-    }));
-  });
-
-  this.getFromPubkey = (pubkey) => entityOrNull('pub', pubkey);
-
-  this.getFromUID = (uid) => entityOrNull('uid', uid);
-
-  this.getFromHash = (hash) => entityOrNull('hash', hash, 'pub');
-
-  this.reducable = (pub) => this.query('SELECT * FROM ' + this.table + ' WHERE pub = ? ORDER BY CAST(written_on as integer) ASC', [pub]);
-
-  this.removeBlock = (blockstamp) => that.exec('DELETE FROM ' + that.table + ' WHERE written_on = \'' + blockstamp + '\'');
-
-  function entityOrNull(field, value, retrieveOnField) {
-    return co(function*() {
-      let reducable = yield that.query('SELECT * FROM ' + that.table + ' WHERE ' + field + ' = ?', [value]);
-      if (reducable.length) {
-        if (retrieveOnField) {
-          // Force full retrieval on `pub` field
-          reducable = yield that.query('SELECT * FROM ' + that.table + ' WHERE pub = ? ORDER BY CAST(written_on as int) ASC', [reducable[0].pub]);
-        }
-        return toCorrectEntity(indexer.DUP_HELPERS.reduce(reducable));
-      }
-      return null;
-    });
-  }
-
-  function toCorrectEntity(row) {
-    // Old field
-    row.pubkey = row.pub;
-    row.buid = row.created_on;
-    row.revocation_sig = null;
-    return row;
-  }
-}
diff --git a/app/lib/dal/sqliteDAL/index/IIndexDAL.ts b/app/lib/dal/sqliteDAL/index/IIndexDAL.ts
new file mode 100644
index 000000000..813e34f67
--- /dev/null
+++ b/app/lib/dal/sqliteDAL/index/IIndexDAL.ts
@@ -0,0 +1,175 @@
+import {SQLiteDriver} from "../../drivers/SQLiteDriver";
+import {AbstractIndex} from "../AbstractIndex";
+import {IindexEntry, Indexer} from "../../../indexer";
+
+const _ = require('underscore');
+
+export interface OldIindexEntry extends IindexEntry {
+  pubkey: string
+  buid: string | null
+  revocation_sig:string | null
+}
+
+export class IIndexDAL extends AbstractIndex<IindexEntry> {
+
+  constructor(driver:SQLiteDriver) {
+    super(
+      driver,
+      'i_index',
+      // PK fields
+      ['op', 'pub', 'created_on', 'written_on'],
+      // Fields
+      [
+        'op',
+        'uid',
+        'pub',
+        'hash',
+        'sig',
+        'created_on',
+        'written_on',
+        'writtenOn',
+        'member',
+        'wasMember',
+        'kick',
+        'wotb_id'
+      ],
+      // Arrays
+      [],
+      // Booleans
+      ['member', 'wasMember', 'kick'],
+      // BigIntegers
+      [],
+      // Transient
+      []
+    )
+  }
+
+  init() {
+    return this.exec('BEGIN;' +
+      'CREATE TABLE IF NOT EXISTS ' + this.table + ' (' +
+      'op VARCHAR(10) NOT NULL,' +
+      'uid VARCHAR(100) NULL,' +
+      'pub VARCHAR(50) NOT NULL,' +
+      'hash VARCHAR(80) NULL,' +
+      'sig VARCHAR(80) NULL,' +
+      'created_on VARCHAR(80) NULL,' +
+      'written_on VARCHAR(80) NOT NULL,' +
+      'member BOOLEAN NULL,' +
+      'wasMember BOOLEAN NULL,' +
+      'kick BOOLEAN NULL,' +
+      'wotb_id INTEGER NULL,' +
+      'PRIMARY KEY (op,pub,created_on,written_on)' +
+      ');' +
+      'CREATE INDEX IF NOT EXISTS idx_iindex_pub ON i_index (pub);' +
+      'COMMIT;')
+  }
+
+  async getMembers() {
+    // All those who has been subject to, or who are currently subject to kicking. Make one result per pubkey.
+    const pubkeys = await this.query('SELECT DISTINCT(pub) FROM ' + this.table);
+    // We get the full representation for each member
+    const reduced = await Promise.all(pubkeys.map(async (entry) => {
+      const reducable = await this.reducable(entry.pub);
+      return Indexer.DUP_HELPERS.reduce(reducable);
+    }));
+    // Filter on those to be kicked, return their pubkey
+    const filtered = _.filter(reduced, (entry:IindexEntry) => entry.member);
+    return filtered.map((t:IindexEntry) => this.toCorrectEntity(t))
+  }
+
+  getMembersPubkeys() {
+    return this.query('SELECT i1.pub ' +
+      'FROM i_index i1 ' +
+      'WHERE i1.member ' +
+      'AND CAST(i1.written_on as int) = (' +
+      ' SELECT MAX(CAST(i2.written_on as int)) ' +
+      ' FROM i_index i2 ' +
+      ' WHERE i1.pub = i2.pub ' +
+      ' AND i2.member IS NOT NULL' +
+      ')')
+  }
+
+  async getLatestMember() {
+    const res:any = (await this.query('SELECT MAX(wotb_id) as max_wotb_id FROM ' + this.table))[0]
+    const max_wotb_id = res.max_wotb_id
+    return this.entityOrNull('wotb_id', max_wotb_id)
+  }
+
+  async getToBeKickedPubkeys() {
+    // All those who has been subject to, or who are currently subject to kicking. Make one result per pubkey.
+    const reducables = Indexer.DUP_HELPERS.reduceBy(await this.sqlFind({ kick: true }), ['pub']);
+    // We get the full representation for each member
+    const reduced = await Promise.all(reducables.map(async (entry) => {
+      const reducable = await this.reducable(entry.pub);
+      return Indexer.DUP_HELPERS.reduce(reducable);
+    }))
+    // Filter on those to be kicked, return their pubkey
+    return _.filter(reduced, (entry:IindexEntry) => entry.kick).map((entry:IindexEntry) => entry.pub);
+  }
+
+  async searchThoseMatching(search:string) {
+    const reducables = Indexer.DUP_HELPERS.reduceBy(await this.sqlFindLikeAny({
+        pub: "%" + search + "%",
+        uid: "%" + search + "%"
+      }), ['pub']);
+    // We get the full representation for each member
+    return await Promise.all(reducables.map(async (entry) => {
+      return this.toCorrectEntity(Indexer.DUP_HELPERS.reduce(await this.reducable(entry.pub)))
+    }))
+  }
+
+  getFromPubkey(pubkey:string) {
+    return this.entityOrNull('pub', pubkey)
+  }
+
+  getFromUID(uid:string) {
+    return this.entityOrNull('uid', uid)
+  }
+
+  getFromHash(hash:string) {
+    return this.entityOrNull('hash', hash, true)
+  }
+
+  reducable(pub:string) {
+    return this.query('SELECT * FROM ' + this.table + ' WHERE pub = ? ORDER BY CAST(written_on as integer) ASC', [pub])
+  }
+
+  removeBlock(blockstamp:string) {
+    return this.exec('DELETE FROM ' + this.table + ' WHERE written_on = \'' + blockstamp + '\'')
+  }
+
+  private async entityOrNull(field:string, value:any, retrieveOnField:boolean = false) {
+    let reducable = await this.query('SELECT * FROM ' + this.table + ' WHERE ' + field + ' = ?', [value]);
+    if (reducable.length) {
+      if (retrieveOnField) {
+        // Force full retrieval on `pub` field
+        reducable = await this.query('SELECT * FROM ' + this.table + ' WHERE pub = ? ORDER BY CAST(written_on as int) ASC', [reducable[0].pub]);
+      }
+      return this.toCorrectEntity(Indexer.DUP_HELPERS.reduce(reducable));
+    }
+    return null;
+  }
+
+  private toCorrectEntity(row:IindexEntry): OldIindexEntry {
+    // Old field
+    return {
+      pubkey: row.pub,
+      pub: row.pub,
+      buid: row.created_on,
+      revocation_sig: null,
+      uid: row.uid,
+      hash: row.hash,
+      sig: row.sig,
+      created_on: row.created_on,
+      member: row.member,
+      wasMember: row.wasMember,
+      kick: row.kick,
+      wotb_id: row.wotb_id,
+      age: row.age,
+      index: row.index,
+      op: row.op,
+      writtenOn: row.writtenOn,
+      written_on: row.written_on
+    }
+  }
+}
diff --git a/app/lib/dal/sqliteDAL/index/MIndexDAL.js b/app/lib/dal/sqliteDAL/index/MIndexDAL.js
deleted file mode 100644
index 77faa633d..000000000
--- a/app/lib/dal/sqliteDAL/index/MIndexDAL.js
+++ /dev/null
@@ -1,72 +0,0 @@
-/**
- * Created by cgeek on 22/08/15.
- */
-
-const co = require('co');
-const indexer         = require('../../../indexer').Indexer
-const AbstractSQLite = require('./../AbstractSQLite');
-const AbstractIndex = require('./../AbstractIndex');
-
-module.exports = MIndexDAL;
-
-function MIndexDAL(driver) {
-
-  "use strict";
-
-  AbstractSQLite.call(this, driver);
-  AbstractIndex.call(this);
-
-  const that = this;
-
-  this.table = 'm_index';
-  this.fields = [
-    'op',
-    'pub',
-    'created_on',
-    'written_on',
-    'writtenOn',
-    'expires_on',
-    'expired_on',
-    'revokes_on',
-    'revoked_on',
-    'chainable_on',
-    'leaving',
-    'revocation'
-  ];
-  this.arrays = [];
-  this.bigintegers = [];
-  this.booleans = ['leaving'];
-  this.pkFields = ['op', 'pub', 'created_on', 'written_on'];
-  this.translated = {};
-
-  this.init = () => co(function *() {
-    return that.exec('BEGIN;' +
-      'CREATE TABLE IF NOT EXISTS ' + that.table + ' (' +
-      'op VARCHAR(10) NOT NULL,' +
-      'pub VARCHAR(50) NOT NULL,' +
-      'created_on VARCHAR(80) NOT NULL,' +
-      'written_on VARCHAR(80) NOT NULL,' +
-      'expires_on INTEGER NULL,' +
-      'expired_on INTEGER NULL,' +
-      'revokes_on INTEGER NULL,' +
-      'revoked_on INTEGER NULL,' +
-      'leaving BOOLEAN NULL,' +
-      'revocation VARCHAR(80) NULL,' +
-      'PRIMARY KEY (op,pub,created_on,written_on)' +
-      ');' +
-      'CREATE INDEX IF NOT EXISTS idx_mindex_pub ON m_index (pub);' +
-      'COMMIT;', []);
-  });
-
-  this.getReducedMS = (pub) => co(function*() {
-    const reducables = yield that.reducable(pub);
-    if (reducables.length) {
-      return indexer.DUP_HELPERS.reduce(reducables);
-    }
-    return null;
-  });
-
-  this.reducable = (pub) => this.query('SELECT * FROM ' + this.table + ' WHERE pub = ? ORDER BY CAST(written_on as integer) ASC', [pub]);
-
-  this.removeBlock = (blockstamp) => that.exec('DELETE FROM ' + that.table + ' WHERE written_on = \'' + blockstamp + '\'');
-}
diff --git a/app/lib/dal/sqliteDAL/index/MIndexDAL.ts b/app/lib/dal/sqliteDAL/index/MIndexDAL.ts
new file mode 100644
index 000000000..7f3e151a9
--- /dev/null
+++ b/app/lib/dal/sqliteDAL/index/MIndexDAL.ts
@@ -0,0 +1,73 @@
+import {SQLiteDriver} from "../../drivers/SQLiteDriver";
+import {AbstractIndex} from "../AbstractIndex";
+import {Indexer, MindexEntry} from "../../../indexer";
+
+export class MIndexDAL extends AbstractIndex<MindexEntry> {
+
+  constructor(driver:SQLiteDriver) {
+    super(
+      driver,
+      'm_index',
+      // PK fields
+      ['op', 'pub', 'created_on', 'written_on'],
+      // Fields
+      [
+        'op',
+        'pub',
+        'created_on',
+        'written_on',
+        'writtenOn',
+        'expires_on',
+        'expired_on',
+        'revokes_on',
+        'revoked_on',
+        'chainable_on',
+        'leaving',
+        'revocation'
+      ],
+      // Arrays
+      [],
+      // Booleans
+      ['leaving'],
+      // BigIntegers
+      [],
+      // Transient
+      []
+    )
+  }
+
+  async init() {
+    await this.exec('BEGIN;' +
+      'CREATE TABLE IF NOT EXISTS ' + this.table + ' (' +
+      'op VARCHAR(10) NOT NULL,' +
+      'pub VARCHAR(50) NOT NULL,' +
+      'created_on VARCHAR(80) NOT NULL,' +
+      'written_on VARCHAR(80) NOT NULL,' +
+      'expires_on INTEGER NULL,' +
+      'expired_on INTEGER NULL,' +
+      'revokes_on INTEGER NULL,' +
+      'revoked_on INTEGER NULL,' +
+      'leaving BOOLEAN NULL,' +
+      'revocation VARCHAR(80) NULL,' +
+      'PRIMARY KEY (op,pub,created_on,written_on)' +
+      ');' +
+      'CREATE INDEX IF NOT EXISTS idx_mindex_pub ON m_index (pub);' +
+      'COMMIT;')
+  }
+
+  async getReducedMS(pub:string) {
+    const reducables = await this.reducable(pub);
+    if (reducables.length) {
+      return Indexer.DUP_HELPERS.reduce(reducables);
+    }
+    return null;
+  }
+
+  reducable(pub:string) {
+    return this.query('SELECT * FROM ' + this.table + ' WHERE pub = ? ORDER BY CAST(written_on as integer) ASC', [pub])
+}
+
+  async removeBlock(blockstamp:string) {
+    return this.exec('DELETE FROM ' + this.table + ' WHERE written_on = \'' + blockstamp + '\'')
+  }
+}
diff --git a/app/lib/dal/sqliteDAL/index/SIndexDAL.js b/app/lib/dal/sqliteDAL/index/SIndexDAL.js
deleted file mode 100644
index f5e5e8413..000000000
--- a/app/lib/dal/sqliteDAL/index/SIndexDAL.js
+++ /dev/null
@@ -1,128 +0,0 @@
-/**
- * Created by cgeek on 22/08/15.
- */
-
-const _ = require('underscore');
-const co = require('co');
-const common = require('duniter-common');
-const indexer         = require('../../../indexer').Indexer
-const constants = require('../../../constants');
-const AbstractSQLite = require('./../AbstractSQLite');
-const AbstractIndex = require('./../AbstractIndex');
-
-module.exports = SIndexDAL;
-
-function SIndexDAL(driver) {
-
-  "use strict";
-
-  AbstractSQLite.call(this, driver);
-  AbstractIndex.call(this, driver);
-
-  const that = this;
-
-  this.table = 's_index';
-  this.fields = [
-    'op',
-    'tx',
-    'identifier',
-    'pos',
-    'created_on',
-    'written_on',
-    'writtenOn',
-    'written_time',
-    'amount',
-    'base',
-    'locktime',
-    'consumed',
-    'conditions'
-  ];
-  this.arrays = [];
-  this.bigintegers = [];
-  this.booleans = ['consumed'];
-  this.pkFields = ['op', 'identifier', 'pos', 'written_on'];
-  this.translated = {};
-
-  this.init = () => co(function *() {
-    return that.exec('BEGIN;' +
-      'CREATE TABLE IF NOT EXISTS ' + that.table + ' (' +
-      'op VARCHAR(10) NOT NULL,' +
-      'tx VARCHAR(80) NULL,' +
-      'identifier VARCHAR(64) NOT NULL,' +
-      'pos INTEGER NOT NULL,' +
-      'created_on VARCHAR(80) NULL,' +
-      'written_on VARCHAR(80) NOT NULL,' +
-      'written_time INTEGER NOT NULL,' +
-      'amount INTEGER NULL,' +
-      'base INTEGER NULL,' +
-      'locktime INTEGER NULL,' +
-      'consumed BOOLEAN NOT NULL,' +
-      'conditions TEXT,' +
-      'PRIMARY KEY (op,identifier,pos,written_on)' +
-      ');' +
-      'CREATE INDEX IF NOT EXISTS idx_sindex_identifier ON s_index (identifier);' +
-      'CREATE INDEX IF NOT EXISTS idx_sindex_pos ON s_index (pos);' +
-      'COMMIT;', []);
-  });
-
-  this.removeBlock = (blockstamp) => that.exec('DELETE FROM ' + that.table + ' WHERE written_on = \'' + blockstamp + '\'');
-
-  this.getSource = (identifier, pos) => co(function*() {
-    const reducable = yield that.query('SELECT * FROM ' + that.table + ' s1 ' +
-      'WHERE s1.identifier = ? ' +
-      'AND s1.pos = ? ' +
-      'ORDER BY op ASC', [identifier, pos]);
-    if (reducable.length == 0) {
-      return null;
-    } else {
-      const src = indexer.DUP_HELPERS.reduce(reducable);
-      src.type = src.tx ? 'T' : 'D';
-      return src;
-    }
-  });
-
-  this.getUDSources = (pubkey) => co(function*() {
-    const reducables = yield that.query('SELECT * FROM ' + that.table + ' s1 ' +
-      'WHERE conditions = ? ' +
-      'AND s1.tx IS NULL ' +
-      'ORDER BY op ASC', ['SIG(' + pubkey + ')']);
-    const reduced = indexer.DUP_HELPERS.reduceBy(reducables, ['identifier', 'pos']).map((src) => {
-      src.type = src.tx ? 'T' : 'D';
-      return src;
-    });
-    return _.sortBy(reduced, (row) => row.type == 'D' ? 0 : 1);
-  });
-
-  this.getAvailableForPubkey = (pubkey) => this.getAvailableForConditions('%SIG(' + pubkey + ')%');
-
-  this.getAvailableForConditions = (conditionsStr) => co(function*() {
-    const potentials = yield that.query('SELECT * FROM ' + that.table + ' s1 ' +
-      'WHERE s1.op = ? ' +
-      'AND conditions LIKE ? ' +
-      'AND NOT EXISTS (' +
-      ' SELECT * ' +
-      ' FROM s_index s2 ' +
-      ' WHERE s2.identifier = s1.identifier ' +
-      ' AND s2.pos = s1.pos ' +
-      ' AND s2.op = ?' +
-      ') ' +
-      'ORDER BY CAST(SUBSTR(written_on, 0, INSTR(written_on, "-")) as number)', [common.constants.IDX_CREATE, conditionsStr, common.constants.IDX_UPDATE]);
-    const sources = potentials.map((src) => {
-      src.type = src.tx ? 'T' : 'D';
-      return src;
-    });
-    return _.sortBy(sources, (row) => row.type == 'D' ? 0 : 1);
-  });
-
-  this.trimConsumedSource = (belowNumber) => co(function*() {
-    const toDelete = yield that.query('SELECT * FROM ' + that.table + ' WHERE consumed AND CAST(written_on as int) < ?', [belowNumber]);
-    const queries = [];
-    for (const row of toDelete) {
-      const sql = "DELETE FROM " + that.table + " " +
-        "WHERE identifier like '" + row.identifier + "' " +
-        "AND pos = " + row.pos;
-      queries.push(sql);
-    }
-    yield that.exec(queries.join(';\n'));
-  });
-}
diff --git a/app/lib/dal/sqliteDAL/index/SIndexDAL.ts b/app/lib/dal/sqliteDAL/index/SIndexDAL.ts
new file mode 100644
index 000000000..13b0c04e3
--- /dev/null
+++ b/app/lib/dal/sqliteDAL/index/SIndexDAL.ts
@@ -0,0 +1,129 @@
+import {Indexer, SindexEntry} from "../../../indexer";
+import {SQLiteDriver} from "../../drivers/SQLiteDriver";
+import {AbstractIndex} from "../AbstractIndex";
+const _ = require('underscore');
+const common = require('duniter-common');
+const constants = require('../../../constants');
+
+export class SIndexDAL extends AbstractIndex<SindexEntry> {
+
+  constructor(driver:SQLiteDriver) {
+    super(
+      driver,
+      's_index',
+      // PK fields
+      ['op', 'identifier', 'pos', 'written_on'],
+      // Fields
+      [
+        'op',
+        'tx',
+        'identifier',
+        'pos',
+        'created_on',
+        'written_on',
+        'writtenOn',
+        'written_time',
+        'amount',
+        'base',
+        'locktime',
+        'consumed',
+        'conditions'
+      ],
+      // Arrays
+      [],
+      // Booleans
+      ['consumed'],
+      // BigIntegers
+      [],
+      // Transient
+      []
+    )
+  }
+
+  async init() {
+    await this.exec('BEGIN;' +
+      'CREATE TABLE IF NOT EXISTS ' + this.table + ' (' +
+      'op VARCHAR(10) NOT NULL,' +
+      'tx VARCHAR(80) NULL,' +
+      'identifier VARCHAR(64) NOT NULL,' +
+      'pos INTEGER NOT NULL,' +
+      'created_on VARCHAR(80) NULL,' +
+      'written_on VARCHAR(80) NOT NULL,' +
+      'written_time INTEGER NOT NULL,' +
+      'amount INTEGER NULL,' +
+      'base INTEGER NULL,' +
+      'locktime INTEGER NULL,' +
+      'consumed BOOLEAN NOT NULL,' +
+      'conditions TEXT,' +
+      'PRIMARY KEY (op,identifier,pos,written_on)' +
+      ');' +
+      'CREATE INDEX IF NOT EXISTS idx_sindex_identifier ON s_index (identifier);' +
+      'CREATE INDEX IF NOT EXISTS idx_sindex_pos ON s_index (pos);' +
+      'COMMIT;')
+  }
+
+  async removeBlock(blockstamp:string) {
+    await this.exec('DELETE FROM ' + this.table + ' WHERE written_on = \'' + blockstamp + '\'')
+  }
+
+  async getSource(identifier:string, pos:number) {
+    const reducable = await this.query('SELECT * FROM ' + this.table + ' s1 ' +
+      'WHERE s1.identifier = ? ' +
+      'AND s1.pos = ? ' +
+      'ORDER BY op ASC', [identifier, pos]);
+    if (reducable.length == 0) {
+      return null;
+    } else {
+      const src = Indexer.DUP_HELPERS.reduce(reducable);
+      src.type = src.tx ? 'T' : 'D';
+      return src;
+    }
+  }
+
+  async getUDSources(pubkey:string) {
+    const reducables = await this.query('SELECT * FROM ' + this.table + ' s1 ' +
+      'WHERE conditions = ? ' +
+      'AND s1.tx IS NULL ' +
+      'ORDER BY op ASC', ['SIG(' + pubkey + ')']);
+    const reduced = Indexer.DUP_HELPERS.reduceBy(reducables, ['identifier', 'pos']).map((src) => {
+      src.type = src.tx ? 'T' : 'D';
+      return src;
+    });
+    return _.sortBy(reduced, (row:SindexEntry) => row.type == 'D' ? 0 : 1);
+  }
+
+  getAvailableForPubkey(pubkey:string) {
+    return this.getAvailableForConditions('%SIG(' + pubkey + ')%')
+  }
+
+  async getAvailableForConditions(conditionsStr:string) {
+    const potentials = await this.query('SELECT * FROM ' + this.table + ' s1 ' +
+      'WHERE s1.op = ? ' +
+      'AND conditions LIKE ? ' +
+      'AND NOT EXISTS (' +
+      ' SELECT * ' +
+      ' FROM s_index s2 ' +
+      ' WHERE s2.identifier = s1.identifier ' +
+      ' AND s2.pos = s1.pos ' +
+      ' AND s2.op = ?' +
+      ') ' +
+      'ORDER BY CAST(SUBSTR(written_on, 0, INSTR(written_on, "-")) as number)', [common.constants.IDX_CREATE, conditionsStr, common.constants.IDX_UPDATE]);
+    const sources = potentials.map((src) => {
+      src.type = src.tx ? 'T' : 'D';
+      return src;
+    });
+    return _.sortBy(sources, (row:SindexEntry) => row.type == 'D' ? 0 : 1);
+  }
+
+  async trimConsumedSource(belowNumber:number) {
+    const toDelete = await this.query('SELECT * FROM ' + this.table + ' WHERE consumed AND CAST(written_on as int) < ?', [belowNumber]);
+    const queries = [];
+    for (const row of toDelete) {
+      const sql = "DELETE FROM " + this.table + " " +
+        "WHERE identifier like '" + row.identifier + "' " +
+        "AND pos = " + row.pos;
+      queries.push(sql);
+    }
+    await this.exec(queries.join(';\n'));
+  }
+}
diff --git a/app/lib/db/DBTransaction.ts b/app/lib/db/DBTransaction.ts
index 1a012e98d..9e0a7c82f 100644
--- a/app/lib/db/DBTransaction.ts
+++ b/app/lib/db/DBTransaction.ts
@@ -26,6 +26,7 @@ export class DBTransaction extends TransactionDTO {
       locktime,
       hash,
       blockstamp,
+      blockstampTime,
       issuers,
       inputs,
       outputs,
diff --git a/app/lib/dto/ConfDTO.ts b/app/lib/dto/ConfDTO.ts
index 66cfca0d7..6b135ca6a 100644
--- a/app/lib/dto/ConfDTO.ts
+++ b/app/lib/dto/ConfDTO.ts
@@ -32,4 +32,8 @@ export class ConfDTO {
     public msWindow: number,
     public sigWindow: number,
 ) {}
+
+  static mock() {
+    return new ConfDTO("", [], [], 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)
+  }
 }
\ No newline at end of file
diff --git a/app/lib/dto/TransactionDTO.ts b/app/lib/dto/TransactionDTO.ts
index 2bd4ea0d2..70ea23cba 100644
--- a/app/lib/dto/TransactionDTO.ts
+++ b/app/lib/dto/TransactionDTO.ts
@@ -28,12 +28,13 @@ export class TransactionDTO {
     public locktime: number,
     public hash: string,
     public blockstamp: string,
+    public blockstampTime: number,
     public issuers: string[],
     public inputs: string[],
     public outputs: string[],
     public unlocks: string[],
     public signatures: string[],
-    public comment?: string
+    public comment: string
   ) {
     // Compute the hash if not given
     if (!hash) {
@@ -76,6 +77,13 @@ export class TransactionDTO {
     })
   }
 
+  outputsAsRecipients(): string[] {
+    return this.outputs.map((out) => {
+      const recipent = out.match('SIG\\((.*)\\)');
+      return (recipent && recipent[1]) || 'UNKNOWN';
+    })
+  }
+
   getCompactVersion() {
     let issuers = this.issuers;
     let raw = ["TX", this.version, issuers.length, this.inputs.length, this.unlocks.length, this.outputs.length, this.comment ? 1 : 0, this.locktime || 0].join(':') + '\n';
@@ -102,17 +110,18 @@ export class TransactionDTO {
 
   static fromJSONObject(obj:any) {
     return new TransactionDTO(
-      obj.version,
-      obj.currency,
-      obj.locktime,
-      obj.hash,
-      obj.blockstamp,
-      obj.issuers,
-      obj.inputs,
-      obj.outputs,
-      obj.unlocks,
-      obj.signatures,
-      obj.comment
+      obj.version || 10,
+      obj.currency || "",
+      obj.locktime || 0,
+      obj.hash || "",
+      obj.blockstamp || "",
+      obj.blockstampTime || 0,
+      obj.issuers || [],
+      obj.inputs || [],
+      obj.outputs || [],
+      obj.unlocks || [],
+      obj.signatures || [],
+      obj.comment || ""
     )
   }
 
@@ -147,4 +156,8 @@ export class TransactionDTO {
     }
     return raw
   }
+
+  static mock() {
+    return new TransactionDTO(1, "", 0, "", "", 0, [], [], [], [], [], "")
+  }
 }
\ No newline at end of file
diff --git a/app/lib/indexer.ts b/app/lib/indexer.ts
index 7806e7308..785ef39a4 100644
--- a/app/lib/indexer.ts
+++ b/app/lib/indexer.ts
@@ -60,14 +60,13 @@ export interface IindexEntry extends IndexEntry {
   member: boolean,
   wasMember: boolean | null,
   kick: boolean | null,
-  wid: number | null,
+  wotb_id: number | null,
   age: number,
   pubUnique?: boolean,
   excludedIsMember?: boolean,
   isBeingKicked?: boolean,
   uidUnique?: boolean,
   hasToBeExcluded?: boolean,
-  wotb_id?: number,
 }
 
 export interface CindexEntry extends IndexEntry {
@@ -105,6 +104,7 @@ export interface SindexEntry extends IndexEntry {
   consumed: boolean,
   txObj: TransactionDTO,
   age: number,
+  type?: string,
   available?: boolean,
   isLocked?: boolean,
   isTimeLocked?: boolean,
@@ -168,7 +168,7 @@ export class Indexer {
         member: true,
         wasMember: true,
         kick: false,
-        wid: null // wotb id
+        wotb_id: null
       })
     }
 
@@ -233,7 +233,7 @@ export class Indexer {
           member: true,
           wasMember: null,
           kick: null,
-          wid: null
+          wotb_id: null
         })
       }
     }
@@ -320,7 +320,7 @@ export class Indexer {
         member: false,
         wasMember: null,
         kick: false,
-        wid: null
+        wotb_id: null
       });
     }
 
@@ -1830,7 +1830,7 @@ function reduce(records: any[]) {
   }, {});
 }
 
-function reduceBy(reducables: SindexEntry[], properties: string[]): any[] {
+function reduceBy(reducables: IndexEntry[], properties: string[]): any[] {
   const reduced = reducables.reduce((map: any, entry: any) => {
     const id = properties.map((prop) => entry[prop]).join('-');
     map[id] = map[id] || [];
diff --git a/test/blockchain/basic-blockchain.ts b/test/blockchain/basic-blockchain.ts
index 9869d3ee9..45b42adf5 100644
--- a/test/blockchain/basic-blockchain.ts
+++ b/test/blockchain/basic-blockchain.ts
@@ -2,10 +2,11 @@ import {BasicBlockchain} from "../../app/lib/blockchain/BasicBlockchain"
 import {ArrayBlockchain} from "./lib/ArrayBlockchain"
 import {SQLBlockchain} from "../../app/lib/blockchain/SqlBlockchain"
 import {SQLiteDriver} from "../../app/lib/dal/drivers/SQLiteDriver"
+import {BIndexDAL} from "../../app/lib/dal/sqliteDAL/index/BIndexDAL";
+import {MetaDAL} from "../../app/lib/dal/sqliteDAL/MetaDAL";
+import {ConfDTO} from "../../app/lib/dto/ConfDTO";
 
 const assert = require('assert')
-const BIndexDAL = require('../../app/lib/dal/sqliteDAL/index/BIndexDAL')
-const MetaDAL = require('../../app/lib/dal/sqliteDAL/MetaDAL')
 
 let blockchain:BasicBlockchain,
   emptyBlockchain:BasicBlockchain
@@ -83,7 +84,7 @@ describe('Basic SQL Blockchain', () => {
       await metaDAL.exec('CREATE TABLE cert (id INTEGER null);')
       await metaDAL.exec('CREATE TABLE membership (id INTEGER null);')
       await metaDAL.exec('CREATE TABLE block (fork INTEGER null);')
-      await metaDAL.upgradeDatabase({});
+      await metaDAL.upgradeDatabase(ConfDTO.mock());
 
       const dal = { bindexDAL }
 
@@ -102,7 +103,7 @@ describe('Basic SQL Blockchain', () => {
       await metaDAL.exec('CREATE TABLE cert (id INTEGER null);')
       await metaDAL.exec('CREATE TABLE membership (id INTEGER null);')
       await metaDAL.exec('CREATE TABLE block (fork INTEGER null);')
-      await metaDAL.upgradeDatabase({});
+      await metaDAL.upgradeDatabase(ConfDTO.mock());
 
       const dal = { bindexDAL }
 
diff --git a/test/blockchain/misc-sql-blockchain.ts b/test/blockchain/misc-sql-blockchain.ts
index 1b2988ff2..3f80bf5b9 100644
--- a/test/blockchain/misc-sql-blockchain.ts
+++ b/test/blockchain/misc-sql-blockchain.ts
@@ -2,13 +2,14 @@
 import {MiscIndexedBlockchain} from "../../app/lib/blockchain/MiscIndexedBlockchain"
 import {ArrayBlockchain} from "./lib/ArrayBlockchain"
 import {SQLiteDriver} from "../../app/lib/dal/drivers/SQLiteDriver"
+import {MIndexDAL} from "../../app/lib/dal/sqliteDAL/index/MIndexDAL";
+import {IIndexDAL} from "../../app/lib/dal/sqliteDAL/index/IIndexDAL";
+import {SIndexDAL} from "../../app/lib/dal/sqliteDAL/index/SIndexDAL";
+import {CIndexDAL} from "../../app/lib/dal/sqliteDAL/index/CIndexDAL";
+import {MetaDAL} from "../../app/lib/dal/sqliteDAL/MetaDAL";
+import {ConfDTO} from "../../app/lib/dto/ConfDTO";
 
 const assert = require('assert')
-const MIndexDAL = require('../../app/lib/dal/sqliteDAL/index/MIndexDAL')
-const IIndexDAL = require('../../app/lib/dal/sqliteDAL/index/IIndexDAL')
-const SIndexDAL = require('../../app/lib/dal/sqliteDAL/index/SIndexDAL')
-const CIndexDAL = require('../../app/lib/dal/sqliteDAL/index/CIndexDAL')
-const MetaDAL = require('../../app/lib/dal/sqliteDAL/MetaDAL')
 
 describe('MISC SQL Blockchain', () => {
 
@@ -24,8 +25,8 @@ describe('MISC SQL Blockchain', () => {
     const cindexDAL = new CIndexDAL(db)
     const metaDAL = new MetaDAL(db)
 
-    await mindexDAL.init()
     await iindexDAL.init()
+    await mindexDAL.init()
     await sindexDAL.init()
     await cindexDAL.init()
     await metaDAL.init()
@@ -36,7 +37,7 @@ describe('MISC SQL Blockchain', () => {
     await metaDAL.exec('CREATE TABLE membership (id INTEGER null);')
     await metaDAL.exec('CREATE TABLE block (fork INTEGER null);')
     await metaDAL.exec('CREATE TABLE b_index (id INTEGER null);')
-    await metaDAL.upgradeDatabase({});
+    await metaDAL.upgradeDatabase(ConfDTO.mock());
 
     blockchain = new MiscIndexedBlockchain(new ArrayBlockchain(), mindexDAL, iindexDAL, sindexDAL, cindexDAL)
   })
-- 
GitLab