diff --git a/silkaj/cli.py b/silkaj/cli.py
index 200298e845e03bb972a20aab3a0890c01d394a62..bcd73bec240f1c9dbbed811858996a505b379a2e 100644
--- a/silkaj/cli.py
+++ b/silkaj/cli.py
@@ -26,10 +26,10 @@ from silkaj.cert import send_certification
 from silkaj.commands import (
     currency_info,
     difficulties,
-    network_info,
     argos_info,
     list_blocks,
 )
+from silkaj.net import network_info
 from silkaj.wot import received_sent_certifications, id_pubkey_correspondence
 from silkaj.auth import generate_auth_file
 from silkaj.license import license_command
diff --git a/silkaj/commands.py b/silkaj/commands.py
index bc8247e3233cfac50752920bf9709afe864ef262..cbf205f2d39d9ce9d25ee2167cd38ea365e1eff9 100644
--- a/silkaj/commands.py
+++ b/silkaj/commands.py
@@ -15,9 +15,8 @@ You should have received a copy of the GNU Affero General Public License
 along with Silkaj. If not, see <https://www.gnu.org/licenses/>.
 """
 
-from click import command, option, argument, IntRange, get_terminal_size
-from datetime import datetime
-from os import system, popen
+from click import command, option, argument, IntRange
+from os import system
 from collections import OrderedDict
 from tabulate import tabulate
 from operator import itemgetter
@@ -26,19 +25,17 @@ import aiohttp
 from _socket import gaierror
 import jsonschema
 
-from duniterpy.api.client import Client, parse_text
 from duniterpy.api import bma
 
 from silkaj.tools import coroutine
 from silkaj.wot import identity_of
 from silkaj.network_tools import (
-    discover_peers,
     best_endpoint_address,
     EndPoint,
     ClientInstance,
     HeadBlock,
 )
-from silkaj.tools import convert_time, message_exit, CurrencySymbol
+from silkaj.tools import convert_time, CurrencySymbol
 from silkaj.constants import ASYNC_SLEEP
 
 
@@ -144,111 +141,6 @@ Common Proof-of-Work difficulty level: {5}, hash starting with `{6}`\n{7}".forma
     )
 
 
-def get_network_sort_key(endpoint):
-    t = list()
-    for akey in network_sort_keys:
-        if akey == "diffi" or akey == "block" or akey == "port":
-            t.append(int(endpoint[akey]) if akey in endpoint else 0)
-        else:
-            t.append(str(endpoint[akey]) if akey in endpoint else "")
-    return tuple(t)
-
-
-@command("net", help="Display network view")
-@option(
-    "--discover", "-d", is_flag=True, help="Discover the network (could take a while)"
-)
-@option(
-    "--sort",
-    "-s",
-    default="block,member,diffi,uid",
-    show_default=True,
-    help="Sort column names comma-separated",
-)
-@coroutine
-async def network_info(discover, sort):
-    global network_sort_keys
-    network_sort_keys = sort.split(",")
-    width = get_terminal_size()[0]
-    if width < 146:
-        message_exit(
-            "Wide screen need to be larger than 146. Current width: " + str(width)
-        )
-    # discover peers
-    # and make sure fields are always ordered the same
-    infos = [
-        OrderedDict(
-            (i, p.get(i, None)) for i in ("domain", "port", "ip4", "ip6", "pubkey")
-        )
-        for p in await discover_peers(discover)
-    ]
-    client = ClientInstance().client
-    diffi = await client(bma.blockchain.difficulties)
-    members = 0
-    print("Getting informations about nodes:")
-    for i, info in enumerate(infos):
-        ep = info
-        api = "BASIC_MERKLED_API " if ep["port"] != "443" else "BMAS "
-        api += ep.get("domain") + " " if ep["domain"] else ""
-        api += ep.get("ip4") + " " if ep["ip4"] else ""
-        api += ep.get("ip6") + " " if ep["ip6"] else ""
-        api += ep.get("port")
-        print("{0:.0f}%".format(i / len(infos) * 100, 1), end=" ")
-        best_ep = best_endpoint_address(info, False)
-        print(best_ep if best_ep is None else info[best_ep], end=" ")
-        print(info["port"])
-        await sleep(ASYNC_SLEEP)
-        try:
-            info["uid"] = await identity_of(info["pubkey"])
-            info["uid"] = info["uid"]["uid"]
-            info["member"] = "yes"
-            members += 1
-        except:
-            info["uid"] = None
-            info["member"] = "no"
-        info["pubkey"] = info["pubkey"][:5] + "…"
-        for d in diffi["levels"]:
-            if info.get("uid") is not None:
-                if info["uid"] == d["uid"]:
-                    info["diffi"] = d["level"]
-                if len(info["uid"]) > 10:
-                    info["uid"] = info["uid"][:9] + "…"
-        sub_client = Client(api)
-        current_blk = await sub_client(bma.blockchain.current)
-        if current_blk is not None:
-            info["gen_time"] = convert_time(current_blk["time"], "hour")
-            if width > 171:
-                info["mediantime"] = convert_time(current_blk["medianTime"], "hour")
-            if width > 185:
-                info["difftime"] = convert_time(
-                    current_blk["time"] - current_blk["medianTime"], "hour"
-                )
-            info["block"] = current_blk["number"]
-            info["hash"] = current_blk["hash"][:10] + "…"
-            summary = await sub_client(bma.node.summary)
-            info["version"] = summary["duniter"]["version"]
-        await sub_client.close()
-        if info.get("domain") is not None and len(info["domain"]) > 20:
-            info["domain"] = "…" + info["domain"][-20:]
-        if info.get("ip6") is not None:
-            if width < 156:
-                info.pop("ip6")
-            else:
-                info["ip6"] = info["ip6"][:8] + "…"
-    await client.close()
-    print(
-        len(infos),
-        "peers ups, with",
-        members,
-        "members and",
-        len(infos) - members,
-        "non-members at",
-        datetime.now().strftime("%H:%M:%S"),
-    )
-    infos = sorted(infos, key=get_network_sort_key)
-    print(tabulate(infos, headers="keys", tablefmt="orgtbl", stralign="center"))
-
-
 @command("blocks", help="Display blocks: default: 0 for current window size")
 @argument("number", default=0, type=IntRange(0, 5000))
 @option(
diff --git a/silkaj/net.py b/silkaj/net.py
new file mode 100644
index 0000000000000000000000000000000000000000..b3ba4ae5bc06f558caff59766f0467c4fb8a3ceb
--- /dev/null
+++ b/silkaj/net.py
@@ -0,0 +1,141 @@
+"""
+Copyright  2016-2020 Maël Azimi <m.a@moul.re>
+
+Silkaj is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Silkaj is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with Silkaj. If not, see <https://www.gnu.org/licenses/>.
+"""
+
+from click import command, option, get_terminal_size
+from datetime import datetime
+from os import system
+from collections import OrderedDict
+from tabulate import tabulate
+from asyncio import sleep
+
+from duniterpy.api.client import Client
+from duniterpy.api import bma
+
+from silkaj.tools import coroutine
+from silkaj.wot import identity_of
+from silkaj.network_tools import (
+    discover_peers,
+    best_endpoint_address,
+    ClientInstance,
+)
+from silkaj.tools import convert_time, message_exit
+from silkaj.constants import ASYNC_SLEEP
+
+
+def get_network_sort_key(endpoint):
+    t = list()
+    for akey in network_sort_keys:
+        if akey == "diffi" or akey == "block" or akey == "port":
+            t.append(int(endpoint[akey]) if akey in endpoint else 0)
+        else:
+            t.append(str(endpoint[akey]) if akey in endpoint else "")
+    return tuple(t)
+
+
+@command("net", help="Display network view")
+@option(
+    "--discover", "-d", is_flag=True, help="Discover the network (could take a while)"
+)
+@option(
+    "--sort",
+    "-s",
+    default="block,member,diffi,uid",
+    show_default=True,
+    help="Sort column names comma-separated",
+)
+@coroutine
+async def network_info(discover, sort):
+    global network_sort_keys
+    network_sort_keys = sort.split(",")
+    width = get_terminal_size()[0]
+    if width < 146:
+        message_exit(
+            "Wide screen need to be larger than 146. Current width: " + str(width)
+        )
+    # discover peers
+    # and make sure fields are always ordered the same
+    infos = [
+        OrderedDict(
+            (i, p.get(i, None)) for i in ("domain", "port", "ip4", "ip6", "pubkey")
+        )
+        for p in await discover_peers(discover)
+    ]
+    client = ClientInstance().client
+    diffi = await client(bma.blockchain.difficulties)
+    members = 0
+    print("Getting informations about nodes:")
+    for i, info in enumerate(infos):
+        ep = info
+        api = "BASIC_MERKLED_API " if ep["port"] != "443" else "BMAS "
+        api += ep.get("domain") + " " if ep["domain"] else ""
+        api += ep.get("ip4") + " " if ep["ip4"] else ""
+        api += ep.get("ip6") + " " if ep["ip6"] else ""
+        api += ep.get("port")
+        print("{0:.0f}%".format(i / len(infos) * 100, 1), end=" ")
+        best_ep = best_endpoint_address(info, False)
+        print(best_ep if best_ep is None else info[best_ep], end=" ")
+        print(info["port"])
+        await sleep(ASYNC_SLEEP)
+        try:
+            info["uid"] = await identity_of(info["pubkey"])
+            info["uid"] = info["uid"]["uid"]
+            info["member"] = "yes"
+            members += 1
+        except:
+            info["uid"] = None
+            info["member"] = "no"
+        info["pubkey"] = info["pubkey"][:5] + "…"
+        for d in diffi["levels"]:
+            if info.get("uid") is not None:
+                if info["uid"] == d["uid"]:
+                    info["diffi"] = d["level"]
+                if len(info["uid"]) > 10:
+                    info["uid"] = info["uid"][:9] + "…"
+        sub_client = Client(api)
+        current_blk = await sub_client(bma.blockchain.current)
+        if current_blk is not None:
+            info["gen_time"] = convert_time(current_blk["time"], "hour")
+            if width > 171:
+                info["mediantime"] = convert_time(current_blk["medianTime"], "hour")
+            if width > 185:
+                info["difftime"] = convert_time(
+                    current_blk["time"] - current_blk["medianTime"], "hour"
+                )
+            info["block"] = current_blk["number"]
+            info["hash"] = current_blk["hash"][:10] + "…"
+            summary = await sub_client(bma.node.summary)
+            info["version"] = summary["duniter"]["version"]
+        await sub_client.close()
+        if info.get("domain") is not None and len(info["domain"]) > 20:
+            info["domain"] = "…" + info["domain"][-20:]
+        if info.get("ip6") is not None:
+            if width < 156:
+                info.pop("ip6")
+            else:
+                info["ip6"] = info["ip6"][:8] + "…"
+    await client.close()
+    print(
+        len(infos),
+        "peers ups, with",
+        members,
+        "members and",
+        len(infos) - members,
+        "non-members at",
+        datetime.now().strftime("%H:%M:%S"),
+    )
+    infos = sorted(infos, key=get_network_sort_key)
+    print(tabulate(infos, headers="keys", tablefmt="orgtbl", stralign="center"))