diff --git a/app/lib/common-libs/errors.ts b/app/lib/common-libs/errors.ts
index d44e0f6eadc87a6f1b7594e9e753251c3735a6fa..358152eda0d8b52502a3ebc0fd220d488fa7cc19 100755
--- a/app/lib/common-libs/errors.ts
+++ b/app/lib/common-libs/errors.ts
@@ -1,5 +1,9 @@
 
 export enum DataErrors {
+  WRONG_CURRENCY_DETECTED,
+  NO_PEERING_AVAILABLE_FOR_SYNC,
+  REMOTE_HAS_NO_CURRENT_BLOCK,
+  CANNOT_CONNECT_TO_REMOTE_FOR_SYNC,
   WS2P_SYNC_PERIMETER_IS_LIMITED,
   PEER_REJECTED,
   TOO_OLD_PEER,
diff --git a/app/lib/other_constants.ts b/app/lib/other_constants.ts
index 2b0139b508162b43c0d3948f0738687386b8d16b..3f62a541231e5ccea2efc85a39e1084bec9d360d 100644
--- a/app/lib/other_constants.ts
+++ b/app/lib/other_constants.ts
@@ -13,7 +13,7 @@
 
 export const OtherConstants = {
 
-  MUTE_LOGS_DURING_UNIT_TESTS: true,
+  MUTE_LOGS_DURING_UNIT_TESTS: false,
   SQL_TRACES: false,
 
   BC_EVENT: {
diff --git a/app/modules/crawler/index.ts b/app/modules/crawler/index.ts
index c2b5ffe7e5456d8ab2329d833c69c03666abea5d..b6ccfe1b8dfe406118f3b4ea712fb81ea75d1717 100644
--- a/app/modules/crawler/index.ts
+++ b/app/modules/crawler/index.ts
@@ -48,8 +48,8 @@ export const CrawlerDependency = {
         return crawler.sandboxPull(server)
       },
 
-      synchronize: (server:Server, onHost:string, onPort:number, upTo:number, chunkLength:number) => {
-        const strategy = new RemoteSynchronizer(onHost, onPort, server)
+      synchronize: (currency: string, server:Server, onHost:string, onPort:number, upTo:number, chunkLength:number) => {
+        const strategy = new RemoteSynchronizer(currency, onHost, onPort, server)
         const remote = new Synchroniser(server, strategy)
         const syncPromise = (async () => {
           await server.dal.disableChangesAPI()
@@ -69,8 +69,8 @@ export const CrawlerDependency = {
        * @param {number} onPort
        * @returns {Promise<any>}
        */
-      testForSync: (server:Server, onHost:string, onPort:number) => {
-        return RemoteSynchronizer.test(onHost, onPort)
+      testForSync: (currency: string, server:Server, onHost:string, onPort:number) => {
+        return RemoteSynchronizer.test(currency, onHost, onPort, server.conf.pair)
       }
     },
 
@@ -88,12 +88,13 @@ export const CrawlerDependency = {
     ],
 
     cli: [{
-      name: 'sync [source] [to]',
+      name: 'sync [source] [to] [currency]',
       desc: 'Synchronize blockchain from a remote Duniter node',
       preventIfRunning: true,
       onDatabaseExecute: async (server:Server, conf:ConfDTO, program:any, params:any): Promise<any> => {
-        const source = params[0]
-        const to     = params[1]
+        const source   = params[0]
+        const to       = params[1]
+        const currency = params[2]
         const HOST_PATTERN = /^[^:/]+(:[0-9]{1,5})?$/
         const FILE_PATTERN = /^(\/.+)$/
         if (!source || !(source.match(HOST_PATTERN) || source.match(FILE_PATTERN))) {
@@ -126,7 +127,10 @@ export const CrawlerDependency = {
           const sp = source.split(':')
           const onHost = sp[0]
           const onPort = parseInt(sp[1] ? sp[1] : '443') // Defaults to 443
-          strategy = new RemoteSynchronizer(onHost, onPort, server, noShufflePeers === true, otherDAL)
+          if (!currency) {
+            throw 'currency parameter is required for network synchronization'
+          }
+          strategy = new RemoteSynchronizer(currency, onHost, onPort, server, noShufflePeers === true, otherDAL)
         } else {
           strategy = new LocalPathSynchronizer(source, server)
         }
diff --git a/app/modules/crawler/lib/connect.ts b/app/modules/crawler/lib/connect.ts
index 2d89d28a6612e029494173a3ec16390aa2c96011..f87741c5e8c18243d62d17bcd41832c032da1f5e 100644
--- a/app/modules/crawler/lib/connect.ts
+++ b/app/modules/crawler/lib/connect.ts
@@ -13,10 +13,11 @@
 
 import {CrawlerConstants} from "./constants"
 import {Contacter} from "./contacter"
+import {PeerDTO} from "../../../lib/dto/PeerDTO";
 
 const DEFAULT_HOST = 'localhost';
 
-export const connect = (peer:any, timeout:number|null = null) => {
+export const connect = (peer:PeerDTO, timeout:number|null = null) => {
   return Promise.resolve(new Contacter(peer.getDns() || peer.getIPv4() || peer.getIPv6() || DEFAULT_HOST, peer.getPort(), {
     timeout: timeout || CrawlerConstants.DEFAULT_TIMEOUT
   }))
diff --git a/app/modules/crawler/lib/contacter.ts b/app/modules/crawler/lib/contacter.ts
index 7789fc0f6c0da8f65c7dd2d713f0c2430ffc085e..0e493502f6fc2ceabf760d0de03422ec10cc1640 100644
--- a/app/modules/crawler/lib/contacter.ts
+++ b/app/modules/crawler/lib/contacter.ts
@@ -65,6 +65,10 @@ export class Contacter {
   getPeers(obj?:any) {
     return this.get('/network/peering/peers', dtos.MerkleOfPeers, obj)
   }
+
+  getPeersArray() {
+    return this.get('/network/peering/peers', dtos.Peers)
+  }
   
   getSources(pubkey:string) {
     return this.get('/tx/sources/', dtos.Sources, pubkey)
diff --git a/app/modules/crawler/lib/sandbox.ts b/app/modules/crawler/lib/sandbox.ts
index f4a53218089179c38b3fd8e93268afa260823986..5a92e8a87c7b0e15ae345dacada964d78cc37476 100644
--- a/app/modules/crawler/lib/sandbox.ts
+++ b/app/modules/crawler/lib/sandbox.ts
@@ -16,6 +16,7 @@ import {Contacter} from "./contacter"
 import {Server} from "../../../../server"
 import {rawer} from "../../../lib/common-libs/index"
 import {parsers} from "../../../lib/common-libs/parsers/index"
+import {IRemoteContacter} from "./sync/IRemoteContacter";
 
 export const pullSandbox = async (currency:string, fromHost:string, fromPort:number, toHost:string, toPort:number, logger:any) => {
   const from = new Contacter(fromHost, fromPort);
@@ -43,12 +44,12 @@ export const pullSandbox = async (currency:string, fromHost:string, fromPort:num
   }
 }
 
-export const pullSandboxToLocalServer = async (currency:string, fromHost:any, toServer:Server, logger:any, watcher:any = null, nbCertsMin = 1, notify = true) => {
+export const pullSandboxToLocalServer = async (currency:string, fromHost:IRemoteContacter, toServer:Server, logger:any, watcher:any = null, nbCertsMin = 1, notify = true) => {
   let res
   try {
     res = await fromHost.getRequirementsPending(nbCertsMin || 1)
   } catch (e) {
-    watcher && watcher.writeStatus('Sandbox pulling: could not fetch requirements on %s', [fromHost.host, fromHost.port].join(':'))
+    watcher && watcher.writeStatus('Sandbox pulling: could not fetch requirements on %s', fromHost.getName())
   }
 
   if (res) {
diff --git a/app/modules/crawler/lib/sync/BMARemoteContacter.ts b/app/modules/crawler/lib/sync/BMARemoteContacter.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0726cec0b842ae8bf474b3bf85617d70ca3cbde2
--- /dev/null
+++ b/app/modules/crawler/lib/sync/BMARemoteContacter.ts
@@ -0,0 +1,56 @@
+// Source file from duniter: Crypto-currency software to manage libre currency such as Äž1
+// Copyright (C) 2018  Cedric Moreau <cem.moreau@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+
+import {NewLogger} from "../../../../lib/logger"
+import {IRemoteContacter} from "./IRemoteContacter";
+import {Contacter} from "../contacter";
+import {HttpMerkleOfPeers, HttpRequirements} from "../../../bma/lib/dtos";
+import {JSONDBPeer} from "../../../../lib/db/DBPeer";
+import {FileDAL} from "../../../../lib/dal/fileDAL";
+import {Watcher} from "./Watcher";
+import {cliprogram} from "../../../../lib/common-libs/programOptions";
+import {connect} from "../connect";
+import {RemoteSynchronizer} from "./RemoteSynchronizer";
+import {PeerDTO} from "../../../../lib/dto/PeerDTO";
+import {CrawlerConstants} from "../constants";
+import {dos2unix} from "../../../../lib/common-libs/dos2unix";
+import {PeeringService} from "../../../../service/PeeringService";
+import {BlockDTO} from "../../../../lib/dto/BlockDTO";
+
+const logger = NewLogger()
+
+export class BMARemoteContacter implements IRemoteContacter {
+
+  constructor(protected contacter: Contacter) {
+  }
+
+  getBlock(number: number): Promise<BlockDTO | null> {
+    return this.contacter.getBlock(number)
+  }
+
+  getCurrent(): Promise<BlockDTO | null> {
+    return this.contacter.getCurrent()
+  }
+
+  async getPeers(): Promise<(JSONDBPeer|null)[]> {
+    return (await this.contacter.getPeersArray()).peers
+  }
+
+  getRequirementsPending(minsig: number): Promise<HttpRequirements> {
+    return this.contacter.getRequirementsPending(minsig)
+  }
+
+  getName(): string {
+    return "BMA remote '" + this.contacter.fullyQualifiedHost + "'"
+  }
+}
diff --git a/app/modules/crawler/lib/sync/IRemoteContacter.ts b/app/modules/crawler/lib/sync/IRemoteContacter.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fc3b8c3bc22971cf389e2c9f71043f533265c618
--- /dev/null
+++ b/app/modules/crawler/lib/sync/IRemoteContacter.ts
@@ -0,0 +1,29 @@
+// Source file from duniter: Crypto-currency software to manage libre currency such as Äž1
+// Copyright (C) 2018  Cedric Moreau <cem.moreau@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+
+import {JSONDBPeer} from "../../../../lib/db/DBPeer";
+import {BlockDTO} from "../../../../lib/dto/BlockDTO";
+import {HttpRequirements} from "../../../bma/lib/dtos";
+
+export interface IRemoteContacter {
+
+  getName(): string
+
+  getPeers(): Promise<(JSONDBPeer|null)[]>
+
+  getCurrent(): Promise<BlockDTO|null>
+
+  getBlock(number: number): Promise<BlockDTO|null>
+
+  getRequirementsPending(number: number): Promise<HttpRequirements>
+}
diff --git a/app/modules/crawler/lib/sync/RemoteSynchronizer.ts b/app/modules/crawler/lib/sync/RemoteSynchronizer.ts
index 9767f3de60c15beab8c687d68ced2aadd468cb51..08ef13a4244c171115a964a208744f5d16639375 100644
--- a/app/modules/crawler/lib/sync/RemoteSynchronizer.ts
+++ b/app/modules/crawler/lib/sync/RemoteSynchronizer.ts
@@ -14,7 +14,6 @@
 import {ISyncDownloader} from "./ISyncDownloader"
 import {BlockDTO} from "../../../../lib/dto/BlockDTO"
 import {PeerDTO} from "../../../../lib/dto/PeerDTO"
-import {Contacter} from "../contacter"
 import {connect} from "../connect"
 import {NewLogger} from "../../../../lib/logger"
 import {CrawlerConstants} from "../constants"
@@ -32,25 +31,37 @@ import {FsSyncDownloader} from "./FsSyncDownloader"
 import {AbstractSynchronizer} from "./AbstractSynchronizer"
 import {pullSandboxToLocalServer} from "../sandbox"
 import * as path from 'path'
+import {IRemoteContacter} from "./IRemoteContacter";
+import {BMARemoteContacter} from "./BMARemoteContacter";
+import {WS2PConnection, WS2PPubkeyLocalAuth, WS2PPubkeyRemoteAuth} from "../../../ws2p/lib/WS2PConnection";
+import {WS2PRequester} from "../../../ws2p/lib/WS2PRequester";
+import {WS2PServerMessageHandler} from "../../../ws2p/lib/interface/WS2PServerMessageHandler";
+import {WS2PMessageHandler} from "../../../ws2p/lib/impl/WS2PMessageHandler";
+import {WS2PResponse} from "../../../ws2p/lib/impl/WS2PResponse";
+import {DataErrors} from "../../../../lib/common-libs/errors";
+import {Key, KeyGen} from "../../../../lib/common-libs/crypto/keyring";
+import {WS2PRemoteContacter} from "./WS2PRemoteContacter";
+import {Keypair} from "../../../../lib/dto/ConfDTO";
+import {cat} from "shelljs";
 
 const logger = NewLogger()
 
 export class RemoteSynchronizer extends AbstractSynchronizer {
 
-  private node:Contacter
+  private node:IRemoteContacter
   private peer:PeerDTO
   private shuffledPeers: JSONDBPeer[]
   private theP2pDownloader: ISyncDownloader
   private theFsDownloader: ISyncDownloader
   private to: number
   private localNumber: number
-  private currency: string
   private watcher: Watcher
   private static contacterOptions = {
     timeout: CrawlerConstants.SYNC_LONG_TIMEOUT
   }
 
   constructor(
+    private readonly currency: string,
     private host: string,
     private port: number,
     private server:Server,
@@ -89,54 +100,75 @@ export class RemoteSynchronizer extends AbstractSynchronizer {
   }
 
   async init(): Promise<void> {
-    const peering = await Contacter.fetchPeer(this.host, this.port, RemoteSynchronizer.contacterOptions)
-    this.peer = PeerDTO.fromJSONObject(peering)
+    const syncApi = await RemoteSynchronizer.getSyncAPI(this.currency, this.host, this.port, this.server.conf.pair)
+    if (!syncApi.api) {
+      throw Error(DataErrors[DataErrors.CANNOT_CONNECT_TO_REMOTE_FOR_SYNC])
+    }
+    this.node = syncApi.api
+    this.peer = PeerDTO.fromJSONObject(syncApi.peering)
+    logger.info("Try with %s %s", this.peer.getURL(), this.peer.pubkey.substr(0, 6))
     // We save this peer as a trusted peer for future contact
     await this.server.PeeringService.submitP(DBPeer.fromPeerDTO(this.peer), false, false, true)
-    logger.info("Try with %s %s", this.peer.getURL(), this.peer.pubkey.substr(0, 6))
-    this.node = await connect(this.peer)
     ;(this.node as any).pubkey = this.peer.pubkey
-    this.watcher.writeStatus('Connecting to ' + this.host + '...')
   }
 
-  async initWithKnownLocalAndToAndCurrency(to: number, localNumber: number, currency: string): Promise<void> {
+  private static async getSyncAPI(currency: string, host: string, port: number, keypair: Keypair) {
+    let api: IRemoteContacter|undefined
+    let peering: any
+    logger.info('Connecting to ' + host + '...')
+    try {
+      const contacter = await connect(PeerDTO.fromJSONObject({ endpoints: [`BASIC_MERKLED_API ${host} ${port}`]}), RemoteSynchronizer.contacterOptions.timeout)
+      peering = await contacter.getPeer()
+      api = new BMARemoteContacter(contacter)
+    } catch (e) {
+      logger.warn(`Node does not support BMA, trying WS2P...`)
+    }
+
+    // If BMA is unreachable, let's try WS2P
+    if (!api) {
+      const pair = KeyGen(keypair.pub, keypair.sec)
+      const connection = WS2PConnection.newConnectionToAddress(1,
+        `ws://${host}:${port}`,
+        new (class SyncMessageHandler implements WS2PMessageHandler {
+          async answerToRequest(json: any, c: WS2PConnection): Promise<WS2PResponse> {
+            throw Error(DataErrors[DataErrors.CANNOT_ARCHIVE_CHUNK_WRONG_SIZE])
+          }
+          async handlePushMessage(json: any, c: WS2PConnection): Promise<void> {
+            logger.warn('Receiving push messages, which are not allowed during a SYNC.', json)
+          }
+        }),
+        new WS2PPubkeyLocalAuth(currency, pair, '00000000'),
+        new WS2PPubkeyRemoteAuth(currency, pair)
+      )
+      const requester = WS2PRequester.fromConnection(connection)
+      peering = await requester.getPeer()
+      api = new WS2PRemoteContacter(requester)
+    }
+    if (!api) {
+      throw Error(DataErrors[DataErrors.CANNOT_CONNECT_TO_REMOTE_FOR_SYNC])
+    }
+    if (!peering) {
+      throw Error(DataErrors[DataErrors.NO_PEERING_AVAILABLE_FOR_SYNC])
+    }
+    if (peering.currency !== currency) {
+      throw Error(DataErrors[DataErrors.WRONG_CURRENCY_DETECTED])
+    }
+    return {
+      api,
+      peering
+    }
+  }
+
+  async initWithKnownLocalAndToAndCurrency(to: number, localNumber: number): Promise<void> {
     this.to = to
     this.localNumber = localNumber
-    this.currency = currency
     //=======
     // Peers (just for P2P download)
     //=======
     let peers:(JSONDBPeer|null)[] = [];
     if (!cliprogram.nopeers && (to - localNumber > 1000)) { // P2P download if more than 1000 blocs
       this.watcher.writeStatus('Peers...');
-      const merkle = await this.dal.merkleForPeers();
-      const getPeers:(params:any) => Promise<HttpMerkleOfPeers> = this.node.getPeers.bind(this.node);
-      const json2 = await getPeers({});
-      const rm = new NodesMerkle(json2);
-      if(rm.root() != merkle.root()){
-        const leavesToAdd:string[] = [];
-        const json = await getPeers({ leaves: true });
-        json.leaves.forEach((leaf:string) => {
-          if(merkle.leaves().indexOf(leaf) == -1){
-            leavesToAdd.push(leaf);
-          }
-        });
-        peers = await Promise.all(leavesToAdd.map(async (leaf) => {
-          try {
-            const json3 = await getPeers({ "leaf": leaf });
-            const jsonEntry = json3.leaf.value;
-            const endpoint = jsonEntry.endpoints[0];
-            this.watcher.writeStatus('Peer ' + endpoint);
-            return jsonEntry;
-          } catch (e) {
-            logger.warn("Could not get peer of leaf %s, continue...", leaf);
-            return null;
-          }
-        }))
-      }
-      else {
-        this.watcher.writeStatus('Peers already known');
-      }
+      peers = await this.node.getPeers()
     }
 
     if (!peers.length) {
@@ -168,97 +200,21 @@ export class RemoteSynchronizer extends AbstractSynchronizer {
     return this.node.getBlock(number)
   }
 
-  static async test(host: string, port: number): Promise<BlockDTO> {
-    const peering = await Contacter.fetchPeer(host, port, this.contacterOptions);
-    const node = await connect(PeerDTO.fromJSONObject(peering));
-    return node.getCurrent()
-  }
-
-  async syncPeers(fullSync: boolean, to?: number): Promise<void> {
-    if (!cliprogram.nopeers && fullSync) {
-
-      const peering = await Contacter.fetchPeer(this.host, this.port, RemoteSynchronizer.contacterOptions);
-
-      let peer = PeerDTO.fromJSONObject(peering);
-      logger.info("Try with %s %s", peer.getURL(), peer.pubkey.substr(0, 6));
-      let node:any = await connect(peer);
-      node.pubkey = peer.pubkey;
-      logger.info('Sync started.');
-
-      this.watcher.writeStatus('Peers...');
-      await this.syncPeer(node);
-      const merkle = await this.dal.merkleForPeers();
-      const getPeers:(params:any) => Promise<HttpMerkleOfPeers> = node.getPeers.bind(node);
-      const json2 = await getPeers({});
-      const rm = new NodesMerkle(json2);
-      if(rm.root() != merkle.root()){
-        const leavesToAdd:string[] = [];
-        const json = await getPeers({ leaves: true });
-        json.leaves.forEach((leaf:string) => {
-          if(merkle.leaves().indexOf(leaf) == -1){
-            leavesToAdd.push(leaf);
-          }
-        });
-        for (let i = 0; i < leavesToAdd.length; i++) {
-          try {
-            const leaf = leavesToAdd[i]
-            const json3 = await getPeers({ "leaf": leaf });
-            const jsonEntry = json3.leaf.value;
-            const sign = json3.leaf.value.signature;
-            const entry:any = {};
-            entry.version = jsonEntry.version
-            entry.currency = jsonEntry.currency
-            entry.pubkey = jsonEntry.pubkey
-            entry.endpoints = jsonEntry.endpoints
-            entry.block = jsonEntry.block
-            entry.signature = sign;
-            this.watcher.writeStatus('Peer ' + entry.pubkey);
-            this.watcher.peersPercent((i + 1) / leavesToAdd.length * 100)
-            await this.PeeringService.submitP(entry, false, to === undefined);
-          } catch (e) {
-            logger.warn(e && e.message || e)
-          }
-        }
-        this.watcher.peersPercent(100)
-      }
-      else {
-        this.watcher.writeStatus('Peers already known');
-      }
+  static async test(currency: string, host: string, port: number, keypair: Keypair): Promise<BlockDTO> {
+    const syncApi = await RemoteSynchronizer.getSyncAPI(currency, host, port, keypair)
+    const current = await syncApi.api.getCurrent()
+    if (!current) {
+      throw Error(DataErrors[DataErrors.REMOTE_HAS_NO_CURRENT_BLOCK])
     }
+    return current
   }
 
-  //============
-  // Peer
-  //============
-  private async syncPeer (node:any) {
-
-    // Global sync vars
-    const remotePeer = PeerDTO.fromJSONObject({});
-    const json = await node.getPeer();
-    remotePeer.version = json.version
-    remotePeer.currency = json.currency
-    remotePeer.pubkey = json.pub
-    remotePeer.endpoints = json.endpoints
-    remotePeer.blockstamp = json.block
-    remotePeer.signature = json.signature
-    const entry = remotePeer.getRawUnsigned();
-    const signature = dos2unix(remotePeer.signature);
-    // Parameters
-    if(!(entry && signature)){
-      throw 'Requires a peering entry + signature';
-    }
-
-    let remoteJsonPeer:any = json
-    remoteJsonPeer.pubkey = json.pubkey;
-    let signatureOK = this.PeeringService.checkPeerSignature(remoteJsonPeer);
-    if (!signatureOK) {
-      this.watcher.writeStatus('Wrong signature for peer #' + remoteJsonPeer.pubkey);
-    }
-    try {
-      await this.PeeringService.submitP(remoteJsonPeer);
-    } catch (err) {
-      if (err.indexOf !== undefined && err.indexOf(CrawlerConstants.ERRORS.NEWER_PEER_DOCUMENT_AVAILABLE.uerr.message) !== -1 && err != CrawlerConstants.ERROR.PEER.UNKNOWN_REFERENCE_BLOCK) {
-        throw err;
+  async syncPeers(fullSync: boolean, to?: number): Promise<void> {
+    const peers = await this.node.getPeers()
+    for (const p of peers) {
+      try {
+        await this.PeeringService.submitP(DBPeer.fromPeerDTO(PeerDTO.fromJSONObject(p)))
+      } catch (e) {
       }
     }
   }
@@ -268,29 +224,3 @@ export class RemoteSynchronizer extends AbstractSynchronizer {
     await pullSandboxToLocalServer(this.currency, this.node, this.server, this.server.logger, this.watcher, 1, false)
   }
 }
-
-class NodesMerkle {
-
-  private depth:number
-  private nodesCount:number
-  private leavesCount:number
-  private merkleRoot:string
-
-  constructor(json:any) {
-    this.depth = json.depth
-    this.nodesCount = json.nodesCount
-    this.leavesCount = json.leavesCount
-    this.merkleRoot = json.root;
-  }
-
-  // var i = 0;
-  // this.levels = [];
-  // while(json && json.levels[i]){
-  //   this.levels.push(json.levels[i]);
-  //   i++;
-  // }
-
-  root() {
-    return this.merkleRoot
-  }
-}
diff --git a/app/modules/crawler/lib/sync/WS2PRemoteContacter.ts b/app/modules/crawler/lib/sync/WS2PRemoteContacter.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1a45c64f92c10c7d4b9476ecf7f282ceb6e7b3db
--- /dev/null
+++ b/app/modules/crawler/lib/sync/WS2PRemoteContacter.ts
@@ -0,0 +1,49 @@
+// Source file from duniter: Crypto-currency software to manage libre currency such as Äž1
+// Copyright (C) 2018  Cedric Moreau <cem.moreau@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+
+import {NewLogger} from "../../../../lib/logger"
+import {IRemoteContacter} from "./IRemoteContacter";
+import {Contacter} from "../contacter";
+import {WS2PRequester} from "../../../ws2p/lib/WS2PRequester";
+import {DBPeer, JSONDBPeer} from "../../../../lib/db/DBPeer";
+import {BlockDTO} from "../../../../lib/dto/BlockDTO";
+import {PeerDTO} from "../../../../lib/dto/PeerDTO";
+import {HttpRequirements} from "../../../bma/lib/dtos";
+
+const logger = NewLogger()
+
+export class WS2PRemoteContacter implements IRemoteContacter {
+
+  getRequirementsPending(min: number): Promise<HttpRequirements> {
+    return this.requester.getRequirementsPending(min)
+  }
+
+  constructor(protected requester: WS2PRequester) {
+  }
+
+  getBlock(number: number): Promise<BlockDTO | null> {
+    return this.requester.getBlock(number)
+  }
+
+  getCurrent(): Promise<BlockDTO | null> {
+    return this.requester.getCurrent()
+  }
+
+  async getPeers(): Promise<(JSONDBPeer | null)[]> {
+    return (await this.requester.getPeers()).map(p => DBPeer.fromPeerDTO(PeerDTO.fromJSONObject(p)))
+  }
+
+  getName(): string {
+    return "WS2P remote"
+  }
+}
diff --git a/app/modules/ws2p/lib/WS2PConnection.ts b/app/modules/ws2p/lib/WS2PConnection.ts
index be9fa5851bc5d917a7a9efe632ad10daa511eae8..6c9e3687ea767ca0ad91d530dfa4f539e201fcf5 100644
--- a/app/modules/ws2p/lib/WS2PConnection.ts
+++ b/app/modules/ws2p/lib/WS2PConnection.ts
@@ -27,7 +27,6 @@ const nuuid = require('node-uuid');
 const logger = require('../../../lib/logger').NewLogger('ws2p')
 
 const MAXIMUM_ERRORS_COUNT = 5
-const REQUEST_TIMEOUT_VALUE = WS2PConstants.REQUEST_TIMEOUT
 
 enum WS2P_ERR {
   REJECTED_PUBKEY_OR_INCORRECT_ASK_SIGNATURE_FROM_REMOTE,
@@ -323,8 +322,8 @@ export class WS2PConnection {
       connectionTimeout:number
       requestTimeout:number
     } = {
-      connectionTimeout: REQUEST_TIMEOUT_VALUE,
-      requestTimeout: REQUEST_TIMEOUT_VALUE
+      connectionTimeout: WS2PConstants.REQUEST_TIMEOUT,
+      requestTimeout: WS2PConstants.REQUEST_TIMEOUT
     },
     private expectedPub:string = "",
     private expectedWS2PUID:string = ""
@@ -346,8 +345,8 @@ export class WS2PConnection {
       connectionTimeout:number,
       requestTimeout:number
     } = {
-      connectionTimeout: REQUEST_TIMEOUT_VALUE,
-      requestTimeout: REQUEST_TIMEOUT_VALUE
+      connectionTimeout: WS2PConstants.REQUEST_TIMEOUT,
+      requestTimeout: WS2PConstants.REQUEST_TIMEOUT
     },
     expectedPub:string = "", 
     expectedWS2PUID:string = "") {
@@ -377,8 +376,8 @@ export class WS2PConnection {
       connectionTimeout:number
       requestTimeout:number
     } = {
-      connectionTimeout: REQUEST_TIMEOUT_VALUE,
-      requestTimeout: REQUEST_TIMEOUT_VALUE
+      connectionTimeout: WS2PConstants.REQUEST_TIMEOUT,
+      requestTimeout: WS2PConstants.REQUEST_TIMEOUT
     },
     expectedPub:string = "") {
     const onWsOpened = Promise.resolve()
diff --git a/app/modules/ws2p/lib/WS2PDocpoolPuller.ts b/app/modules/ws2p/lib/WS2PDocpoolPuller.ts
index cc44dc48078102263157eb6c0e42ecd751db9657..a720d2455eacf9acd7e485bc1e00c4b7b9175d57 100644
--- a/app/modules/ws2p/lib/WS2PDocpoolPuller.ts
+++ b/app/modules/ws2p/lib/WS2PDocpoolPuller.ts
@@ -29,7 +29,11 @@ export class WS2PDocpoolPuller {
     return pullSandboxToLocalServer(this.server.conf.currency, {
       getRequirementsPending: (minCert = 1) => {
         return requester.getRequirementsPending(minCert)
-      }
+      },
+      getName: () => this.connection.pubkey,
+      getPeers: async () => [],
+      getCurrent: async () => null,
+      getBlock: async () => null,
     }, this.server, this.server.logger)
   }
 }
diff --git a/app/modules/ws2p/lib/WS2PRequester.ts b/app/modules/ws2p/lib/WS2PRequester.ts
index bfa2ea23589915a181d8488b74573b89e1f851e0..e043742eae4d1f2a82661e123992aec020eb9e70 100644
--- a/app/modules/ws2p/lib/WS2PRequester.ts
+++ b/app/modules/ws2p/lib/WS2PRequester.ts
@@ -13,6 +13,7 @@
 
 import {WS2PConnection} from "./WS2PConnection"
 import {BlockDTO} from "../../../lib/dto/BlockDTO"
+import {PeerDTO} from "../../../lib/dto/PeerDTO";
 
 export enum WS2P_REQ {
   KNOWN_PEERS,
@@ -32,6 +33,14 @@ export class WS2PRequester {
     return new WS2PRequester(ws2pc)
   }
 
+  getPeer(): Promise<PeerDTO> {
+    return this.query(WS2P_REQ.PEER_DOCUMENT)
+  }
+
+  getPeers(): Promise<PeerDTO[]> {
+    return this.query(WS2P_REQ.KNOWN_PEERS)
+  }
+
   getCurrent(): Promise<BlockDTO> {
     return this.query(WS2P_REQ.CURRENT)
   }
diff --git a/test/integration/misc/cli.ts b/test/integration/misc/cli.ts
index a4540493bfc591fa046194e28e995b6327cccb0f..3f22278ecca404c1109dc55cec5214872fa61e6f 100644
--- a/test/integration/misc/cli.ts
+++ b/test/integration/misc/cli.ts
@@ -58,13 +58,13 @@ describe("CLI", function() {
         /***************
          * Normal nodes
          */
-        return fakeSyncServer(onReadBlockchainChunk, onReadParticularBlock, onPeersRequested);
+        return fakeSyncServer('duniter_unit_test_currency', onReadBlockchainChunk, onReadParticularBlock, onPeersRequested);
       } else if (index == 2) {
         
         /***************
          * Node with wrong chaining between 2 chunks of blocks
          */
-        return fakeSyncServer((count:number, from:number) => {
+        return fakeSyncServer('duniter_unit_test_currency', (count:number, from:number) => {
           // We just need to send the wrong chunk
           from = from - count;
           return Promise.resolve(blockchain.blocks.slice(from, from + count));
@@ -74,7 +74,7 @@ describe("CLI", function() {
         /***************
          * Node with wrong chaining between 2 blocks
          */
-        return fakeSyncServer((count:number, from:number) => {
+        return fakeSyncServer('duniter_unit_test_currency', (count:number, from:number) => {
           // We just need to send the wrong chunk
           const chunk = blockchain.blocks.slice(from, from + count).map((block:any, index2:number) => {
             if (index2 === 10) {
@@ -90,7 +90,7 @@ describe("CLI", function() {
         /***************
          * Node with apparent good chaining, but one of the hashs is WRONG
          */
-        return fakeSyncServer((count:number, from:number) => {
+        return fakeSyncServer('duniter_unit_test_currency', (count:number, from:number) => {
           // We just need to send the wrong chunk
           const chunk = blockchain.blocks.slice(from, from + count).map((block:any, index2:number) => {
             if (index2 === 10) {
@@ -109,6 +109,7 @@ describe("CLI", function() {
     }))
     farmOfServers.map((server, index) => {
       const peer = {
+        currency: 'duniter_unit_test_currency',
         endpoints: [['BASIC_MERKLED_API', server.host, server.port].join(' ')],
         pubkey: hashf(index + ""),
         hash: hashf(index + "").toUpperCase()
@@ -133,14 +134,14 @@ describe("CLI", function() {
 
   it('sync 7 blocks (fast)', async () => {
     await execute(['reset', 'data']);
-    await execute(['sync', fakeServer.host + ':' + String(fakeServer.port), '7', '--nocautious', '--nointeractive', '--noshuffle']);
+    await execute(['sync', fakeServer.host + ':' + String(fakeServer.port), '7', 'duniter_unit_test_currency', '--nocautious', '--nointeractive', '--noshuffle']);
     const res = await execute(['export-bc', '--nostdout']);
     res[res.length - 1].should.have.property('number').equal(7);
     res.should.have.length(7 + 1); // blocks #0..#7
   })
 
   it('sync 4 blocks (cautious)', async () => {
-    await execute(['sync', fakeServer.host + ':' + String(fakeServer.port), '11', '--nointeractive']);
+    await execute(['sync', fakeServer.host + ':' + String(fakeServer.port), '11', 'duniter_unit_test_currency', '--nointeractive']);
     const res = await execute(['export-bc', '--nostdout']);
     res[res.length - 1].should.have.property('number').equal(11);
     res.should.have.length(11 + 1);
@@ -153,7 +154,7 @@ describe("CLI", function() {
   })
 
   it('[spawn] sync 10 first blocks --memory', async () => {
-    await execute(['sync', fakeServer.host + ':' + String(fakeServer.port), '10', '--memory', '--cautious', '--nointeractive']);
+    await execute(['sync', fakeServer.host + ':' + String(fakeServer.port), '10', 'duniter_unit_test_currency', '--memory', '--cautious', '--nointeractive']);
   })
 });
 
diff --git a/test/integration/tools/test-framework.ts b/test/integration/tools/test-framework.ts
index 52ced0319e67cefb91e669420afdfd896603b502..fe7d475d6532c3781403a94040bd9f79767dbef3 100644
--- a/test/integration/tools/test-framework.ts
+++ b/test/integration/tools/test-framework.ts
@@ -1,10 +1,15 @@
-import {catUser, NewTestingServer, tacUser, TestingServer} from "./toolbox"
+import {catUser, NewTestingServer, tacUser, TestingServer, tocUser} from "./toolbox"
 import {TestUser} from "./TestUser"
 import * as assert from 'assert'
 
-export function writeBasicTestWith2Users(writeTests: (test: (testTitle: string, fn: (server: TestingServer, cat: TestUser, tac: TestUser) => Promise<void>) => void) => void) {
+export function writeBasicTestWith2Users(writeTests: (
+  test: (
+    testTitle: string,
+    fn: (server: TestingServer, cat: TestUser, tac: TestUser, toc: TestUser) => Promise<void>
+  ) => void
+) => void) {
 
-  let s1:TestingServer, cat:TestUser, tac:TestUser
+  let s1:TestingServer, cat:TestUser, tac:TestUser, toc:TestUser
 
   before(async () => {
     s1 = NewTestingServer({
@@ -16,12 +21,13 @@ export function writeBasicTestWith2Users(writeTests: (test: (testTitle: string,
     })
     cat = catUser(s1)
     tac = tacUser(s1)
+    toc = tocUser(s1)
     await s1.prepareForNetwork()
   })
 
-  writeTests((title, cb: (server: TestingServer, cat: TestUser, tac: TestUser) => Promise<void>) => {
+  writeTests((title, cb: (server: TestingServer, cat: TestUser, tac: TestUser, toc: TestUser) => Promise<void>) => {
     it(title, async () => {
-      await cb(s1, cat, tac)
+      await cb(s1, cat, tac, toc)
     })
   })
 }
diff --git a/test/integration/tools/toolbox.ts b/test/integration/tools/toolbox.ts
index ad761b1c3303e0e7eaf251748c31ee562fab91c6..f6688e60dd7004535a26c6e790a55be673eee082 100644
--- a/test/integration/tools/toolbox.ts
+++ b/test/integration/tools/toolbox.ts
@@ -158,7 +158,7 @@ export const createUser = async (uid:string, pub:string, sec:string, defaultServ
   return new TestUser(uid, keyring, { server: defaultServer });
 }
 
-export const fakeSyncServer = async (readBlocksMethod:any, readParticularBlockMethod:any, onPeersRequested:any) => {
+export const fakeSyncServer = async (currency: string, readBlocksMethod:any, readParticularBlockMethod:any, onPeersRequested:any) => {
 
   const host = HOST;
   const port = PORT++;
@@ -181,6 +181,7 @@ export const fakeSyncServer = async (readBlocksMethod:any, readParticularBlockMe
     // Mock BMA method for sync mocking
     httpMethods.httpGET('/network/peering', async () => {
       return {
+        currency,
         endpoints: [['BASIC_MERKLED_API', host, port].join(' ')]
       }
     }, noLimit);
@@ -664,7 +665,7 @@ export class TestingServer {
     }
   }
 
-  async enableWS2P(port: number = PORT++) {
+  async enableWS2P(port: number = PORT++): Promise<TestWS2PAPI> {
     const cluster = WS2PCluster.plugOn(this._server)
     await (this._server.ws2pCluster as WS2PCluster).listen(HOST, port)
     const doConnection = (pair: Key, ws2pId: string, constructor: new (
@@ -686,11 +687,20 @@ export class TestingServer {
       },
       connectForSync: (pair: Key, ws2pId: string) => {
         return doConnection(pair, ws2pId, WS2PPubkeySyncLocalAuth)
-      }
+      },
+      host: HOST,
+      port
     }
   }
 }
 
+export interface TestWS2PAPI {
+  connect: (pair: Key, ws2pId: string) => WS2PRequester
+  connectForSync: (pair: Key, ws2pId: string) => WS2PRequester
+  host: string
+  port: number
+}
+
 export async function newWS2PBidirectionnalConnection(currency:string, k1:Key, k2:Key, serverHandler:WS2PMessageHandler) {
   let i = 1
   let port = PORT++
@@ -785,4 +795,13 @@ export function tacUser(server: TestingServer) {
     {
       server
     })
+}
+
+export function tocUser(server: TestingServer) {
+  return new TestUser('toc', {
+    pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo',
+    sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'},
+    {
+      server
+    })
 }
\ No newline at end of file
diff --git a/test/integration/ws2p/ws2p_sync.ts b/test/integration/ws2p/ws2p_sync.ts
index a1c812b8ea0efd76fd6fdc6d2040820f5bb0a889..b6852290e1dea562a8040c5fc2797b3d0a0a9451 100644
--- a/test/integration/ws2p/ws2p_sync.ts
+++ b/test/integration/ws2p/ws2p_sync.ts
@@ -13,21 +13,48 @@
 
 import {WS2PConstants} from "../../../app/modules/ws2p/lib/constants"
 import {assertEqual, assertNotNull, createCurrencyWith2Blocks, writeBasicTestWith2Users} from "../tools/test-framework"
+import {NewTestingServer, TestWS2PAPI} from "../tools/toolbox";
+import {assertThrows} from "../../unit-tools";
+import {CrawlerDependency} from "../../../app/modules/crawler/index";
 
 describe('WS2P sync', () => writeBasicTestWith2Users((test) => {
 
-  WS2PConstants.CONNEXION_TIMEOUT = 100
-  WS2PConstants.REQUEST_TIMEOUT= 100
+
+  // We want the test to fail quickly
+  WS2PConstants.CONNEXION_TIMEOUT = 1000
+  WS2PConstants.REQUEST_TIMEOUT = 1000
+
+  let ws2p: TestWS2PAPI
 
   test('should be able to init with 2 blocks', async (s1, cat, tac) => {
     await createCurrencyWith2Blocks(s1, cat, tac)
   })
 
-  test('if we disable the changes API', async (s1, cat, tac) => {
-    const ws2p = await s1.enableWS2P()
-    const ws = (await ws2p).connectForSync(tac.keypair, '12345678')
+  test('we should be able to connect for SYNC', async (s1, cat, tac) => {
+    ws2p = await s1.enableWS2P()
+    const ws = ws2p.connectForSync(tac.keypair, '12345678')
     const current = await ws.getCurrent()
     assertNotNull(current)
     assertEqual(2, current.number)
   })
+
+  test('we should NOT be able to reconnect for SYNC', async (s1, cat, tac) => {
+    const ws = ws2p.connectForSync(tac.keypair, '22222222')
+    await assertThrows(ws.getCurrent(), 'WS2P connection timeout')
+  })
+
+  test('we should be able to connect for SYNC with toc', async (s1, cat, tac, toc) => {
+    const ws = ws2p.connectForSync(toc.keypair, '33333333')
+    const current = await ws.getCurrent()
+    assertNotNull(current)
+    assertEqual(2, current.number)
+  })
+
+  test('we should be able to make a full sync with cat', async (s1, cat, tac, toc) => {
+    const s2 = NewTestingServer({ pair: cat.keypair })
+    await s2.initWithDAL()
+    // We sync on s1
+    await CrawlerDependency.duniter.methods.synchronize(s1.conf.currency, s2._server, ws2p.host, ws2p.port, 2, 250).syncPromise
+    assertNotNull(await s2.dal.getCurrentBlockOrNull())
+  })
 }))