From 36f1ef5721947f718f2ee0f5d355f155e4e16e1d Mon Sep 17 00:00:00 2001
From: blavenie <benoit.lavenier@e-is.pro>
Date: Wed, 30 Jan 2019 23:56:33 +0100
Subject: [PATCH] [fix] Fix currency id/name in Dao [enh] Add
 WotRemoteService.sendCertification() implementation [enh] Add
 NetworkRemoveService.getDifficulties()

---
 .../client/actions/TransactionAction.java     |   6 +-
 .../core/client/config/Configuration.java     |   4 +
 .../duniter/core/client/dao/CurrencyDao.java  |   6 +-
 .../org/duniter/core/client/dao/PeerDao.java  |   9 +
 .../client/dao/mem/MemoryCurrencyDaoImpl.java |  16 +-
 .../client/dao/mem/MemoryPeerDaoImpl.java     |  12 +
 .../core/client/model/BasicIdentity.java      |  11 +
 .../client/model/bma/BlockchainBlock.java     |   1 +
 .../model/bma/BlockchainDifficulties.java     |  68 ++++
 .../model/bma/BlockchainMemberships.java      |   2 +-
 .../core/client/model/bma/Protocol.java       |   2 +
 .../core/client/model/local/Contact.java      |   4 +-
 .../core/client/model/local/Currency.java     |  23 +-
 .../core/client/model/local/Identity.java     |  50 ++-
 .../core/client/model/{ => local}/Member.java |  27 +-
 .../core/client/model/local/Peers.java        |  12 +-
 .../core/client/service/HttpService.java      |   2 +
 .../core/client/service/HttpServiceImpl.java  |   6 +-
 .../service/bma/BaseRemoteServiceImpl.java    |  17 +
 .../service/bma/BlockchainRemoteService.java  |  33 +-
 .../bma/BlockchainRemoteServiceImpl.java      | 223 ++++++-----
 .../service/bma/NetworkRemoteServiceImpl.java |  21 +-
 .../service/bma/TransactionRemoteService.java |   8 +-
 .../bma/TransactionRemoteServiceImpl.java     |  74 ++--
 .../client/service/bma/WotRemoteService.java  |  47 +--
 .../service/bma/WotRemoteServiceImpl.java     | 375 ++++++++++--------
 .../CurrencyRegistryRemoteServiceImpl.java    |   4 +-
 .../client/service/local/CurrencyService.java |  20 +-
 .../service/local/CurrencyServiceImpl.java    | 122 +++---
 .../service/local/NetworkServiceImpl.java     |  11 +-
 .../client/service/local/PeerServiceImpl.java |  19 +-
 .../bma/BlockchainRemoteServiceTest.java      |  13 +
 .../service/bma/WotRemoteServiceTest.java     |  28 ++
 33 files changed, 735 insertions(+), 541 deletions(-)
 create mode 100644 duniter4j-core-client/src/main/java/org/duniter/core/client/model/bma/BlockchainDifficulties.java
 rename duniter4j-core-client/src/main/java/org/duniter/core/client/model/{ => local}/Member.java (65%)

