diff --git a/app/lib/common-libs/moment.ts b/app/lib/common-libs/moment.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ca05144233a3364fc44985f8cee8947870af7521
--- /dev/null
+++ b/app/lib/common-libs/moment.ts
@@ -0,0 +1,16 @@
+// Source file from duniter: Crypto-currency software to manage libre currency such as Äž1
+// Copyright (C) 2018  Cedric Moreau <cem.moreau@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+
+const _moment_ = require("moment")
+
+export const moment = _moment_
\ No newline at end of file
diff --git a/app/lib/dal/fileDAL.ts b/app/lib/dal/fileDAL.ts
index 256d93cbff504c377b2a15aae3d77bde615fdafb..12a07818d173ba48de018c999a192eee6b13d421 100644
--- a/app/lib/dal/fileDAL.ts
+++ b/app/lib/dal/fileDAL.ts
@@ -326,6 +326,11 @@ export class FileDAL {
     return (await this.blockDAL.getAbsoluteBlock(number, hash)) || (await this.blockchainArchiveDAL.getBlock(number, hash))
   }
 
+  async getAbsoluteBlockByBlockstamp(blockstamp: string): Promise<DBBlock|null> {
+    const sp = blockstamp.split('-')
+    return this.getAbsoluteBlockByNumberAndHash(parseInt(sp[0]), sp[1])
+  }
+
   async existsNonChainableLink(from:string, vHEAD_1:DBHead, sigStock:number) {
     // Cert period rule
     const medianTime = vHEAD_1 ? vHEAD_1.medianTime : 0;
diff --git a/app/lib/dal/indexDAL/abstract/GenericDAO.ts b/app/lib/dal/indexDAL/abstract/GenericDAO.ts
index 500899136bffbaf86ff136b4b8c2c3dc342d3704..12ada2d2819ac5f280283e17b0f5a9f5b874d5c2 100644
--- a/app/lib/dal/indexDAL/abstract/GenericDAO.ts
+++ b/app/lib/dal/indexDAL/abstract/GenericDAO.ts
@@ -20,7 +20,7 @@ export interface GenericDAO<T> extends Initiable {
    * @param sort A LokiJS's compunded sort object.
    * @returns {Promise<any>} A set of records.
    */
-  findRawWithOrder(criterion: any, sort:((string|((string|boolean)[]))[])): Promise<any>
+  findRawWithOrder(criterion: any, sort:((string|((string|boolean)[]))[])): Promise<T[]>
 
   /**
    * Make a single insert.
diff --git a/app/modules/dump.ts b/app/modules/dump.ts
index 3ebba35e3057b43b2834c7d11db43810f96a5641..5d3aae6907b2ea300c844246b5587bda46fc285e 100644
--- a/app/modules/dump.ts
+++ b/app/modules/dump.ts
@@ -13,13 +13,15 @@
 
 import {ConfDTO} from "../lib/dto/ConfDTO"
 import {Server} from "../../server"
+import {moment} from "../lib/common-libs/moment"
+import {DBBlock} from "../lib/db/DBBlock"
 
-const Table = require('cli-table');
+const Table = require('cli-table')
 
 module.exports = {
   duniter: {
     cli: [{
-      name: 'dump [what] [name]',
+      name: 'dump [what] [name] [cond]',
       desc: 'Dumps data of the blockchain.',
       logs: false,
       preventIfRunning: true,
@@ -27,31 +29,15 @@ module.exports = {
       onDatabaseExecute: async (server:Server, conf:ConfDTO, program:any, params:any) => {
         const what: string = params[0] || ''
         const name: string = params[1] || ''
+        const cond: string = params[2] || ''
         switch (what) {
 
           case 'table':
-            let rows: any[]
-            switch (name) {
-              case 'i_index':
-                rows = await server.dal.iindexDAL.findRawWithOrder({}, [['writtenOn', false], ['wotb_id', false]])
-                dump(rows, (program.dbgOmitCols || "").split(',').concat('index', 'meta', '$loki', 'writtenOn', 'age'))
-                break
-              case 'm_index':
-                rows = await server.dal.mindexDAL.findRawWithOrder({}, [['writtenOn', false], ['pub', false]])
-                dump(rows, ['op','pub','created_on','written_on','expires_on','expired_on','revokes_on','revoked_on','leaving','revocation','chainable_on'])
-                break
-              case 'c_index':
-                rows = await server.dal.cindexDAL.findRawWithOrder({}, [['writtenOn', false], ['issuer', false], ['receiver', false]])
-                dump(rows, ['op','issuer','receiver','created_on','written_on','sig','expires_on','expired_on','chainable_on','from_wid','to_wid'])
-                break
-              case 's_index':
-                rows = await server.dal.sindexDAL.findRawWithOrder({}, [['writtenOn', false], ['identifier', false], ['pos', false]])
-                dump(rows, ['op','tx','identifier','pos','created_on','written_on','written_time','amount','base','locktime','consumed','conditions'])
-                break
-              default:
-                console.error(`Unknown dump table ${name}`)
-                break
-            }
+            await dumpTable(server, name, cond)
+            break
+
+          case 'history':
+            await dumpHistory(server, name)
             break
 
           default:
@@ -65,6 +51,46 @@ module.exports = {
   }
 }
 
+async function dumpTable(server: Server, name: string, condition?: string) {
+  const criterion: any = {}
+  const filters = condition && condition.split(',') || []
+  for (const f of filters) {
+    const k = f.split('=')[0]
+    const v = f.split('=')[1]
+    if (v === 'true' || v === 'false') {
+      criterion[k] = v === 'true' ? true : 0
+    } else if (v === 'NULL') {
+      criterion[k] = null
+    } else if (v.match(/^\d+$/)) {
+      criterion[k] = parseInt(v)
+    } else {
+      criterion[k] = v
+    }
+  }
+  let rows: any[]
+  switch (name) {
+    case 'i_index':
+      rows = await server.dal.iindexDAL.findRawWithOrder(criterion, [['writtenOn', false], ['wotb_id', false]])
+      dump(rows, ['op','uid','pub','hash','sig','created_on','written_on','member','wasMember','kick','wotb_id'])
+      break
+    case 'm_index':
+      rows = await server.dal.mindexDAL.findRawWithOrder(criterion, [['writtenOn', false], ['pub', false]])
+      dump(rows, ['op','pub','created_on','written_on','expires_on','expired_on','revokes_on','revoked_on','leaving','revocation','chainable_on'])
+      break
+    case 'c_index':
+      rows = await server.dal.cindexDAL.findRawWithOrder(criterion, [['writtenOn', false], ['issuer', false], ['receiver', false]])
+      dump(rows, ['op','issuer','receiver','created_on','written_on','sig','expires_on','expired_on','chainable_on','from_wid','to_wid'])
+      break
+    case 's_index':
+      rows = await server.dal.sindexDAL.findRawWithOrder(criterion, [['writtenOn', false], ['identifier', false], ['pos', false]])
+      dump(rows, ['op','tx','identifier','pos','created_on','written_on','written_time','amount','base','locktime','consumed','conditions'])
+      break
+    default:
+      console.error(`Unknown dump table ${name}`)
+      break
+  }
+}
+
 function dump(rows: any[], columns: string[]) {
   // Table columns
   const t = new Table({
@@ -91,3 +117,45 @@ function dump(rows: any[], columns: string[]) {
     console.error(e)
   }
 }
+
+async function dumpHistory(server: Server, pub: string) {
+  const irows = await server.dal.iindexDAL.findRawWithOrder({ pub }, [['writtenOn', false]])
+  const mrows = await server.dal.mindexDAL.findRawWithOrder({ pub }, [['writtenOn', false]])
+  console.log('----- IDENTITY -----')
+  for (const e of irows) {
+    const date = await getDateFor(server, e.written_on)
+    if (e.uid) {
+      console.log('%s: new identity %s (created on %s)', date, e.uid, await getDateFor(server, e.created_on as string))
+    } else if (e.member) {
+      console.log('%s: comeback', date)
+    } else if (e.kick) {
+      // console.log('%s: being kicked... (either)', date)
+    } else if (e.member === false) {
+      console.log('%s: excluded', date)
+    } else {
+      console.log('Non displayable IINDEX entry')
+    }
+  }
+  console.log('----- MEMBERSHIP -----')
+  for (const e of mrows) {
+    const date = await getDateFor(server, e.written_on)
+    if (e.chainable_on) {
+      console.log('%s: join/renew', date)
+    } else if (e.expired_on) {
+      console.log('%s: expired', date)
+    } else {
+      console.log('Non displayable MINDEX entry')
+    }
+  }
+}
+
+async function getDateFor(server: Server, blockstamp: string) {
+  const b = (await server.dal.getAbsoluteBlockByBlockstamp(blockstamp)) as DBBlock
+  const s = "         " + b.number
+  const bnumberPadded = s.substr(s.length - 6)
+  return formatTimestamp(b.medianTime) + ' (#' + bnumberPadded + ')'
+}
+
+function formatTimestamp(ts: number) {
+  return moment(ts * 1000).format('YYYY-MM-DD hh:mm:ss')
+}
\ No newline at end of file