diff --git a/duniter4j-client/src/main/java/org/duniter/client/actions/TransactionAction.java b/duniter4j-client/src/main/java/org/duniter/client/actions/TransactionAction.java
index 8415a1f2..8060100c 100644
--- a/duniter4j-client/src/main/java/org/duniter/client/actions/TransactionAction.java
+++ b/duniter4j-client/src/main/java/org/duniter/client/actions/TransactionAction.java
@@ -100,7 +100,7 @@ public class TransactionAction extends AbstractAction  {
 
             Currency currency = ServiceLocator.instance().getBlockchainRemoteService().getCurrencyFromPeer(peer);
             ServiceLocator.instance().getCurrencyService().save(currency);
-            peer.setCurrency(currency.getCurrencyName());
+            peer.setCurrency(currency.getId());
             ServiceLocator.instance().getPeerService().save(peer);
 
 
@@ -123,7 +123,7 @@ public class TransactionAction extends AbstractAction  {
             }
 
             Wallet wallet = new Wallet(
-                    currency.getCurrencyName(),
+                    currency.getId(),
                     null,
                     keypair.getPubKey(),
                     keypair.getSecKey());
@@ -219,7 +219,7 @@ public class TransactionAction extends AbstractAction  {
         logTxSummary(wallet);
 
         peers.stream().forEach(peer -> {
-            peer.setCurrency(currency.getCurrencyName());
+            peer.setCurrency(currency.getId());
             peerService.save(peer);
 
             log.debug(String.format("Send TX to [%s]...", peer));
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/config/Configuration.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/config/Configuration.java
index 7bb45477..0b7cc4f2 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/config/Configuration.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/config/Configuration.java
@@ -251,6 +251,10 @@ public class Configuration  {
         return applicationConfig.getOptionAsInt(ConfigurationOption.NETWORK_TIMEOUT.getKey());
     }
 
+    public int getNetworkLargerTimeout() {
+        return Math.max(30000, getNetworkTimeout());
+    }
+
     public int getNetworkMaxTotalConnections() {
         return applicationConfig.getOptionAsInt(ConfigurationOption.NETWORK_MAX_CONNECTIONS.getKey());
     }
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/dao/CurrencyDao.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/dao/CurrencyDao.java
index e33b0676..ee7c5d4c 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/dao/CurrencyDao.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/dao/CurrencyDao.java
@@ -40,9 +40,11 @@ public interface CurrencyDao extends Bean, EntityDao<String, Currency> {
 
     void remove(final Currency currency);
 
-    List<String> getCurrencyIds();
+    Set<String> getAllIds();
 
-    List<Currency> getCurrencies(long accountId);
+    List<Currency> getAll();
+
+    List<Currency> getAllByAccount(long accountId);
 
     /**
      * Return the value of the last universal dividend
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/dao/PeerDao.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/dao/PeerDao.java
index 1a9ade97..d12e7013 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/dao/PeerDao.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/dao/PeerDao.java
@@ -24,6 +24,7 @@ package org.duniter.core.client.dao;
 
 import org.duniter.core.client.model.bma.EndpointApi;
 import org.duniter.core.client.model.bma.NetworkPeers;
+import org.duniter.core.client.model.bma.NetworkWs2pHeads;
 import org.duniter.core.client.model.local.Peer;
 
 import java.util.Collection;
@@ -56,6 +57,14 @@ public interface PeerDao extends EntityDao<String, Peer> {
      */
     List<NetworkPeers.Peer> getBmaPeersByCurrencyId(String currencyId, String[] pubkeys);
 
+    /**
+     * Get WS2p heads as BMA /network/ws2p/head format
+     * @param currencyId
+     * @param pubkeys use to filter on specific pubkeys. If null, not filtering
+     * @return
+     */
+    List<NetworkWs2pHeads.Head> getWs2pPeersByCurrencyId(String currencyId, String[] pubkeys);
+
     boolean isExists(String currencyId, String peerId);
 
     Long getMaxLastUpTime(String currencyId);
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/dao/mem/MemoryCurrencyDaoImpl.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/dao/mem/MemoryCurrencyDaoImpl.java
index 82ed699d..1daf5844 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/dao/mem/MemoryCurrencyDaoImpl.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/dao/mem/MemoryCurrencyDaoImpl.java
@@ -23,6 +23,7 @@ package org.duniter.core.client.dao.mem;
  */
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import org.duniter.core.client.dao.CurrencyDao;
 
 import java.util.*;
@@ -61,15 +62,18 @@ public class MemoryCurrencyDaoImpl implements CurrencyDao {
     }
 
     @Override
-    public List<String> getCurrencyIds() {
-        return ImmutableList.copyOf(currencies.keySet());
+    public Set<String> getAllIds() {
+        return ImmutableSet.copyOf(currencies.keySet());
     }
 
     @Override
-    public List<org.duniter.core.client.model.local.Currency> getCurrencies(long accountId) {
-        List<org.duniter.core.client.model.local.Currency> result = new ArrayList<>();
-        result.addAll(currencies.values());
-        return result;
+    public List<org.duniter.core.client.model.local.Currency> getAll() {
+        return ImmutableList.copyOf(currencies.values());
+    }
+
+    @Override
+    public List<org.duniter.core.client.model.local.Currency> getAllByAccount(long accountId) {
+        return ImmutableList.copyOf(currencies.values());
     }
 
     @Override
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/dao/mem/MemoryPeerDaoImpl.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/dao/mem/MemoryPeerDaoImpl.java
index 9fd7dbe0..44cd11b4 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/dao/mem/MemoryPeerDaoImpl.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/dao/mem/MemoryPeerDaoImpl.java
@@ -26,6 +26,7 @@ import com.google.common.collect.ImmutableList;
 import org.duniter.core.client.dao.PeerDao;
 import org.duniter.core.client.model.bma.EndpointApi;
 import org.duniter.core.client.model.bma.NetworkPeers;
+import org.duniter.core.client.model.bma.NetworkWs2pHeads;
 import org.duniter.core.client.model.local.Peer;
 import org.duniter.core.client.model.local.Peers;
 import org.duniter.core.util.Preconditions;
@@ -121,6 +122,17 @@ public class MemoryPeerDaoImpl implements PeerDao {
         return Peers.toBmaPeers(getPeersByCurrencyIdAndApiAndPubkeys(currencyId, null, pubkeys));
     }
 
+    @Override
+    public List<NetworkWs2pHeads.Head> getWs2pPeersByCurrencyId(String currencyId, String[] pubkeys) {
+        Preconditions.checkNotNull(currencyId);
+
+        return getPeersByCurrencyIdAndApiAndPubkeys(currencyId, null, pubkeys)
+                .stream()
+                .map(Peers::toWs2pHead)
+                // Skip if no message
+                .filter(head -> head.getMessage() != null)
+                .collect(Collectors.toList());
+    }
 
     @Override
     public boolean isExists(final String currencyId, final  String peerId) {
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/BasicIdentity.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/BasicIdentity.java
index 389673ad..20456b52 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/BasicIdentity.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/BasicIdentity.java
@@ -23,6 +23,9 @@ package org.duniter.core.client.model;
  */
 
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.duniter.core.client.model.local.LocalEntity;
+
 import java.io.Serializable;
 
 /**
@@ -36,6 +39,10 @@ public class BasicIdentity implements Serializable {
 
     private static final long serialVersionUID = 8080689271400316984L;
 
+    public static final String PROPERTY_UID = "uid";
+    public static final String PROPERTY_PUBKEY = "pubkey";
+    public static final String PROPERTY_SIGNATURE = "signature";
+
     private String pubkey;
 
     private String signature;
@@ -58,10 +65,14 @@ public class BasicIdentity implements Serializable {
         this.signature = signature;
     }
 
+    @JsonIgnore
+    @Deprecated
     public String getSelf() {
         return signature;
     }
 
+    @JsonIgnore
+    @Deprecated
     public void setSelf(String signature) {
         this.signature = signature;
     }
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/bma/BlockchainBlock.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/bma/BlockchainBlock.java
index 4724fadd..57e707f3 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/bma/BlockchainBlock.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/bma/BlockchainBlock.java
@@ -51,6 +51,7 @@ public class BlockchainBlock implements Serializable {
     public static final String PROPERTY_REVOKED = "revoked";
     public static final String PROPERTY_EXCLUDED = "excluded";
     public static final String PROPERTY_MEDIAN_TIME = "medianTime";
+    public static final String PROPERTY_ISSUER = "issuer";
 
 
     private static final long serialVersionUID = -5598140972293452669L;
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/bma/BlockchainDifficulties.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/bma/BlockchainDifficulties.java
new file mode 100644
index 00000000..82617b53
--- /dev/null
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/bma/BlockchainDifficulties.java
@@ -0,0 +1,68 @@
+package org.duniter.core.client.model.bma;
+
+/*
+ * #%L
+ * UCoin Java :: Core Client API
+ * %%
+ * Copyright (C) 2014 - 2016 EIS
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public 
+ * License along with this program.  If not, see
+ * <http://www.gnu.org/licenses/gpl-3.0.html>.
+ * #L%
+ */
+
+import java.io.Serializable;
+
+public class BlockchainDifficulties implements Serializable {
+	private static final long serialVersionUID = -5631089862715942431L;
+
+	private Long block;
+	private DifficultyLevel[] levels;
+
+	public Long getBlock() {
+		return block;
+	}
+	public void setBlock(Long block) {
+		this.block = block;
+	}
+	public DifficultyLevel[] getLevels() {
+		return levels;
+	}
+	public void setLevels(DifficultyLevel[] levels) {
+		this.levels = levels;
+	}
+
+	public static class DifficultyLevel implements Serializable {
+		private static final long serialVersionUID = 1L;
+
+		private String uid;
+		private int level;
+
+		public String getUid() {
+			return uid;
+		}
+
+		public void setUid(String uid) {
+			this.uid = uid;
+		}
+
+		public int getLevel() {
+			return level;
+		}
+
+		public void setLevel(int level) {
+			this.level = level;
+		}
+	}
+}
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/bma/BlockchainMemberships.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/bma/BlockchainMemberships.java
index 1f2c36b5..99f896b7 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/bma/BlockchainMemberships.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/bma/BlockchainMemberships.java
@@ -45,7 +45,7 @@ public class BlockchainMemberships extends BasicIdentity {
 		this.memberships = memberships;
 	}
 
-	public class Membership implements Serializable {
+	public static class Membership implements Serializable {
 		private static final long serialVersionUID = 1L;
 
 		private String version;
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/bma/Protocol.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/bma/Protocol.java
index 0c854f39..07cf3a2c 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/bma/Protocol.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/bma/Protocol.java
@@ -35,6 +35,8 @@ public interface Protocol {
 
     String TYPE_MEMBERSHIP = "Membership";
 
+    String TYPE_CERTIFICATION = "Certification";
+
     String TYPE_TRANSACTION = "Transaction";
 
     String TYPE_PEER = "Peer";
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/local/Contact.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/local/Contact.java
index 6d95919e..f9fa2715 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/local/Contact.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/local/Contact.java
@@ -113,7 +113,7 @@ public class Contact implements LocalEntity<Long>, Serializable {
 
     public boolean hasIdentityForCurrency(String currencyId) {
         return identities.stream()
-                .anyMatch(identity -> identity.getCurrencyId() != null
-                        && currencyId.equals(identity.getCurrencyId()));
+                .anyMatch(identity -> identity.getCurrency() != null
+                        && currencyId.equals(identity.getCurrency()));
     }
 }
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/local/Currency.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/local/Currency.java
index 04770f58..d4b64004 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/local/Currency.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/local/Currency.java
@@ -25,7 +25,6 @@ package org.duniter.core.client.model.local;
 import java.io.Serializable;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
-import org.duniter.core.client.model.Account;
 import org.duniter.core.client.model.bma.BlockchainParameters;
 
 /**
@@ -33,7 +32,7 @@ import org.duniter.core.client.model.bma.BlockchainParameters;
  */
 public class Currency implements LocalEntity<String>, Serializable {
 
-    private String currencyName;
+    private String id;
     private Integer membersCount;
     private String firstBlockSignature;
     private Long lastUD;
@@ -42,11 +41,11 @@ public class Currency implements LocalEntity<String>, Serializable {
     public Currency() {
     }
 
-    public Currency(String currencyName,
+    public Currency(String id,
                     String firstBlockSignature,
                     int membersCount,
                     BlockchainParameters parameters) {
-        this.currencyName = currencyName;
+        this.id = id;
         this.firstBlockSignature = firstBlockSignature;
         this.membersCount = membersCount;
         this.parameters = parameters;
@@ -54,12 +53,11 @@ public class Currency implements LocalEntity<String>, Serializable {
 
     @JsonIgnore
     public String getId() {
-        return currencyName;
+        return id;
     }
 
-    public String getCurrencyName()
-    {
-        return currencyName;
+    public void setId(String id) {
+        this.id = id;
     }
 
     public Integer getMembersCount() {
@@ -70,13 +68,6 @@ public class Currency implements LocalEntity<String>, Serializable {
         return firstBlockSignature;
     }
 
-    public void setId(String id) {
-        this.currencyName = id;
-    }
-
-    public void setCurrencyName(String currencyName) {
-        this.currencyName = currencyName;
-    }
 
     public void setMembersCount(Integer membersCount) {
         this.membersCount = membersCount;
@@ -103,6 +94,6 @@ public class Currency implements LocalEntity<String>, Serializable {
     }
 
     public String toString() {
-        return currencyName;
+        return id;
     }
 }
\ No newline at end of file
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/local/Identity.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/local/Identity.java
index dbe29e99..3b82915b 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/local/Identity.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/local/Identity.java
@@ -23,29 +23,23 @@ package org.duniter.core.client.model.local;
  */
 
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import org.duniter.core.client.model.BasicIdentity;
 
 public class Identity extends BasicIdentity {
 
     private static final long serialVersionUID = -7451079677730158794L;
 
+    public static final String PROPERTY_IS_MEMBER = "isMember";
+    public static final String PROPERTY_WAS_MEMBER = "wasMember";
+
     private String timestamp = null;
 
     private Boolean isMember = null;
 
-    private String currencyId;
-
-    /**
-     * The timestamp value of the signature date (a BLOCK_UID)
-     * @return
-     */
-    public String getTimestamp() {
-        return timestamp;
-    }
+    private Boolean wasMember = null;
 
-    public void setTimestamp(String timestamp) {
-        this.timestamp = timestamp;
-    }
+    private String currency;
 
     /**
      * Indicate whether the certification is written in the blockchain or not.
@@ -58,11 +52,35 @@ public class Identity extends BasicIdentity {
         this.isMember = isMember;
     }
 
-    public String getCurrencyId() {
-        return currencyId;
+    public Boolean getWasMember() {
+        return wasMember;
+    }
+
+    public void setWasMember(Boolean wasMember) {
+        this.wasMember = wasMember;
+    }
+
+    /**
+     * The timestamp value of the signature date (a BLOCK_UID)
+     * @return
+     */
+    @JsonIgnore
+    public String getTimestamp() {
+        return timestamp;
+    }
+
+    @JsonIgnore
+    public void setTimestamp(String timestamp) {
+        this.timestamp = timestamp;
+    }
+
+    @JsonIgnore
+    public String getCurrency() {
+        return currency;
     }
 
-    public void setCurrencyId(String currencyId) {
-        this.currencyId = currencyId;
+    @JsonIgnore
+    public void setCurrency(String currency) {
+        this.currency = currency;
     }
 }
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/Member.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/local/Member.java
similarity index 65%
rename from duniter4j-core-client/src/main/java/org/duniter/core/client/model/Member.java
rename to duniter4j-core-client/src/main/java/org/duniter/core/client/model/local/Member.java
index fb6a9ad8..2ed02c89 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/Member.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/local/Member.java
@@ -1,4 +1,4 @@
-package org.duniter.core.client.model;
+package org.duniter.core.client.model.local;
 
 /*
  * #%L
@@ -23,29 +23,20 @@ package org.duniter.core.client.model;
  */
 
 
-import org.duniter.core.client.model.local.Identity;
+import com.fasterxml.jackson.annotation.JsonIgnore;
 
-public class Member extends Identity {
+public class Member extends Identity implements LocalEntity<String> {
 
     private static final long serialVersionUID = 8448049949323699700L;
 
-    private String number;
-
-    private String hash;
-
-    public String getNumber() {
-        return number;
+    @JsonIgnore
+    public String getId() {
+        return getPubkey();
     }
 
-    public void setNumber(String number) {
-        this.number = number;
+    @JsonIgnore
+    public void setId(String pubkey) {
+        setPubkey(pubkey);
     }
 
-    public String getHash() {
-        return hash;
-    }
-
-    public void setHash(String hash) {
-        this.hash = hash;
-    }
 }
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/local/Peers.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/local/Peers.java
index 3648143a..deb2d801 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/model/local/Peers.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/model/local/Peers.java
@@ -24,10 +24,7 @@ package org.duniter.core.client.model.local;
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
-import org.duniter.core.client.model.bma.EndpointApi;
-import org.duniter.core.client.model.bma.NetworkPeering;
-import org.duniter.core.client.model.bma.NetworkPeers;
-import org.duniter.core.client.model.bma.Protocol;
+import org.duniter.core.client.model.bma.*;
 import org.duniter.core.util.CollectionUtils;
 import org.duniter.core.util.StringUtils;
 
@@ -147,6 +144,13 @@ public final class Peers {
         }).collect(Collectors.toList());
     }
 
+    public static NetworkWs2pHeads.Head toWs2pHead(Peer peer) {
+        NetworkWs2pHeads.Head result = new NetworkWs2pHeads.Head();
+
+        // TODO : add implementation
+
+        return result;
+    }
 
     public static  Peer.PeerStatus getStatus(final Peer peer) {
         return peer.getStats() != null &&
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/HttpService.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/HttpService.java
index b1a02dee..366bdd16 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/HttpService.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/HttpService.java
@@ -50,6 +50,8 @@ public interface HttpService extends Service {
 
     <T> T executeRequest(Peer peer, String absolutePath, Class<? extends T> resultClass);
 
+    <T> T executeRequest(Peer peer, String absolutePath, Class<? extends T> resultClass, int timeout) ;
+
     String getPath(Peer peer, String... absolutePath);
 
     String getPath(String... absolutePath);
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/HttpServiceImpl.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/HttpServiceImpl.java
index 9f74e067..c7516b43 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/HttpServiceImpl.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/HttpServiceImpl.java
@@ -152,8 +152,12 @@ public class HttpServiceImpl implements HttpService, Closeable, InitializingBean
     }
 
     public <T> T executeRequest(Peer peer, String absolutePath, Class<? extends T> resultClass)  {
+        return executeRequest(peer, absolutePath, resultClass, 0);
+    }
+
+    public <T> T executeRequest(Peer peer, String absolutePath, Class<? extends T> resultClass, int timeout)  {
         HttpGet httpGet = new HttpGet(peer.getUrl() + absolutePath);
-        return executeRequest(HttpClients.getThreadHttpClient(0), httpGet, resultClass);
+        return executeRequest(HttpClients.getThreadHttpClient(timeout), httpGet, resultClass);
     }
 
     public String getPath(Peer peer, String... absolutePath) {
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BaseRemoteServiceImpl.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BaseRemoteServiceImpl.java
index b1cfc667..f051ea60 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BaseRemoteServiceImpl.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BaseRemoteServiceImpl.java
@@ -58,15 +58,29 @@ public abstract class BaseRemoteServiceImpl implements Service, InitializingBean
         peerService = null;
     }
 
+    @Deprecated
     public <T> T executeRequest(Peer peer, String absolutePath, Class<? extends T> resultClass)  {
         return httpService.executeRequest(peer, absolutePath, resultClass);
     }
 
+    @Deprecated
+    public <T> T executeRequest(Peer peer, String absolutePath, Class<? extends T> resultClass, int timeout)  {
+        return httpService.executeRequest(peer, absolutePath, resultClass, timeout);
+    }
+
+    @Deprecated
     public <T> T executeRequest(String currencyId, String absolutePath, Class<? extends T> resultClass)  {
         Peer peer = peerService.getActivePeerByCurrencyId(currencyId);
         return httpService.executeRequest(peer, absolutePath, resultClass);
     }
 
+    @Deprecated
+    public <T> T executeRequest(String currencyId, String absolutePath, Class<? extends T> resultClass, int timeout)  {
+        Peer peer = peerService.getActivePeerByCurrencyId(currencyId);
+        return httpService.executeRequest(peer, absolutePath, resultClass, timeout);
+    }
+
+    @Deprecated
     public <T> T executeRequest(HttpUriRequest request, Class<? extends T> resultClass)  {
         return httpService.executeRequest(request, resultClass);
     }
@@ -76,14 +90,17 @@ public abstract class BaseRemoteServiceImpl implements Service, InitializingBean
         return httpService.getPath(peer, aPath);
     }
 
+    @Deprecated
     public String getPath(Peer peer, String aPath) {
         return httpService.getPath(peer, aPath);
     }
 
+    @Deprecated
     public URIBuilder getURIBuilder(URI baseUri, String... path) {
         return httpService.getURIBuilder(baseUri, path);
     }
 
+    @Deprecated
     public URIBuilder getURIBuilder(URL baseUrl, String... path) {
         try {
             return httpService.getURIBuilder(baseUrl.toURI(), path);
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BlockchainRemoteService.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BlockchainRemoteService.java
index eaac3b40..f93313a0 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BlockchainRemoteService.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BlockchainRemoteService.java
@@ -23,6 +23,7 @@ package org.duniter.core.client.service.bma;
  */
 
 import org.duniter.core.beans.Service;
+import org.duniter.core.client.model.bma.BlockchainDifficulties;
 import org.duniter.core.client.model.local.Identity;
 import org.duniter.core.client.model.bma.BlockchainBlock;
 import org.duniter.core.client.model.bma.BlockchainMemberships;
@@ -49,6 +50,8 @@ public interface BlockchainRemoteService extends Service {
      */
     BlockchainParameters getParameters(String currencyId, boolean useCache);
 
+    BlockchainParameters getParameters(Peer peer, boolean useCache);
+
     /**
      * get the blockchain parameters (currency parameters)
      *
@@ -84,6 +87,8 @@ public interface BlockchainRemoteService extends Service {
      */
     Long getBlockDividend(String currencyId, long number) throws BlockNotFoundException;
 
+    Long getBlockDividend(Peer peer, long number) throws BlockNotFoundException;
+
     /**
      * Retrieve a block, by id (from 0 to current)
      *
@@ -124,6 +129,7 @@ public interface BlockchainRemoteService extends Service {
      *
      * @return
      */
+    BlockchainBlock getCurrentBlock(Peer peer, boolean useCache);
     BlockchainBlock getCurrentBlock(String currencyId, boolean useCache);
 
     /**
@@ -131,15 +137,8 @@ public interface BlockchainRemoteService extends Service {
      *
      * @return
      */
-    BlockchainBlock getCurrentBlock(String currencyId);
-
-    /**
-     * Retrieve the current block
-     *
-     * @param peer the peer to use for request
-     * @return the last block
-     */
     BlockchainBlock getCurrentBlock(Peer peer);
+    BlockchainBlock getCurrentBlock(String currencyId);
 
     /**
      * Retrieve the currency data, from peer
@@ -149,23 +148,20 @@ public interface BlockchainRemoteService extends Service {
      */
     Currency getCurrencyFromPeer(Peer peer);
 
-    BlockchainParameters getBlockchainParametersFromPeer(Peer peer);
-
     /**
-     * Retrieve the last emitted UD (or ud0 if not UD emitted yet)
-     *
-     * @param currencyId id of currency
+     * Retrieve personal difficulties (level, uid)
      * @return
      */
-    long getLastUD(String currencyId);
+    BlockchainDifficulties getDifficulties(Peer peer);
+    BlockchainDifficulties getDifficulties(String currencyId);
 
     /**
-     * Retrieve the last emitted UD, from a peer (or ud0 if not UD emitted yet)
+     * Retrieve the last emitted UD (or ud0 if not UD emitted yet)
      *
-     * @param currencyId id of currency
      * @return
      */
     long getLastUD(Peer peer);
+    long getLastUD(String currencyId);
 
     /**
      * Check is a identity is not already used by a existing member
@@ -193,7 +189,6 @@ public interface BlockchainRemoteService extends Service {
      */
     void loadMembership(String currencyId, Identity identity, boolean checkLookupForNonMember);
 
-
     BlockchainMemberships getMembershipByUid(String currencyId, String uid);
 
     BlockchainMemberships getMembershipByPublicKey(String currencyId, String pubkey);
@@ -220,18 +215,18 @@ public interface BlockchainRemoteService extends Service {
      * @param startOffset
      * @return
      */
+    Map<Integer, Long> getUDs(Peer peer, long startOffset);
     Map<Integer, Long> getUDs(String currencyId, long startOffset);
 
     /**
      * Listening new block event
-     * @param currencyId
      * @param listener
      * @param autoReconnect
      * @return
      */
+    WebsocketClientEndpoint addBlockListener(Peer peer, WebsocketClientEndpoint.MessageListener listener, boolean autoReconnect);
     WebsocketClientEndpoint addBlockListener(String currencyId, WebsocketClientEndpoint.MessageListener listener, boolean autoReconnect);
 
-    WebsocketClientEndpoint addBlockListener(Peer peer, WebsocketClientEndpoint.MessageListener listener, boolean autoReconnect);
 
 
 }
\ No newline at end of file
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BlockchainRemoteServiceImpl.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BlockchainRemoteServiceImpl.java
index c577dbc8..ed3fc30e 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BlockchainRemoteServiceImpl.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/BlockchainRemoteServiceImpl.java
@@ -22,6 +22,7 @@ package org.duniter.core.client.service.bma;
  * #L%
  */
 
+import com.google.common.collect.Maps;
 import org.apache.http.NameValuePair;
 import org.apache.http.client.entity.UrlEncodedFormEntity;
 import org.apache.http.client.methods.HttpPost;
@@ -75,6 +76,8 @@ public class BlockchainRemoteServiceImpl extends BaseRemoteServiceImpl implement
 
     public static final String URL_MEMBERSHIP_SEARCH = URL_BASE + "/memberships/%s";
 
+    public static final String URL_DIFFICULTIES = URL_BASE + "/difficulties";
+
     public static final String URL_WS_BLOCK = "/ws/block";
 
     private Configuration config;
@@ -114,44 +117,56 @@ public class BlockchainRemoteServiceImpl extends BaseRemoteServiceImpl implement
     }
 
     @Override
-    public BlockchainParameters getParameters(String currencyId, boolean useCache) {
-        if (!useCache) {
-            return getParameters(currencyId);
+    public BlockchainParameters getParameters(Peer peer, boolean useCache) {
+        if (!useCache || peer.getCurrency() == null) {
+            return getParameters(peer);
         } else {
-            return mParametersCache.get(currencyId);
+            BlockchainParameters result = mParametersCache.getIfPresent(peer.getCurrency());
+            if (result == null) {
+                result = getParameters(peer);
+                if (result != null) {
+                    mParametersCache.put(peer.getCurrency(), result);
+                }
+            }
+            return result;
         }
     }
 
     @Override
-    public BlockchainParameters getParameters(String currencyId) {
-        // get blockchain parameter
-        BlockchainParameters result = executeRequest(currencyId, URL_PARAMETERS, BlockchainParameters.class);
-        return result;
+    public BlockchainParameters getParameters(String currencyId, boolean useCache) {
+        return getParameters(peerService.getActivePeerByCurrencyId(currencyId), useCache);
     }
 
     @Override
     public BlockchainParameters getParameters(Peer peer) {
-        // get blockchain parameter
-        BlockchainParameters result = executeRequest(peer, URL_PARAMETERS, BlockchainParameters.class);
-        return result;
+        return httpService.executeRequest(peer, URL_PARAMETERS, BlockchainParameters.class);
     }
 
     @Override
-    public BlockchainBlock getBlock(String currencyId, long number) throws BlockNotFoundException  {
-        String path = String.format(URL_BLOCK, number);
+    public BlockchainParameters getParameters(String currencyId) {
+        return getParameters(peerService.getActivePeerByCurrencyId(currencyId));
+    }
+
+    @Override
+    public BlockchainBlock getBlock(Peer peer, long number) throws BlockNotFoundException {
         try {
-            return executeRequest(currencyId, path, BlockchainBlock.class);
+            return httpService.executeRequest(peer, String.format(URL_BLOCK, number), BlockchainBlock.class);
         }
         catch(HttpNotFoundException e) {
-            throw new BlockNotFoundException(String.format("Block #%s not found", number));
+            throw new BlockNotFoundException(String.format("Block #%s not found on peer [%s]", number, peer));
         }
     }
 
     @Override
-    public Long getBlockDividend(String currencyId, long number) throws BlockNotFoundException {
+    public BlockchainBlock getBlock(String currencyId, long number) throws BlockNotFoundException  {
+       return getBlock(peerService.getActivePeerByCurrencyId(currencyId), number);
+    }
+
+    @Override
+    public Long getBlockDividend(Peer peer, long number) throws BlockNotFoundException {
         String path = String.format(URL_BLOCK, number);
         try {
-            String json = executeRequest(currencyId, path, String.class);
+            String json = httpService.executeRequest(peer, path, String.class);
             return getDividendFromBlockJson(json);
         }
         catch(HttpNotFoundException e) {
@@ -159,23 +174,17 @@ public class BlockchainRemoteServiceImpl extends BaseRemoteServiceImpl implement
         }
     }
 
-
     @Override
-    public BlockchainBlock getBlock(Peer peer, long number) throws BlockNotFoundException {
-        // Get block from number
-        String path = String.format(URL_BLOCK, number);
-        try {
-            return executeRequest(peer, path, BlockchainBlock.class);
-        }
-        catch(HttpNotFoundException e) {
-            throw new BlockNotFoundException(String.format("Block #%s not found on peer [%s]", number, peer));
-        }
+    public Long getBlockDividend(String currencyId, long number) throws BlockNotFoundException {
+        return getBlockDividend(peerService.getActivePeerByCurrencyId(currencyId), number);
     }
 
+
+
     @Override
     public long[] getBlocksWithTx(Peer peer) {
         try {
-            Blocks blocks = executeRequest(peer, URL_BLOCK_WITH_TX, Blocks.class);
+            Blocks blocks = httpService.executeRequest(peer, URL_BLOCK_WITH_TX, Blocks.class);
             return (blocks == null || blocks.getResult() == null) ? new long[0] : blocks.getResult().getBlocks();
         }
         catch(HttpNotFoundException e) {
@@ -189,7 +198,7 @@ public class BlockchainRemoteServiceImpl extends BaseRemoteServiceImpl implement
         // get blockchain parameter
         String path = String.format(URL_BLOCK, number);
         try {
-            return executeRequest(peer, path, String.class);
+            return httpService.executeRequest(peer, path, String.class);
         }
         catch(HttpNotFoundException e) {
             throw new BlockNotFoundException(String.format("Block #%s not found on peer [%s]", number, peer));
@@ -200,7 +209,7 @@ public class BlockchainRemoteServiceImpl extends BaseRemoteServiceImpl implement
     public String[] getBlocksAsJson(Peer peer, int count, int from) {
         // get blockchain parameter
         String path = String.format(URL_BLOCKS_FROM, count, from);
-        String jsonBlocksStr = executeRequest(peer, path, String.class);
+        String jsonBlocksStr = httpService.executeRequest(peer, path, String.class);
 
         // Parse only array content, but deserialize array item
         JsonArrayParser parser = new JsonArrayParser();
@@ -212,25 +221,35 @@ public class BlockchainRemoteServiceImpl extends BaseRemoteServiceImpl implement
      *
      * @return
      */
-    public BlockchainBlock getCurrentBlock(String currencyId, boolean useCache) {
-        if (!useCache) {
-            return getCurrentBlock(currencyId);
+    @Override
+    public BlockchainBlock getCurrentBlock(Peer peer, boolean useCache) {
+        if (!useCache || peer.getCurrency() == null) {
+            return getCurrentBlock(peer);
         } else {
-            return mCurrentBlockCache.get(currencyId);
+            BlockchainBlock result = mCurrentBlockCache.getIfPresent(peer.getCurrency());
+            if (result == null) {
+                result = getCurrentBlock(peer);
+                if (result != null) {
+                    mCurrentBlockCache.put(peer.getCurrency(), result);
+                }
+            }
+            return result;
         }
     }
 
+    public BlockchainBlock getCurrentBlock(String currencyId, boolean useCache) {
+        return getCurrentBlock(peerService.getActivePeerByCurrencyId(currencyId), useCache);
+    }
+
     @Override
     public BlockchainBlock getCurrentBlock(String currencyId) {
-        // get blockchain parameter
-        BlockchainBlock result = executeRequest(currencyId, URL_BLOCK_CURRENT, BlockchainBlock.class);
-        return result;
+        return getCurrentBlock(peerService.getActivePeerByCurrencyId(currencyId));
     }
 
     @Override
     public BlockchainBlock getCurrentBlock(Peer peer) {
         // get blockchain parameter
-        BlockchainBlock result = executeRequest(peer, URL_BLOCK_CURRENT, BlockchainBlock.class);
+        BlockchainBlock result = httpService.executeRequest(peer, URL_BLOCK_CURRENT, BlockchainBlock.class);
         return result;
     }
 
@@ -241,7 +260,7 @@ public class BlockchainRemoteServiceImpl extends BaseRemoteServiceImpl implement
         BlockchainBlock lastBlock = getCurrentBlock(peer);
 
         org.duniter.core.client.model.local.Currency result = new org.duniter.core.client.model.local.Currency();
-        result.setCurrencyName(parameter.getCurrency());
+        result.setId(parameter.getCurrency());
         result.setFirstBlockSignature(firstBlock.getSignature());
         result.setMembersCount(lastBlock.getMembersCount());
         result.setLastUD(parameter.getUd0());
@@ -249,38 +268,10 @@ public class BlockchainRemoteServiceImpl extends BaseRemoteServiceImpl implement
         return result;
     }
 
-    @Override
-    public BlockchainParameters getBlockchainParametersFromPeer(Peer peer){
-        return getParameters(peer);
-    }
-
-    @Override
-    public long getLastUD(String currencyId) {
-        // get block number with UD
-        String blocksWithUdResponse = executeRequest(currencyId, URL_BLOCK_WITH_UD, String.class);
-        Integer blockNumber = getLastBlockNumberFromJson(blocksWithUdResponse);
-
-        // If no result (this could happen when no UD has been send
-        if (blockNumber == null) {
-            // get the first UD from currency parameter
-            BlockchainParameters parameter = getParameters(currencyId);
-            return parameter.getUd0();
-        }
-
-        // Get the UD from the last block with UD
-        Long lastUD = getBlockDividend(currencyId, blockNumber);
-
-        // Check not null (should never append)
-        if (lastUD == null) {
-            throw new TechnicalException("Unable to get last UD from server");
-        }
-        return lastUD.longValue();
-    }
-
     @Override
     public long getLastUD(Peer peer) {
         // get block number with UD
-        String blocksWithUdResponse = executeRequest(peer, URL_BLOCK_WITH_UD, String.class);
+        String blocksWithUdResponse = httpService.executeRequest(peer, URL_BLOCK_WITH_UD, String.class);
 
         int[] blocksWithUD = getBlockNumbersFromJson(blocksWithUdResponse);
 
@@ -293,7 +284,7 @@ public class BlockchainRemoteServiceImpl extends BaseRemoteServiceImpl implement
                 try {
                     // Get the UD from the last block with UD
                     String path = String.format(URL_BLOCK, blocksWithUD[index]);
-                    String json = executeRequest(peer, path, String.class);
+                    String json = httpService.executeRequest(peer, path, String.class);
                     Long lastUD = getDividendFromBlockJson(json);
 
                     // Check not null (should never append)
@@ -312,6 +303,11 @@ public class BlockchainRemoteServiceImpl extends BaseRemoteServiceImpl implement
         return parameter.getUd0();
     }
 
+    @Override
+    public long getLastUD(String currencyId) {
+        return getLastUD(peerService.getActivePeerByCurrencyId(currencyId));
+    }
+
     /**
      * Check is a identity is not already used by a existing member
      *
@@ -414,25 +410,23 @@ public class BlockchainRemoteServiceImpl extends BaseRemoteServiceImpl implement
         List<NameValuePair> urlParameters = new ArrayList<NameValuePair>();
         urlParameters.add(new BasicNameValuePair("membership", membership));
 
-        HttpPost httpPost = new HttpPost(getPath(wallet.getCurrencyId(), URL_MEMBERSHIP));
+        HttpPost httpPost = new HttpPost(httpService.getPath(wallet.getCurrencyId(), URL_MEMBERSHIP));
         try {
             httpPost.setEntity(new UrlEncodedFormEntity(urlParameters));
         } catch (UnsupportedEncodingException e) {
             throw new TechnicalException(e);
         }
 
-        String membershipResult = executeRequest(httpPost, String.class);
+        String membershipResult = httpService.executeRequest(httpPost, String.class);
         if (log.isDebugEnabled()) {
             log.debug("received from /tx/process: " + membershipResult);
         }
-
-        executeRequest(httpPost, String.class);
     }
 
 
     public void requestMembership(Peer peer, String currency, byte[] pubKey, byte[] secKey, String uid, String membershipBlockUid, String selfBlockUid) {
         // http post /blockchain/membership
-        HttpPost httpPost = new HttpPost(getPath(peer, URL_MEMBERSHIP));
+        HttpPost httpPost = new HttpPost(httpService.getPath(peer, URL_MEMBERSHIP));
 
         // compute the self-certification
         String membership = getSignedMembership(currency, pubKey, secKey, uid, membershipBlockUid, selfBlockUid, true/*side in*/);
@@ -448,32 +442,20 @@ public class BlockchainRemoteServiceImpl extends BaseRemoteServiceImpl implement
         }
 
         // Execute the request
-        executeRequest(httpPost, String.class);
+        httpService.executeRequest(httpPost, String.class);
     }
 
-    public BlockchainMemberships getMembershipByPubkeyOrUid(String currencyId, String uidOrPubkey) {
-        String path = String.format(URL_MEMBERSHIP_SEARCH, uidOrPubkey);
-
-        // search blockchain membership
+    public BlockchainMemberships getMembershipByPubkeyOrUid(Peer peer, String uidOrPubkey) {
         try {
-            return executeRequest(currencyId, path, BlockchainMemberships.class);
+            return httpService.executeRequest(peer, String.format(URL_MEMBERSHIP_SEARCH, uidOrPubkey), BlockchainMemberships.class);
         } catch (HttpBadRequestException e) {
             log.debug("No member matching this pubkey or uid: " + uidOrPubkey);
             return null;
         }
     }
 
-    public BlockchainMemberships getMembershipByPubkeyOrUid(Peer peer, String uidOrPubkey) {
-        String path = String.format(URL_MEMBERSHIP_SEARCH, uidOrPubkey);
-
-        // search blockchain membership
-        try {
-            BlockchainMemberships result = executeRequest(peer, path, BlockchainMemberships.class);
-            return result;
-        } catch (HttpBadRequestException e) {
-            log.debug("No member matching this pubkey or uid: " + uidOrPubkey);
-            return null;
-        }
+    public BlockchainMemberships getMembershipByPubkeyOrUid(String currencyId, String uidOrPubkey) {
+        return getMembershipByPubkeyOrUid(peerService.getActivePeerByCurrencyId(currencyId), uidOrPubkey);
     }
 
     public String getMembership(Wallet wallet,
@@ -501,22 +483,16 @@ public class BlockchainRemoteServiceImpl extends BaseRemoteServiceImpl implement
     /**
      * Get UD, by block number
      *
-     * @param currencyId
+     * @param peer
      * @param startOffset
      * @return
      */
-    public Map<Integer, Long> getUDs(String currencyId, long startOffset) {
+    public Map<Integer, Long> getUDs(Peer peer, long startOffset) {
         log.debug(String.format("Getting block's UD from block [%s]", startOffset));
 
-        int[] blockNumbersWithUD = getBlocksWithUD(currencyId);
-
-        Map<Integer, Long> result = new LinkedHashMap<Integer,Long>();
+        int[] blockNumbersWithUD = getBlocksWithUD(peer);
 
-//         Insert the UD0 (if need)
-//        if (startOffset <= 0) {
-//            BlockchainParameters parameters = getParameters(currencyId, true/*with cache*/);
-//            result.put(0, parameters.getUd0());
-//        }
+        Map<Integer, Long> result = Maps.newLinkedHashMap();
 
         boolean previousBlockInsert = false;
         if (blockNumbersWithUD != null && blockNumbersWithUD.length != 0) {
@@ -524,10 +500,10 @@ public class BlockchainRemoteServiceImpl extends BaseRemoteServiceImpl implement
             for (Integer blockNumber : blockNumbersWithUD) {
                 if (blockNumber >= startOffset) {
                     if(!previousBlockInsert){
-                        Long previousUd = getParameters(currencyId, true/*with cache*/).getUd0();
+                        Long previousUd = getParameters(peer, true/*with cache*/).getUd0();
                         Integer previousBlockNumber = 0;
                         if(previousBlockNumberWithUd!=null){
-                            previousUd = getBlockDividend(currencyId, previousBlockNumberWithUd);
+                            previousUd = getBlockDividend(peer, previousBlockNumberWithUd);
                             if (previousUd == null) {
                                 throw new TechnicalException(
                                         String.format("Unable to get UD from server block [%s]",
@@ -539,7 +515,7 @@ public class BlockchainRemoteServiceImpl extends BaseRemoteServiceImpl implement
                         result.put(previousBlockNumber, previousUd);
                         previousBlockInsert = true;
                     }
-                    Long ud = getBlockDividend(currencyId, blockNumber);
+                    Long ud = getBlockDividend(peer, blockNumber);
                     // Check not null (should never append)
                     if (ud == null) {
                         throw new TechnicalException(String.format("Unable to get UD from server block [%s]", blockNumber));
@@ -550,15 +526,21 @@ public class BlockchainRemoteServiceImpl extends BaseRemoteServiceImpl implement
                 }
             }
         }else{
-            result.put(0, getParameters(currencyId, true/*with cache*/).getUd0());
+            result.put(0, getParameters(peer, true/*with cache*/).getUd0());
         }
 
         return result;
     }
 
-    @Override
-    public WebsocketClientEndpoint addBlockListener(String currencyId, WebsocketClientEndpoint.MessageListener listener, boolean autoReconnect) {
-        return addBlockListener(peerService.getActivePeerByCurrencyId(currencyId), listener, autoReconnect);
+    /**
+     * Get UD, by block number
+     *
+     * @param currencyId
+     * @param startOffset
+     * @return
+     */
+    public Map<Integer, Long> getUDs(String currencyId, long startOffset) {
+        return getUDs(peerService.getActivePeerByCurrencyId(currencyId), startOffset);
     }
 
     @Override
@@ -575,6 +557,20 @@ public class BlockchainRemoteServiceImpl extends BaseRemoteServiceImpl implement
         return wsClientEndPoint;
     }
 
+    @Override
+    public WebsocketClientEndpoint addBlockListener(String currencyId, WebsocketClientEndpoint.MessageListener listener, boolean autoReconnect) {
+        return addBlockListener(peerService.getActivePeerByCurrencyId(currencyId), listener, autoReconnect);
+    }
+
+    @Override
+    public BlockchainDifficulties getDifficulties(Peer peer) {
+        return httpService.executeRequest(peer, URL_DIFFICULTIES, BlockchainDifficulties.class, config.getNetworkLargerTimeout());
+    }
+
+    @Override
+    public BlockchainDifficulties getDifficulties(String currencyId) {
+        return getDifficulties(peerService.getActivePeerByCurrencyId(currencyId));
+    }
 
     /* -- Internal methods -- */
 
@@ -646,12 +642,10 @@ public class BlockchainRemoteServiceImpl extends BaseRemoteServiceImpl implement
 
     }
 
-    private int[] getBlocksWithUD(String currencyId) {
+    private int[] getBlocksWithUD(Peer peer) {
         log.debug("Getting blocks with UD");
 
-        String json = executeRequest(currencyId, URL_BLOCK_WITH_UD, String.class);
-
-
+        String json = httpService.executeRequest(peer, URL_BLOCK_WITH_UD, String.class);
 
         int startIndex = json.indexOf("[");
         int endIndex = json.lastIndexOf(']');
@@ -685,6 +679,11 @@ public class BlockchainRemoteServiceImpl extends BaseRemoteServiceImpl implement
         return result;
     }
 
+    private int[] getBlocksWithUD(String currencyId) {
+        Peer peer = peerService.getActivePeerByCurrencyId(currencyId);
+        return getBlocksWithUD(peer);
+    }
+
     protected String getSignedMembership(String currency,
                                       byte[] pubKey,
                                       byte[] secKey,
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/NetworkRemoteServiceImpl.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/NetworkRemoteServiceImpl.java
index a7c0e63e..c05a640a 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/NetworkRemoteServiceImpl.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/NetworkRemoteServiceImpl.java
@@ -24,8 +24,6 @@ package org.duniter.core.client.service.bma;
 
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
-import java.net.URI;
-import java.net.URISyntaxException;
 import java.util.*;
 
 import com.fasterxml.jackson.databind.JsonNode;
@@ -35,13 +33,12 @@ import org.apache.http.NameValuePair;
 import org.apache.http.client.entity.UrlEncodedFormEntity;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.message.BasicNameValuePair;
+import org.duniter.core.client.config.Configuration;
 import org.duniter.core.client.model.bma.*;
 import org.duniter.core.client.model.bma.jackson.JacksonUtils;
 import org.duniter.core.client.model.local.Peer;
-import org.duniter.core.client.model.local.Wallet;
 import org.duniter.core.exception.TechnicalException;
 import org.duniter.core.util.Preconditions;
-import org.duniter.core.util.StringUtils;
 import org.duniter.core.util.websocket.WebsocketClientEndpoint;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -71,13 +68,15 @@ public class NetworkRemoteServiceImpl extends BaseRemoteServiceImpl implements N
 
     public static final String URL_WS2P_HEADS = URL_WS2P + "/heads";
 
+    public final Configuration config;
+
     public NetworkRemoteServiceImpl() {
         super();
+        this.config = Configuration.instance();
     }
 
     public NetworkPeering getPeering(Peer peer) {
-        NetworkPeering result = httpService.executeRequest(peer, URL_PEERING, NetworkPeering.class);
-        return result;
+        return httpService.executeRequest(peer, URL_PEERING, NetworkPeering.class);
     }
 
     @Override
@@ -125,9 +124,9 @@ public class NetworkRemoteServiceImpl extends BaseRemoteServiceImpl implements N
     public List<Peer> findPeers(Peer peer, String status, EndpointApi endpointApi, Integer currentBlockNumber, String currentBlockHash) {
         Preconditions.checkNotNull(peer);
 
-        List<Peer> result = new ArrayList<Peer>();
+        List<Peer> result = Lists.newArrayList();
 
-        NetworkPeers remoteResult = httpService.executeRequest(peer, URL_PEERS, NetworkPeers.class);
+        NetworkPeers remoteResult = httpService.executeRequest(peer, URL_PEERS, NetworkPeers.class, config.getNetworkLargerTimeout());
 
         for (NetworkPeers.Peer remotePeer: remoteResult.peers) {
             boolean match = (status == null || status.equalsIgnoreCase(remotePeer.status))
@@ -161,7 +160,7 @@ public class NetworkRemoteServiceImpl extends BaseRemoteServiceImpl implements N
     public List<Ws2pHead> getWs2pHeads(Peer peer) {
         Preconditions.checkNotNull(peer);
 
-        NetworkWs2pHeads remoteResult = httpService.executeRequest(peer, URL_WS2P_HEADS, NetworkWs2pHeads.class);
+        NetworkWs2pHeads remoteResult = httpService.executeRequest(peer, URL_WS2P_HEADS, NetworkWs2pHeads.class, config.getNetworkLargerTimeout());
 
         List<Ws2pHead> result = Lists.newArrayList();
 
@@ -210,7 +209,7 @@ public class NetworkRemoteServiceImpl extends BaseRemoteServiceImpl implements N
         Preconditions.checkNotNull(peeringDocument);
 
         // http post /tx/process
-        HttpPost httpPost = new HttpPost(getPath(peer, URL_PEERING_PEERS));
+        HttpPost httpPost = new HttpPost(httpService.getPath(peer, URL_PEERING_PEERS));
 
         if (log.isDebugEnabled()) {
             log.debug(String.format(
@@ -227,7 +226,7 @@ public class NetworkRemoteServiceImpl extends BaseRemoteServiceImpl implements N
             throw new TechnicalException(e);
         }
 
-        String result = executeRequest(httpPost, String.class);
+        String result = httpService.executeRequest(httpPost, String.class);
         if (log.isDebugEnabled()) {
             log.debug("Received from " + URL_PEERING_PEERS + " (POST): " + result);
         }
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/TransactionRemoteService.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/TransactionRemoteService.java
index 0e5ab18a..e6d48bb8 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/TransactionRemoteService.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/TransactionRemoteService.java
@@ -58,17 +58,17 @@ public interface TransactionRemoteService extends Service {
 	String transfer(Wallet wallet, String destPubKey, long amount,
                     String comment) throws InsufficientCreditException;
 
-	TxSource getSources(String currencyId, String pubKey);
-
     TxSource getSources(Peer peer, String pubKey);
+	TxSource getSources(String currencyId, String pubKey);
 
+    long getCreditOrZero(Peer peer, String pubKey);
     long getCreditOrZero(String currencyId, String pubKey);
 
-    Long getCredit(String currencyId, String pubKey);
-
     Long getCredit(Peer peer, String pubKey);
+    Long getCredit(String currencyId, String pubKey);
 
     long computeCredit(TxSource.Source[] sources);
 
+    TxHistory getTxHistory(Peer peer, String pubKey, long fromBlockNumber, long toBlockNumber);
     TxHistory getTxHistory(String currencyId, String pubKey, long fromBlockNumber, long toBlockNumber);
 }
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/TransactionRemoteServiceImpl.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/TransactionRemoteServiceImpl.java
index 47c91a51..7b02b75a 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/TransactionRemoteServiceImpl.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/TransactionRemoteServiceImpl.java
@@ -91,15 +91,12 @@ public class TransactionRemoteServiceImpl extends BaseRemoteServiceImpl implemen
 		Preconditions.checkNotNull(wallet);
 		Preconditions.checkArgument(peer != null || wallet.getCurrencyId() != null);
 
+		peer = peer != null ? peer : peerService.getActivePeerByCurrencyId(wallet.getCurrencyId());
 		// Get current block
-		BlockchainBlock currentBlock = peer != null ?
-				executeRequest(peer, BlockchainRemoteServiceImpl.URL_BLOCK_CURRENT, BlockchainBlock.class) :
-				executeRequest(wallet.getCurrencyId(), BlockchainRemoteServiceImpl.URL_BLOCK_CURRENT, BlockchainBlock.class);
+		BlockchainBlock currentBlock = httpService.executeRequest(peer, BlockchainRemoteServiceImpl.URL_BLOCK_CURRENT, BlockchainBlock.class);
 
 		// http post /tx/process
-		HttpPost httpPost = peer != null ?
-				new HttpPost(getPath(peer, URL_TX_PROCESS)) :
-				new HttpPost(getPath(wallet.getCurrencyId(), URL_TX_PROCESS));
+		HttpPost httpPost = new HttpPost(httpService.getPath(peer, URL_TX_PROCESS));
 
 		// compute transaction
 		String transaction = getSignedTransaction(peer, wallet, currentBlock, destPubKey, 0, amount,
@@ -120,7 +117,7 @@ public class TransactionRemoteServiceImpl extends BaseRemoteServiceImpl implemen
 			throw new TechnicalException(e);
 		}
 
-		String selfResult = executeRequest(httpPost, String.class);
+		String selfResult = httpService.executeRequest(httpPost, String.class);
 		if (log.isDebugEnabled()) {
 			log.debug("Received from /tx/process: " + selfResult);
 		}
@@ -136,17 +133,6 @@ public class TransactionRemoteServiceImpl extends BaseRemoteServiceImpl implemen
 
 	}
 
-	public TxSource getSources(String currencyId, String pubKey) {
-		if (log.isDebugEnabled()) {
-			log.debug(String.format("Get sources by pubKey: %s", pubKey));
-		}
-
-		// get parameter
-		String path = String.format(URL_TX_SOURCES, pubKey);
-		TxSource result = executeRequest(currencyId, path, TxSource.class);
-
-		return result;
-	}
 
 	public TxSource getSources(Peer peer, String pubKey) {
 		if (log.isDebugEnabled()) {
@@ -155,13 +141,17 @@ public class TransactionRemoteServiceImpl extends BaseRemoteServiceImpl implemen
 
 		// get parameter
 		String path = String.format(URL_TX_SOURCES, pubKey);
-		TxSource result = executeRequest(peer, path, TxSource.class);
+		TxSource result = httpService.executeRequest(peer, path, TxSource.class);
 
 		return result;
 	}
 
-    public long getCreditOrZero(String currencyId, String pubKey) {
-        Long credit = getCredit(currencyId, pubKey);
+	public TxSource getSources(String currencyId, String pubKey) {
+		return getSources(peerService.getActivePeerByCurrencyId(currencyId), pubKey);
+	}
+
+    public long getCreditOrZero(Peer peer, String pubKey) {
+        Long credit = getCredit(peer, pubKey);
 
         if (credit == null) {
             return 0;
@@ -169,22 +159,9 @@ public class TransactionRemoteServiceImpl extends BaseRemoteServiceImpl implemen
         return credit.longValue();
     }
 
-    public Long getCredit(String currencyId, String pubKey) {
-		if (log.isDebugEnabled()) {
-			log.debug(String.format("Get credit by pubKey [%s] for currency [id=%s]", pubKey, currencyId));
-		}
-
-        // get parameter
-        String path = String.format(URL_TX_SOURCES, pubKey);
-        TxSource result = executeRequest(currencyId, path, TxSource.class);
-
-        if (result == null) {
-            return null;
-        }
-
-        // Compute the credit
-        return computeCredit(result.getSources());
-    }
+	public long getCreditOrZero(String currencyId, String pubKey) {
+		return getCreditOrZero(peerService.getActivePeerByCurrencyId(currencyId), pubKey);
+	}
 
     public Long getCredit(Peer peer, String pubKey) {
         if (log.isDebugEnabled()) {
@@ -193,7 +170,7 @@ public class TransactionRemoteServiceImpl extends BaseRemoteServiceImpl implemen
 
         // get parameter
         String path = String.format(URL_TX_SOURCES, pubKey);
-        TxSource result = executeRequest(peer, path, TxSource.class);
+        TxSource result = httpService.executeRequest(peer, path, TxSource.class);
 
         if (result == null) {
             return null;
@@ -203,8 +180,11 @@ public class TransactionRemoteServiceImpl extends BaseRemoteServiceImpl implemen
         return computeCredit(result.getSources());
     }
 
+	public Long getCredit(String currencyId, String pubKey) {
+		return getCredit(peerService.getActivePeerByCurrencyId(currencyId), pubKey);
+	}
 
-    public long computeCredit(TxSource.Source[] sources) {
+	public long computeCredit(TxSource.Source[] sources) {
         if (CollectionUtils.isEmpty(sources)) {
             return 0;
         }
@@ -216,22 +196,26 @@ public class TransactionRemoteServiceImpl extends BaseRemoteServiceImpl implemen
         return credit;
     }
 
-    public TxHistory getTxHistory(String currencyId, String pubKey, long fromBlockNumber, long toBlockNumber) {
+    public TxHistory getTxHistory(Peer peer, String pubKey, long start, long end) {
 		Preconditions.checkNotNull(pubKey);
-        Preconditions.checkArgument(fromBlockNumber >= 0);
-        Preconditions.checkArgument(fromBlockNumber <= toBlockNumber);
+        Preconditions.checkArgument(start >= 0);
+        Preconditions.checkArgument(start <= end);
 
         if (log.isDebugEnabled()) {
-			log.debug(String.format("Get TX history by pubKey [%s], from block [%s -> %s]", pubKey, fromBlockNumber, toBlockNumber));
+			log.debug(String.format("Get TX history by pubKey [%s], from block [%s -> %s]", pubKey, start, end));
 		}
 
         // get parameter
-        String path = String.format(URL_TX_HISTORY, pubKey, fromBlockNumber, toBlockNumber);
-		TxHistory result = executeRequest(currencyId, path, TxHistory.class);
+        String path = String.format(URL_TX_HISTORY, pubKey, start, end);
+		TxHistory result = httpService.executeRequest(peer, path, TxHistory.class);
 
         return result;
     }
 
+	public TxHistory getTxHistory(String currencyId, String pubKey, long start, long end) {
+		return getTxHistory(peerService.getActivePeerByCurrencyId(currencyId), pubKey, start, end);
+	}
+
 	/* -- internal methods -- */
 
 	protected String getSignedTransaction(Peer peer,
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/WotRemoteService.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/WotRemoteService.java
index f89c399f..4cc37b8c 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/WotRemoteService.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/WotRemoteService.java
@@ -25,10 +25,7 @@ package org.duniter.core.client.service.bma;
 import org.duniter.core.beans.Service;
 import org.duniter.core.client.model.bma.WotCertification;
 import org.duniter.core.client.model.bma.WotLookup;
-import org.duniter.core.client.model.local.Certification;
-import org.duniter.core.client.model.local.Identity;
-import org.duniter.core.client.model.local.Peer;
-import org.duniter.core.client.model.local.Wallet;
+import org.duniter.core.client.model.local.*;
 
 import java.util.Collection;
 import java.util.List;
@@ -39,50 +36,54 @@ public interface WotRemoteService extends Service {
 
     List<Identity> findIdentities(Set<String> currenciesIds, String uidOrPubKey);
 
+    WotLookup.Uid find(Peer peer, String uidOrPubKey);
     WotLookup.Uid find(String currencyId, String uidOrPubKey);
 
-    void getRequirments(String currencyId, String pubKey);
+    void getRequirements(String currencyId, String pubKey);
 
+    WotLookup.Uid findByUid(Peer peer, String uid);
     WotLookup.Uid findByUid(String currencyId, String uid);
 
-    WotLookup.Uid findByUidAndPublicKey(String currencyId, String uid, String pubKey);
-
     WotLookup.Uid findByUidAndPublicKey(Peer peer, String uid, String pubKey);
+    WotLookup.Uid findByUidAndPublicKey(String currencyId, String uid, String pubKey);
 
+    Identity getIdentity(Peer peer, String uid, String pubKey);
     Identity getIdentity(String currencyId, String uid, String pubKey);
 
+    Identity getIdentity(Peer peer, String pubKey);
     Identity getIdentity(String currencyId, String pubKey);
 
-    Identity getIdentity(Peer peer, String uid, String pubKey);
-
+    Collection<Certification> getCertifications(Peer peer, String uid, String pubkey, boolean isMember);
     Collection<Certification> getCertifications(String currencyId, String uid, String pubkey, boolean isMember);
 
+    WotCertification getCertifiedBy(Peer peer, String uid);
     WotCertification getCertifiedBy(String currencyId, String uid);
 
-    int countValidCertifiers(String currencyId, String pubkey);
-    
-    WotCertification getCertifiersOf(String currencyId, String uid);
+    long countValidCertifiers(Peer peer, String pubkey);
+    long countValidCertifiers(String currencyId, String pubkey);
 
-    String getSignedIdentity(String currency, byte[] pubKey, byte[] secKey, String uid, String blockUid);
+    WotCertification getCertifiersOf(Peer peer, String uid);
+    WotCertification getCertifiersOf(String currencyId, String uid);
 
-    Map<String, String> getMembersUids(String currencyId);
+    String getSignedIdentity(String currencyId, byte[] pubKey, byte[] secKey, String uid, String blockUid);
 
     Map<String, String> getMembersUids(Peer peer);
-
-    void sendIdentity(String currencyId, byte[] pubKey, byte[] secKey, String uid, String blockUid);
+    List<Member> getMembers(Peer peer);
+    List<Member> getMembers(String currencyId);
 
     void sendIdentity(Peer peer, String currency, byte[] pubKey, byte[] secKey, String uid, String blockUid);
-
-    String getCertification(byte[] pubKey, byte[] secKey, String userUid,
-                                   String userTimestamp,
-                                   String userSignature);
+    void sendIdentity(String currencyId, byte[] pubKey, byte[] secKey, String uid, String blockUid);
 
     String sendCertification(Wallet wallet, Identity identity);
 
+    String sendCertification(Peer peer,
+                             byte[] pubKey, byte[] secKey,
+                             String userUid, String userPubKeyHash,
+                             String userTimestamp, String userSignature);
+
     String sendCertification(String currencyId,
-                                    byte[] pubKey, byte[] secKey,
-                                  String uid, String timestamp,
-                                  String userUid, String userPubKeyHash,
+                             byte[] pubKey, byte[] secKey,
+                             String userUid, String userPubKeyHash,
                              String userTimestamp, String userSignature);
 
 }
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/WotRemoteServiceImpl.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/WotRemoteServiceImpl.java
index f2869f89..19d86c77 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/WotRemoteServiceImpl.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/bma/WotRemoteServiceImpl.java
@@ -23,18 +23,17 @@ package org.duniter.core.client.service.bma;
  */
 
 import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.apache.commons.collections4.MapUtils;
 import org.duniter.core.client.model.ModelUtils;
 import org.duniter.core.client.model.bma.*;
-import org.duniter.core.client.model.local.Certification;
-import org.duniter.core.client.model.local.Identity;
-import org.duniter.core.client.model.local.Peer;
-import org.duniter.core.client.model.local.Wallet;
+import org.duniter.core.client.model.local.*;
 import org.duniter.core.client.service.ServiceLocator;
 import org.duniter.core.client.service.local.CurrencyService;
 import org.duniter.core.exception.TechnicalException;
 import org.duniter.core.service.CryptoService;
 import org.duniter.core.util.CollectionUtils;
-import org.duniter.core.util.ObjectUtils;
 import org.duniter.core.util.Preconditions;
 import org.duniter.core.util.crypto.CryptoUtils;
 import org.apache.http.NameValuePair;
@@ -46,6 +45,7 @@ import org.slf4j.LoggerFactory;
 
 import java.io.UnsupportedEncodingException;
 import java.util.*;
+import java.util.stream.Collectors;
 
 public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRemoteService {
 
@@ -55,6 +55,8 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
 
     public static final String URL_ADD = URL_BASE + "/add";
 
+    public static final String URL_CERTIFY = URL_BASE + "/certify";
+
     public static final String URL_MEMBERS = URL_BASE + "/members";
 
     public static final String URL_LOOKUP = URL_BASE + "/lookup/%s";
@@ -88,13 +90,14 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
     }
 
     public List<Identity> findIdentities(Set<String> currenciesIds, String uidOrPubKey) {
-        List<Identity> result = new ArrayList<Identity>();
+        List<Identity> result = Lists.newArrayList();
 
         String path = String.format(URL_LOOKUP, uidOrPubKey);
 
         for (String currencyId: currenciesIds) {
 
-            WotLookup lookupResult = executeRequest(currencyId, path, WotLookup.class);
+            Peer peer = peerService.getActivePeerByCurrencyId(currencyId);
+            WotLookup lookupResult = httpService.executeRequest(peer, path, WotLookup.class);
 
             addAllIdentities(result, lookupResult, currencyId);
         }
@@ -102,14 +105,14 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
         return result;
     }
 
-    public WotLookup.Uid find(String currencyId, String uidOrPubKey) {
+    public WotLookup.Uid find(Peer peer, String uidOrPubKey) {
         if (log.isDebugEnabled()) {
             log.debug(String.format("Try to find user by looking up on [%s]", uidOrPubKey));
         }
 
         // get parameter
         String path = String.format(URL_LOOKUP, uidOrPubKey);
-        WotLookup lookupResults = executeRequest(currencyId, path, WotLookup.class);
+        WotLookup lookupResults = httpService.executeRequest(peer, path, WotLookup.class);
 
         for (WotLookup.Result result : lookupResults.getResults()) {
             if (CollectionUtils.isNotEmpty(result.getUids())) {
@@ -122,38 +125,50 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
 
     }
 
-    public Map<String, String> getMembersUids(String currencyId) {
-        // get /wot/members
-        JsonNode json = executeRequest(currencyId, URL_MEMBERS, JsonNode.class);
+    public WotLookup.Uid find(String currencyId, String uidOrPubKey) {
+        return find(peerService.getActivePeerByCurrencyId(currencyId), uidOrPubKey);
+    }
 
-        if (json == null  || !json.has("results")) return null;
+    @Override
+    public Map<String, String> getMembersUids(Peer peer) {
+        // get /wot/members
+        JsonNode json = httpService.executeRequest(peer, URL_MEMBERS, JsonNode.class);
 
-        Map<String, String> result = new HashMap<>();
+        if (json == null || !json.has("results")) return null;
 
+        Map<String, String> result = Maps.newHashMap();
         json.get("results").forEach(entry -> {
-            result.put(entry.get("pubkey").asText(), entry.get("uid").asText());
+            result.put(
+                    entry.get("pubkey").asText(),
+                    entry.get("uid").asText()
+            );
         });
         return result;
     }
 
-    public Map<String, String> getMembersUids(Peer peer) {
-        // get /wot/members
-        JsonNode json = executeRequest(peer, URL_MEMBERS, JsonNode.class);
+    public List<Member> getMembers(Peer peer) {
 
-        if (json == null || !json.has("results")) return null;
+        Map<String, String> map = getMembersUids(peer);
+        if (MapUtils.isEmpty(map)) return null;
 
-        Map<String, String> result = new HashMap<>();
+        return map.entrySet().stream().map(entry -> {
+            Member member = new Member();
+            member.setPubkey(entry.getKey());
+            member.setUid(entry.getValue());
+            member.setMember(true);
+            return member;
+        }).collect(Collectors.toList());
+    }
 
-        json.get("results").forEach(entry -> {
-            result.put(entry.get("pubkey").asText(), entry.get("uid").asText());
-        });
+    public List<Member> getMembers(String currencyId) {
+        List<Member> result = getMembers(peerService.getActivePeerByCurrencyId(currencyId));
+        result.forEach(m -> m.setCurrency(currencyId));
         return result;
     }
 
-
-    public void getRequirments(String currencyId, String pubKey) {
+    public void getRequirements(String currencyId, String pubKey) {
         if (log.isDebugEnabled()) {
-            log.debug(String.format("Try to find user requirements on [%s]", pubKey));
+            log.debug(String.format("TODO: implement /wot/requirements on [%s]", pubKey));
         }
         // get parameter
         String path = String.format(URL_REQUIREMENT, pubKey);
@@ -162,14 +177,14 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
 
     }
 
-    public WotLookup.Uid findByUid(String currencyId, String uid) {
+    public WotLookup.Uid findByUid(Peer peer, String uid) {
         if (log.isDebugEnabled()) {
             log.debug(String.format("Try to find user info by uid: %s", uid));
         }
 
         // call lookup
         String path = String.format(URL_LOOKUP, uid);
-        WotLookup lookupResults = executeRequest(currencyId, path, WotLookup.class);
+        WotLookup lookupResults = httpService.executeRequest(peer, path, WotLookup.class);
 
         // Retrieve the exact uid
         WotLookup.Uid uniqueResult = getUid(lookupResults, uid);
@@ -180,22 +195,12 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
         return uniqueResult;
     }
 
-    public WotLookup.Uid findByUidAndPublicKey(String currencyId, String uid, String pubKey) {
-        if (log.isDebugEnabled()) {
-            log.debug(String.format("Try to find user info by uid [%s] and pubKey [%s]", uid, pubKey));
-        }
-
-        // call lookup
-        String path = String.format(URL_LOOKUP, uid);
-        WotLookup lookupResults = executeRequest(currencyId, path, WotLookup.class);
-
-        // Retrieve the exact uid
-        WotLookup.Uid uniqueResult = getUidByUidAndPublicKey(lookupResults, uid, pubKey);
-        if (uniqueResult == null) {
-            return null;
-        }
+    public WotLookup.Uid findByUid(String currencyId, String uid) {
+        return findByUid(peerService.getActivePeerByCurrencyId(currencyId), uid);
+    }
 
-        return uniqueResult;
+    public WotLookup.Uid findByUidAndPublicKey(String currencyId, String uid, String pubKey) {
+        return findByUidAndPublicKey(peerService.getActivePeerByCurrencyId(currencyId), uid, pubKey);
     }
 
     public WotLookup.Uid findByUidAndPublicKey(Peer peer, String uid, String pubKey) {
@@ -205,7 +210,7 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
 
         // call lookup
         String path = String.format(URL_LOOKUP, uid);
-        WotLookup lookupResults = executeRequest(peer, path, WotLookup.class);
+        WotLookup lookupResults = httpService.executeRequest(peer, path, WotLookup.class);
 
         // Retrieve the exact uid
         WotLookup.Uid uniqueResult = getUidByUidAndPublicKey(lookupResults, uid, pubKey);
@@ -217,130 +222,113 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
     }
 
     public Identity getIdentity(String currencyId, String uid, String pubKey) {
+        return getIdentity(peerService.getActivePeerByCurrencyId(currencyId), uid, pubKey);
+    }
+
+    public Identity getIdentity(Peer peer, String uid, String pubKey) {
         if (log.isDebugEnabled()) {
             log.debug(String.format("Get identity by uid [%s] and pubKey [%s]", uid, pubKey));
         }
 
-        WotLookup.Uid lookupUid = findByUidAndPublicKey(currencyId, uid, pubKey);
+        WotLookup.Uid lookupUid = findByUidAndPublicKey(peer, uid, pubKey);
         if (lookupUid == null) {
             return null;
         }
-        return toIdentity(lookupUid);
-    }
 
-    public Identity getIdentity(String currencyId, String pubKey) {
-//        Log.d(TAG, String.format("Get identity by uid [%s] and pubKey [%s]", uid, pubKey));
-
-        WotLookup.Uid lookupUid = find(currencyId, pubKey);
-        if (lookupUid == null) {
-            return null;
-        }
         Identity result = toIdentity(lookupUid);
         result.setPubkey(pubKey);
-        result.setCurrencyId(currencyId);
         return result;
     }
 
-    public Identity getIdentity(Peer peer, String uid, String pubKey) {
+    public Identity getIdentity(String currencyId, String pubKey) {
+        return getIdentity(peerService.getActivePeerByCurrencyId(currencyId), pubKey);
+    }
+
+    @Override
+    public Identity getIdentity(Peer peer, String pubKey) {
         if (log.isDebugEnabled()) {
-            log.debug(String.format("Get identity by uid [%s] and pubKey [%s]", uid, pubKey));
+            log.debug(String.format("Get identity by pubKey [%s]", pubKey));
         }
 
-        WotLookup.Uid lookupUid = findByUidAndPublicKey(peer, uid, pubKey);
+        WotLookup.Uid lookupUid = find(peer, pubKey);
         if (lookupUid == null) {
             return null;
         }
-        return toIdentity(lookupUid);
+        Identity result = toIdentity(lookupUid);
+        result.setPubkey(pubKey);
+        result.setCurrency(peer.getCurrency());
+        return result;
     }
 
-    public Collection<Certification> getCertifications(String currencyId, String uid, String pubkey, boolean isMember) {
+
+    public Collection<Certification> getCertifications(Peer peer, String uid, String pubkey, boolean isMember) {
         Preconditions.checkNotNull(uid);
         Preconditions.checkNotNull(pubkey);
 
         if (isMember) {
-            return getCertificationsByPubkeyForMember(currencyId, pubkey, true);
+            return getCertificationsByPubkeyForMember(peer, pubkey, true);
         }
         else {
-            return getCertificationsByPubkeyForNonMember(currencyId, uid, pubkey);
+            return getCertificationsByPubkeyForNonMember(peer, uid, pubkey);
         }
     }
 
+    public Collection<Certification> getCertifications(String currencyId, String uid, String pubkey, boolean isMember) {
+        return getCertifications(peerService.getActivePeerByCurrencyId(currencyId), uid, pubkey, isMember);
+    }
 
-    public WotCertification getCertifiedBy(String currencyId, String uid) {
+    public WotCertification getCertifiedBy(Peer peer, String uid) {
         if (log.isDebugEnabled()) {
             log.debug(String.format("Try to get certifications done by uid: %s", uid));
         }
 
         // call certified-by
         String path = String.format(URL_CERTIFIED_BY, uid);
-        WotCertification result = executeRequest(currencyId, path, WotCertification.class);
+        WotCertification result = httpService.executeRequest(peer, path, WotCertification.class);
         
         return result;
+    }
+
+    public WotCertification getCertifiedBy(String currencyId, String uid) {
+        return getCertifiedBy(peerService.getActivePeerByCurrencyId(currencyId), uid);
 
     }
 
-    public int countValidCertifiers(String currencyId, String pubkey) {
+    public long countValidCertifiers(Peer peer, String pubkey) {
         if (log.isDebugEnabled()) {
             log.debug(String.format("Try to count valid certifications done by pubkey: %s", pubkey));
         }
 
-        int count =0;
-
         // call certified-by
-        Collection<Certification> certifiersOf = getCertificationsByPubkeyForMember(currencyId, pubkey, false/*only certifiers of*/);
-        if (CollectionUtils.isEmpty(certifiersOf)) {
-            return 0;
-        }
-
-        for(Certification certifier : certifiersOf){
-            if(certifier.isValid()){
-                count++;
-            }
-        }
+        Collection<Certification> certifiersOf = getCertificationsByPubkeyForMember(peer, pubkey, false/*only certifiers of*/);
+        if (CollectionUtils.isEmpty(certifiersOf)) return 0;
 
-        return count;
+        return certifiersOf.stream().filter(Certification::isValid).count();
+    }
 
+    public long countValidCertifiers(String currencyId, String pubkey) {
+        return countValidCertifiers(peerService.getActivePeerByCurrencyId(currencyId), pubkey);
     }
     
-    public WotCertification getCertifiersOf(String currencyId, String uid) {
+    public WotCertification getCertifiersOf(Peer peer, String uid) {
         if (log.isDebugEnabled()) {
             log.debug(String.format("Try to get certifications done to uid: %s", uid));
         }
 
         // call certifiers-of
         String path = String.format(URL_CERTIFIERS_OF, uid);
-        WotCertification result = executeRequest(currencyId, path, WotCertification.class);
+        WotCertification result = httpService.executeRequest(peer, path, WotCertification.class);
         
         return result;
     }
 
-
-    public void sendIdentity(String currencyId, byte[] pubKey, byte[] secKey, String userId, String blockUid) {
-        // http post /wot/add
-        HttpPost httpPost = new HttpPost(getPath(currencyId, URL_ADD));
-
-        String currency = currencyService.getCurrencyNameById(currencyId);
-
-        // compute the self-certification
-        String identity = getSignedIdentity(currency, pubKey, secKey, userId, blockUid);
-
-        List<NameValuePair> urlParameters = new ArrayList<NameValuePair>();
-        urlParameters.add(new BasicNameValuePair("identity", identity));
-
-        try {
-            httpPost.setEntity(new UrlEncodedFormEntity(urlParameters));
-        }
-        catch(UnsupportedEncodingException e) {
-            throw new TechnicalException(e);
-        }
-
-        // Execute the request
-        executeRequest(httpPost, String.class);
+    public WotCertification getCertifiersOf(String currencyId, String uid) {
+        return getCertifiersOf(peerService.getActivePeerByCurrencyId(currencyId), uid);
     }
 
     public void sendIdentity(Peer peer, String currency, byte[] pubKey, byte[] secKey, String uid, String blockUid) {
         // http post /wot/add
-        HttpPost httpPost = new HttpPost(getPath(peer, URL_ADD));
+        HttpPost httpPost = new HttpPost(httpService.getPath(peer, URL_ADD));
 
         // compute the self-certification
         String identity = getSignedIdentity(currency, pubKey, secKey, uid, blockUid);
@@ -356,34 +344,27 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
         }
 
         // Execute the request
-        executeRequest(httpPost, String.class);
+        httpService.executeRequest(httpPost, String.class);
     }
 
-    public String sendCertification(Wallet wallet,
-                                    Identity identity) {
-        return sendCertification(
-                    wallet.getCurrencyId(),
-                    wallet.getPubKey(),
-                    wallet.getSecKey(),
-                    wallet.getIdentity().getUid(),
-                    wallet.getIdentity().getTimestamp(),
-                    identity.getUid(),
-                    identity.getPubkey(),
-                    identity.getTimestamp(),
-                    identity.getSignature());
+    public void sendIdentity(String currencyId, byte[] pubKey, byte[] secKey, String uid, String blockUid) {
+        String currency = currencyService.getNameById(currencyId);
+        sendIdentity(peerService.getActivePeerByCurrencyId(currencyId), currency, pubKey, secKey, uid, blockUid);
     }
 
-    public String sendCertification(String currencyId,
-                                    byte[] pubKey, byte[] secKey,
-                                  String uid, String timestamp,
-                                  String userUid, String userPubKeyHash,
-                                  String userBlockUid, String userSignature) {
+    public String sendCertification(Peer peer,
+                                    byte[] pubKey,
+                                    byte[] secKey,
+                                    String idtyUid,
+                                    String idtyIssuer,
+                                    String idtyBlockUid,
+                                    String idtySignature) {
         // http post /wot/add
-        HttpPost httpPost = new HttpPost(getPath(currencyId, URL_ADD));
+        HttpPost httpPost = new HttpPost(httpService.getPath(peer, URL_CERTIFY));
 
         // Read the current block (number and hash)
         BlockchainRemoteService blockchainService = ServiceLocator.instance().getBlockchainRemoteService();
-        BlockchainBlock currentBlock = blockchainService.getCurrentBlock(currencyId);
+        BlockchainBlock currentBlock = blockchainService.getCurrentBlock(peer);
         int blockNumber = currentBlock.getNumber();
         String blockHash = (blockNumber != 0)
                 ? currentBlock.getHash()
@@ -392,20 +373,16 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
         // Compute the pub key hash
         String pubKeyHash = CryptoUtils.encodeBase58(pubKey);
 
-        // compute signed identity
-        String identity = getIdentity(currentBlock.getCurrency(),
-                pubKeyHash, userUid, userBlockUid, userSignature);
-
         // Compute the certification
-        String certification = null; /* FIXME getCertification(pubKey, secKey,
-                userUid, userBlockUid, userSignature,
-                blockNumber, blockHash);*/
-        String inlineCertification = toInlineCertification(pubKeyHash, userPubKeyHash, certification);
+        String certification = getCertification(
+                currentBlock.getCurrency(),
+                pubKeyHash,
+                secKey,
+                idtyIssuer, idtyUid, idtyBlockUid, idtySignature,
+                blockNumber, blockHash);
 
         List<NameValuePair> urlParameters = new ArrayList<NameValuePair>();
-        urlParameters.add(new BasicNameValuePair("identity", identity));
-        urlParameters.add(new BasicNameValuePair("self", identity));
-        urlParameters.add(new BasicNameValuePair("other", inlineCertification));
+        urlParameters.add(new BasicNameValuePair("cert", certification));
 
         try {
             httpPost.setEntity(new UrlEncodedFormEntity(urlParameters));
@@ -413,12 +390,35 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
         catch(UnsupportedEncodingException e) {
             throw new TechnicalException(e);
         }
-        String selfResult = executeRequest(httpPost, String.class);
-        log.debug("received from /add: " + selfResult);
+        String selfResult = httpService.executeRequest(httpPost, String.class);
+        log.debug("received from /wot/certify: " + selfResult);
 
         return selfResult;
     }
 
+    public String sendCertification(String currencyId,
+                                    byte[] pubKey, byte[] secKey,
+                                    String idtyIssuer,
+                                    String idtyUid,
+                                    String idtyBlockUid,
+                                    String idtySignature) {
+        return sendCertification(
+                peerService.getActivePeerByCurrencyId(currencyId),
+                pubKey, secKey, idtyIssuer, idtyUid,idtyBlockUid, idtySignature);
+    }
+
+    public String sendCertification(Wallet wallet,
+                                    Identity identity) {
+        return sendCertification(
+                wallet.getCurrencyId(),
+                wallet.getPubKey(),
+                wallet.getSecKey(),
+                identity.getUid(),
+                identity.getPubkey(),
+                identity.getTimestamp(),
+                identity.getSignature());
+    }
+
     public void addAllIdentities(List<Identity> result, WotLookup lookupResults, String currencyName) {
 
         for (WotLookup.Result lookupResult: lookupResults.getResults()) {
@@ -433,7 +433,7 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
 
                 // Fill currency id and name
                 // TODO
-                target.setCurrencyId(currencyName);
+                target.setCurrency(currencyName);
 
                 result.add(target);
             }
@@ -471,10 +471,10 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
 
     /* -- Internal methods -- */
 
-    protected Collection<Certification> getCertificationsByPubkeyForMember(String currencyId, String pubkey, boolean onlyCertifiersOf) {
+    protected Collection<Certification> getCertificationsByPubkeyForMember(Peer peer, String pubkey, boolean onlyCertifiersOf) {
 
-        BlockchainParameters bcParameter = bcService.getParameters(currencyId, true);
-        BlockchainBlock currentBlock = bcService.getCurrentBlock(currencyId, true);
+        BlockchainParameters bcParameter = bcService.getParameters(peer, true);
+        BlockchainBlock currentBlock = bcService.getCurrentBlock(peer, true);
         long medianTime = currentBlock.getMedianTime();
         int sigValidity = bcParameter.getSigValidity();
         int sigQty = bcParameter.getSigQty();
@@ -482,14 +482,14 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
         Collection<Certification> result = new TreeSet<Certification>(ModelUtils.newWotCertificationComparatorByUid());
 
         // Certifiers of
-        WotCertification certifiersOfList = getCertifiersOf(currencyId, pubkey);
+        WotCertification certifiersOfList = getCertifiersOf(peer, pubkey);
         boolean certifiersOfIsEmpty = (certifiersOfList == null
                 || certifiersOfList.getCertifications() == null);
         int validWrittenCertifiersCount = 0;
         if (!certifiersOfIsEmpty) {
             for (WotCertification.Certification certifier : certifiersOfList.getCertifications()) {
 
-                Certification cert = toCertification(certifier, currencyId);
+                Certification cert = toCertification(certifier);
                 cert.setCertifiedBy(false);
                 result.add(cert);
 
@@ -521,14 +521,14 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
         if (!onlyCertifiersOf) {
 
             // Certified by
-            WotCertification certifiedByList = getCertifiedBy(currencyId, pubkey);
+            WotCertification certifiedByList = getCertifiedBy(peer, pubkey);
             boolean certifiedByIsEmpty = (certifiedByList == null
                     || certifiedByList.getCertifications() == null);
 
             if (!certifiedByIsEmpty) {
                 for (WotCertification.Certification certifiedBy : certifiedByList.getCertifications()) {
 
-                    Certification cert = toCertification(certifiedBy, currencyId);
+                    Certification cert = toCertification(certifiedBy);
                     cert.setCertifiedBy(true);
                     result.add(cert);
 
@@ -552,7 +552,14 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
         return result;
     }
 
-    protected Collection<Certification> getCertificationsByPubkeyForNonMember(String currencyId, final String uid, final String pubkey) {
+    protected Collection<Certification> getCertificationsByPubkeyForMember(final String currencyId, String pubkey, boolean onlyCertifiersOf) {
+        Collection<Certification> result = getCertificationsByPubkeyForMember(peerService.getActivePeerByCurrencyId(currencyId), pubkey, onlyCertifiersOf);
+        result.forEach(c -> c.setCurrencyId(currencyId));
+        return result;
+    }
+
+
+    protected Collection<Certification> getCertificationsByPubkeyForNonMember(Peer peer, final String uid, final String pubkey) {
         // Ordered list, by uid/pubkey/cert time
 
         Collection<Certification> result = new TreeSet<>(ModelUtils.newWotCertificationComparatorByUid());
@@ -563,7 +570,7 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
 
         // call lookup
         String path = String.format(URL_LOOKUP, pubkey);
-        WotLookup lookupResults = executeRequest(currencyId, path, WotLookup.class);
+        WotLookup lookupResults = httpService.executeRequest(peer, path, WotLookup.class);
 
         // Retrieve the exact uid
         WotLookup.Uid lookupUId = getUidByUidAndPublicKey(lookupResults, uid, pubkey);
@@ -572,7 +579,7 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
         Map<String, Certification> certifierByPubkeys = new HashMap<>();
         if (lookupUId != null && lookupUId.getOthers() != null) {
             for(WotLookup.OtherSignature lookupSignature: lookupUId.getOthers()) {
-                Collection<Certification> certifiers = toCertifierCertifications(lookupSignature, currencyId);
+                Collection<Certification> certifiers = toCertifierCertifications(lookupSignature);
                 result.addAll(certifiers);
             }
         }
@@ -584,9 +591,6 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
                     for(WotLookup.SignedSignature lookupSignature : lookupResult.getSigned()) {
                         Certification certifiedBy = toCertifiedByCerticication(lookupSignature);
 
-                        // Set the currency Id
-                        certifiedBy.setCurrencyId(currencyId);
-
                         // If exists, link to other side certification
                         String certifiedByPubkey = certifiedBy.getPubkey();
                         if (certifierByPubkeys.containsKey(certifiedByPubkey)) {
@@ -609,6 +613,12 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
         return result;
     }
 
+    protected Collection<Certification> getCertificationsByPubkeyForNonMember(String currencyId, final String uid, final String pubkey) {
+        Collection<Certification> result = getCertificationsByPubkeyForNonMember(peerService.getActivePeerByCurrencyId(currencyId), uid, pubkey);
+        result.forEach(c -> c.setCurrencyId(currencyId));
+        return result;
+    }
+
     protected String toInlineCertification(String pubKeyHash,
                                            String userPubKeyHash,
                                            String certification) {
@@ -642,12 +652,26 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
                 .toString();
     }
 
-    public String getCertification(byte[] pubKey, byte[] secKey, String userUid,
-                                   String userTimestamp,
-                                   String userSignature) {
+    public String getCertification(String currency,
+                                   String issuer,
+                                   byte[] secKey,
+                                   String idtyIssuer,
+                                   String idtyUid,
+                                   String idtyTimestamp,
+                                   String idtySignature,
+                                   int certBlockNumber,
+                                   String certBlockHash) {
+
         // Create the self part to sign
         String unsignedCertification = getCertificationUnsigned(
-                userUid, userTimestamp, userSignature);
+                currency,
+                issuer,
+                idtyIssuer,
+                idtyUid,
+                idtyTimestamp,
+                idtySignature,
+                certBlockNumber,
+                certBlockHash);
 
         // Compute the signature
         String signature = cryptoService.sign(unsignedCertification, secKey);
@@ -660,21 +684,25 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
                 .toString();
     }
 
-    protected String getCertificationUnsigned(String userUid,
-                                      String userTimestamp,
-                                      String userSignature) {
+    protected String getCertificationUnsigned(String currency,
+                                              String issuer,
+                                              String idtyPubkey,
+                                              String idtyUid,
+                                              String idtyTimestamp,
+                                              String idtySignature,
+                                              int certBlockNumber,
+                                              String certBlockHash) {
         // Create the self part to sign
         return new StringBuilder()
-                .append("UID:")
-                .append(userUid)
-                .append("\nMETA:TS:")
-                .append(userTimestamp)
-                .append('\n')
-                .append(userSignature)
-                /*.append("\nMETA:TS:")
-                .append(blockNumber)
-                .append('-')
-                .append(blockHash)*/
+                .append("Version: ").append(Protocol.VERSION)
+                .append("\nType: ").append(Protocol.TYPE_CERTIFICATION)
+                .append("\nCurrency: ").append(currency)
+                .append("\nIssuer: ").append(issuer)
+                .append("\nIdtyIssuer: ").append(idtyPubkey)
+                .append("\nIdtyUniqueID: ").append(idtyUid)
+                .append("\nIdtyTimestamp: ").append(idtyTimestamp)
+                .append("\nIdtySignature: ").append(idtySignature)
+                .append("\nCertTimestamp: ").append(certBlockNumber).append('-').append(certBlockHash)
                 .append('\n').toString();
     }
 
@@ -724,6 +752,9 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
     protected WotLookup.Uid getUidByUidAndPublicKey(WotLookup lookupResults,
                                                    String filterUid,
                                                    String filterPublicKey) {
+        Preconditions.checkNotNull(filterUid);
+        Preconditions.checkNotNull(filterPublicKey);
+
         if (lookupResults.getResults() == null || lookupResults.getResults().length == 0) {
             return null;
         }
@@ -744,17 +775,16 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
         return null;
     }
 
-    private Certification toCertification(final WotCertification.Certification source, final String currencyId) {
+    private Certification toCertification(final WotCertification.Certification source) {
         Certification target = new Certification();
         target.setPubkey(source.getPubkey());
         target.setUid(source.getUid());
         target.setMember(source.getIsMember());
-        target.setCurrencyId(currencyId);
 
         return target;
     }
 
-    private Collection<Certification> toCertifierCertifications(final WotLookup.OtherSignature source, final String currencyId) {
+    private Collection<Certification> toCertifierCertifications(final WotLookup.OtherSignature source) {
         List<Certification> result = new ArrayList<Certification>();
         // If only one uid
         if (source.getUids().length == 1) {
@@ -772,8 +802,6 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
             // Is member
             target.setMember(source.isMember());
 
-            // Set currency Id
-            target.setCurrencyId(currencyId);
 
             result.add(target);
         }
@@ -793,9 +821,6 @@ public class WotRemoteServiceImpl extends BaseRemoteServiceImpl implements WotRe
                 // Is member
                 target.setMember(source.isMember());
 
-                // Set currency Id
-                target.setCurrencyId(currencyId);
-
                 result.add(target);
             }
         }
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/elasticsearch/CurrencyRegistryRemoteServiceImpl.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/elasticsearch/CurrencyRegistryRemoteServiceImpl.java
index bfc93ec1..8ea61b6a 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/elasticsearch/CurrencyRegistryRemoteServiceImpl.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/elasticsearch/CurrencyRegistryRemoteServiceImpl.java
@@ -101,8 +101,8 @@ public class CurrencyRegistryRemoteServiceImpl extends BaseRemoteServiceImpl imp
         }
 
         // get currency
-        String path = getPath(peer, URL_ALL_CURRENCY_NAMES);
-        String jsonResponse = executeRequest(new HttpGet(path), String.class);
+        String path = httpService.getPath(peer, URL_ALL_CURRENCY_NAMES);
+        String jsonResponse = httpService.executeRequest(new HttpGet(path), String.class);
 
         List<String> currencyNames = new JsonAttributeParser<>("currencyName", String.class).getValues(jsonResponse);
 
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/local/CurrencyService.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/local/CurrencyService.java
index 45b2e791..3f9809c4 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/local/CurrencyService.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/local/CurrencyService.java
@@ -36,41 +36,37 @@ public interface CurrencyService extends Service {
 
     Currency save(final Currency currency);
 
-    List<Currency> getCurrencies(long accountId);
+    List<Currency> getAll();
 
-    Currency getCurrencyById(String currencyId);
+    List<Currency> getAllByAccount(long accountId);
+
+    Currency getById(String currencyId);
 
     /**
      * Return a (cached) currency name, by id
      * @param currencyId
      * @return
      */
-    String getCurrencyNameById(String currencyId);
+    String getNameById(String currencyId);
 
     /**
      * Return a currency id, by name
      * @param currencyName
      * @return
      */
-    String getCurrencyIdByName(String currencyName);
+    String getIdByName(String currencyName);
 
     /**
      * Return a (cached) list of currency ids
      * @return
      */
-    Set<String> getCurrencyIds();
+    Set<String> getAllIds();
 
     /**
      * Return a (cached) number of registered currencies
      * @return
      */
-    int getCurrencyCount();
-
-    /**
-     * Fill allOfToList cache need for currencies
-     * @param context
-     */
-    void loadCache(long accountId);
+    int count();
 
     /**
      * Return the value of the last universal dividend
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/local/CurrencyServiceImpl.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/local/CurrencyServiceImpl.java
index 50fcb9b1..ccee8dee 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/local/CurrencyServiceImpl.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/local/CurrencyServiceImpl.java
@@ -27,6 +27,7 @@ import org.duniter.core.client.dao.CurrencyDao;
 import org.duniter.core.client.model.local.Currency;
 import org.duniter.core.client.service.ServiceLocator;
 import org.duniter.core.client.service.bma.BlockchainRemoteService;
+import org.duniter.core.util.CollectionUtils;
 import org.duniter.core.util.ObjectUtils;
 import org.duniter.core.util.Preconditions;
 import org.duniter.core.util.StringUtils;
@@ -37,6 +38,7 @@ import java.io.IOException;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 
 /**
@@ -62,11 +64,8 @@ public class CurrencyServiceImpl implements CurrencyService, InitializingBean {
         blockchainRemoteService = ServiceLocator.instance().getBlockchainRemoteService();
         currencyDao = ServiceLocator.instance().getBean(CurrencyDao.class);
 
-        // Load cache from account
-        long accountId = ServiceLocator.instance().getDataContext().getAccountId();
-        if (accountId != -1) {
-            loadCache(accountId);
-        }
+        // Load cache
+        initCaches();
     }
 
     @Override
@@ -76,13 +75,13 @@ public class CurrencyServiceImpl implements CurrencyService, InitializingBean {
     }
 
     public Currency save(final Currency currency) {
-        ObjectUtils.checkNotNull(currency);
-        ObjectUtils.checkArgument(StringUtils.isNotBlank(currency.getCurrencyName()));
-        ObjectUtils.checkArgument(StringUtils.isNotBlank(currency.getFirstBlockSignature()));
-        ObjectUtils.checkNotNull(currency.getMembersCount());
-        ObjectUtils.checkArgument(currency.getMembersCount().intValue() >= 0);
-        ObjectUtils.checkNotNull(currency.getLastUD());
-        ObjectUtils.checkArgument(currency.getLastUD().longValue() > 0);
+        Preconditions.checkNotNull(currency);
+        Preconditions.checkArgument(StringUtils.isNotBlank(currency.getId()));
+        Preconditions.checkArgument(StringUtils.isNotBlank(currency.getFirstBlockSignature()));
+        Preconditions.checkNotNull(currency.getMembersCount());
+        Preconditions.checkArgument(currency.getMembersCount().intValue() >= 0);
+        Preconditions.checkNotNull(currency.getLastUD());
+        Preconditions.checkArgument(currency.getLastUD().longValue() > 0);
 
         Currency result;
 
@@ -106,12 +105,18 @@ public class CurrencyServiceImpl implements CurrencyService, InitializingBean {
         return result;
     }
 
-    public List<Currency> getCurrencies(long accountId) {
-        return currencyDao.getCurrencies(accountId);
+    public List<Currency> getAllByAccount(long accountId) {
+        return currencyDao.getAllByAccount(accountId);
     }
 
+    public List<Currency> getAll() {
+        Set<String> ids = currencyDao.getAllIds();
+        return ids.stream()
+                .map(id -> getById(id))
+                .collect(Collectors.toList());
+    }
 
-    public Currency getCurrencyById(String currencyId) {
+    public Currency getById(String currencyId) {
         return mCurrencyCache.get(currencyId);
     }
 
@@ -120,12 +125,12 @@ public class CurrencyServiceImpl implements CurrencyService, InitializingBean {
      * @param currencyId
      * @return
      */
-    public String getCurrencyNameById(String currencyId) {
-        Currency currency = mCurrencyCache.getIfPresent(currencyId);
+    public String getNameById(String currencyId) {
+        Currency currency = mCurrencyCache != null ? mCurrencyCache.getIfPresent(currencyId) : null;
         if (currency == null) {
             return null;
         }
-        return currency.getCurrencyName();
+        return currency.getId();
     }
 
     /**
@@ -133,13 +138,13 @@ public class CurrencyServiceImpl implements CurrencyService, InitializingBean {
      * @param currencyName
      * @return
      */
-    public String getCurrencyIdByName(String currencyName) {
+    public String getIdByName(String currencyName) {
         Preconditions.checkArgument(StringUtils.isNotBlank(currencyName));
 
         // Search from currencies
         for (Map.Entry<String, Currency> entry : mCurrencyCache.entrySet()) {
             Currency currency = entry.getValue();
-            if (ObjectUtils.equals(currencyName, currency.getCurrencyName())) {
+            if (ObjectUtils.equals(currencyName, currency.getId())) {
                 return entry.getKey();
             }
         }
@@ -150,62 +155,65 @@ public class CurrencyServiceImpl implements CurrencyService, InitializingBean {
      * Return a (cached) list of currency ids
      * @return
      */
-    public Set<String> getCurrencyIds() {
-        return mCurrencyCache.keySet();
+    public Set<String> getAllIds() {
+        Set<String> ids = mCurrencyCache.keySet();
+        if (CollectionUtils.isEmpty(ids)) {
+            ids = currencyDao.getAllIds();
+        }
+        return ids;
     }
 
     /**
      * Return a (cached) number of registered currencies
      * @return
      */
-    public int getCurrencyCount() {
+    public int count() {
         return mCurrencyCache.entrySet().size();
     }
 
-
     /**
      * Fill allOfToList cache need for currencies
-     * @param accountId
      */
-    public void loadCache(long accountId) {
-        if (mCurrencyCache == null || mUDCache == null) {
-            // Create and fill the currency cache
-            List<Currency> currencies = getCurrencies(accountId);
-            if (mCurrencyCache == null) {
-
-                mCurrencyCache = new SimpleCache<String, Currency>() {
-                    @Override
-                    public Currency load(String currencyId) {
-                        return currencyDao.getById(currencyId);
-                    }
-                };
+    public void initCaches() {
+        if (mCurrencyCache != null && mUDCache != null) return;
+
+        // Create and fill the currency cache
+        if (mCurrencyCache == null) {
 
-                // Fill the cache
-                for (Currency currency : currencies) {
-                    mCurrencyCache.put(currency.getId(), currency);
+            mCurrencyCache = new SimpleCache<String, Currency>() {
+                @Override
+                public Currency load(String currencyId) {
+                    return currencyDao.getById(currencyId);
                 }
-            }
+            };
 
-            // Create the UD cache
-            if (mUDCache == null) {
+            // Fill cache for the configured account
+            long accountId = ServiceLocator.instance().getDataContext().getAccountId();
+            List<Currency> currencies = (accountId != -1) ? getAllByAccount(accountId) : getAll();
+            for (Currency currency : currencies) {
+                mCurrencyCache.put(currency.getId(), currency);
+            }
+        }
 
-                mUDCache = new SimpleCache<String, Long>(UD_CACHE_TIME_MILLIS) {
-                    @Override
-                    public Long load(final String currencyId) {
-                        // Retrieve the last UD from the blockchain
-                        final Long lastUD = blockchainRemoteService.getLastUD(currencyId);
+        // Create the UD cache
+        if (mUDCache == null) {
 
-                        // Update currency
-                        Currency currency = getCurrencyById(currencyId);
-                        if (!ObjectUtils.equals(currency.getLastUD(), lastUD)) {
-                            currency.setLastUD(lastUD);
-                            currencyDao.update(currency);
-                        }
+            mUDCache = new SimpleCache<String, Long>(UD_CACHE_TIME_MILLIS) {
+                @Override
+                public Long load(final String currencyId) {
+                    // Retrieve the last UD from the blockchain
+                    final Long lastUD = blockchainRemoteService.getLastUD(currencyId);
 
-                        return lastUD;
+                    // Update currency
+                    Currency currency = getById(currencyId);
+                    if (!ObjectUtils.equals(currency.getLastUD(), lastUD)) {
+                        currency.setLastUD(lastUD);
+                        currencyDao.update(currency);
                     }
-                };
-            }
+
+                    return lastUD;
+                }
+            };
         }
     }
 
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/local/NetworkServiceImpl.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/local/NetworkServiceImpl.java
index d6110585..8df91db7 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/local/NetworkServiceImpl.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/local/NetworkServiceImpl.java
@@ -25,6 +25,7 @@ package org.duniter.core.client.service.local;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
 import org.duniter.core.client.config.Configuration;
 import org.duniter.core.client.model.bma.*;
 import org.duniter.core.client.model.local.Peer;
@@ -370,7 +371,7 @@ public class NetworkServiceImpl extends BaseRemoteServiceImpl implements Network
         final String currency = filter != null && filter.currency != null ? filter.currency :
                 blockchainRemoteService.getParameters(mainPeer).getCurrency();
 
-        final List<String> knownBlocks = new ArrayList<>();
+        final Set<String> knownBlocks = Sets.newHashSet();
         final Predicate<Peer> peerFilter = peerFilter(filter);
         final Comparator<Peer> peerComparator = peerComparator(sort);
         final ExecutorService pool = (executor != null) ? executor : ForkJoinPool.commonPool();
@@ -378,12 +379,8 @@ public class NetworkServiceImpl extends BaseRemoteServiceImpl implements Network
 
         // Refreshing one peer (e.g. received from WS)
         Consumer<List<Peer>> updateKnownBlocks = (updatedPeers) ->
-            updatedPeers.forEach(peer -> {
-                String buid = Peers.buid(peer);
-                if (!knownBlocks.contains(buid)) {
-                    knownBlocks.add(buid);
-                }
-            });
+            knownBlocks.addAll(updatedPeers.stream().map(Peers::buid).collect(Collectors.toSet()))
+        ;
 
         // Load all peers
         Runnable loadAllPeers = () -> {
diff --git a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/local/PeerServiceImpl.java b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/local/PeerServiceImpl.java
index a39e51f2..a459e0b1 100644
--- a/duniter4j-core-client/src/main/java/org/duniter/core/client/service/local/PeerServiceImpl.java
+++ b/duniter4j-core-client/src/main/java/org/duniter/core/client/service/local/PeerServiceImpl.java
@@ -31,7 +31,6 @@ import org.duniter.core.client.service.ServiceLocator;
 import org.duniter.core.exception.TechnicalException;
 import org.duniter.core.service.CryptoService;
 import org.duniter.core.util.CollectionUtils;
-import org.duniter.core.util.ObjectUtils;
 import org.duniter.core.util.Preconditions;
 import org.duniter.core.util.StringUtils;
 import org.duniter.core.util.cache.Cache;
@@ -170,7 +169,7 @@ public class PeerServiceImpl implements PeerService, InitializingBean {
             }
         };
 
-        List<Currency> currencies = ServiceLocator.instance().getCurrencyService().getCurrencies(accountId);
+        List<Currency> currencies = ServiceLocator.instance().getCurrencyService().getAllByAccount(accountId);
 
         for (Currency currency: currencies) {
             // Get peers from DB
@@ -232,13 +231,23 @@ public class PeerServiceImpl implements PeerService, InitializingBean {
     protected Peer loadDefaultPeer(String currencyId) {
         List<Peer> peers = peerDao.getPeersByCurrencyId(currencyId);
         if (CollectionUtils.isEmpty(peers)) {
-            String currencyName = currencyService.getCurrencyNameById(currencyId);
             throw new TechnicalException(String.format(
                     "No peers configure for currency [%s]",
-                    currencyName != null ? currencyName : currencyId));
+                    currencyId));
         }
 
-        return peers.get(0);
+        Peer defaultPeer = peers.stream()
+                .filter(peer -> peer.getStats() == null || peer.getStats().getStatus() == null || peer.getStats().getStatus() == Peer.PeerStatus.UP)
+                .findFirst().orElse(null);
+        if (defaultPeer != null) {
+            // Make sure currency is filled
+            defaultPeer.setCurrency(currencyId);
+        }
+        else {
+            log.warn(String.format("[%s] No default peer found. Unable to send remote request.", currencyId));
+        }
+
+        return defaultPeer;
     }
 
 }
diff --git a/duniter4j-core-client/src/test/java/org/duniter/core/client/service/bma/BlockchainRemoteServiceTest.java b/duniter4j-core-client/src/test/java/org/duniter/core/client/service/bma/BlockchainRemoteServiceTest.java
index cc92dee0..dc539d76 100644
--- a/duniter4j-core-client/src/test/java/org/duniter/core/client/service/bma/BlockchainRemoteServiceTest.java
+++ b/duniter4j-core-client/src/test/java/org/duniter/core/client/service/bma/BlockchainRemoteServiceTest.java
@@ -28,6 +28,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import org.duniter.core.client.TestResource;
 import org.duniter.core.client.config.Configuration;
 import org.duniter.core.client.model.bma.BlockchainBlock;
+import org.duniter.core.client.model.bma.BlockchainDifficulties;
 import org.duniter.core.client.model.bma.BlockchainParameters;
 import org.duniter.core.client.model.bma.ErrorCode;
 import org.duniter.core.client.model.bma.jackson.JacksonUtils;
@@ -189,6 +190,18 @@ public class BlockchainRemoteServiceTest {
         }
     }
 
+    @Test
+    public void getDifficulties() {
+        Peer peer = createTestPeer();
+
+        BlockchainDifficulties result = service.getDifficulties(peer);
+        Assert.assertNotNull(result);
+        Assert.assertNotNull(result.getBlock());
+
+        Assert.assertNotNull(result.getLevels());
+        Assert.assertTrue(result.getLevels().length > 0);
+    }
+
     /* -- Internal methods -- */
 
     protected Peer createTestPeer() {
diff --git a/duniter4j-core-client/src/test/java/org/duniter/core/client/service/bma/WotRemoteServiceTest.java b/duniter4j-core-client/src/test/java/org/duniter/core/client/service/bma/WotRemoteServiceTest.java
index 7d781c16..a58bb52f 100644
--- a/duniter4j-core-client/src/test/java/org/duniter/core/client/service/bma/WotRemoteServiceTest.java
+++ b/duniter4j-core-client/src/test/java/org/duniter/core/client/service/bma/WotRemoteServiceTest.java
@@ -27,6 +27,7 @@ import org.duniter.core.client.TestResource;
 import org.duniter.core.client.config.Configuration;
 import org.duniter.core.client.model.bma.ErrorCode;
 import org.duniter.core.client.model.local.Identity;
+import org.duniter.core.client.model.local.Member;
 import org.duniter.core.client.model.local.Peer;
 import org.duniter.core.client.model.local.Wallet;
 import org.duniter.core.client.service.ServiceLocator;
@@ -156,6 +157,33 @@ public class WotRemoteServiceTest {
         }
 	}
 
+	@Test
+	public void sendCertification()  {
+		Peer peer = createTestPeer();
+		Wallet wallet = createTestWallet();
+		WotRemoteService service = ServiceLocator.instance().getWotRemoteService();
+
+		Identity result = service.getIdentity(peer, "kimamila", "5ocqzyDMMWf1V8bsoNhWb1iNwax1e9M7VTUN6navs8of");
+		Assert.assertNotNull(result);
+		Assert.assertNotNull(result.getUid());
+		Assert.assertNotNull(result.getPubkey());
+
+		try {
+			service.sendCertification(wallet, result);
+		} catch (BmaTechnicalException e) {
+			// Test user is not a member: an 1002 should be return
+			Assert.assertTrue(e.getCode() == 1002);
+		}
+	}
+
+	@Test
+	public void getMembers() {
+		Peer peer = createTestPeer();
+		List<Member> result = service.getMembers(peer);
+		Assert.assertNotNull(result);
+		Assert.assertTrue(result.size() > 0);
+	}
+
 	/* -- internal methods */
 
 	protected Wallet createTestWallet() {
-- 
GitLab