diff --git a/.cargo/config b/.cargo/config
index 3527f8783469aade58728a6a2c86c2cc4c8dfd4a..3b8aaea1d5e245c71373fa095819c8cec1a131ca 100644
--- a/.cargo/config
+++ b/.cargo/config
@@ -1,5 +1,6 @@
 [alias]
 cucumber = "test -p duniter-end2end-tests --test cucumber_tests --"
+smoldot = "test -p duniter-end2end-tests --test smoldot_tests -- --nocapture"
 tu = "test --workspace --exclude duniter-end2end-tests"
 xtask = "run --package xtask --"
 
diff --git a/Cargo.lock b/Cargo.lock
index ed959f0a8d777e426dd888ebcff93591b964e697..fae8265cf222e6d24dfd372c574b40fe244677a5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1361,7 +1361,9 @@ dependencies = [
  "notify",
  "parity-scale-codec",
  "portpicker",
+ "serde",
  "serde_json",
+ "sp-core",
  "sp-keyring",
  "subxt",
  "tokio",
diff --git a/end2end-tests/Cargo.toml b/end2end-tests/Cargo.toml
index 8d7b445eeded82e13bb22a059caefa39ad27fd7d..7fb726eaca779df264258f55e10121f02e34cc54 100644
--- a/end2end-tests/Cargo.toml
+++ b/end2end-tests/Cargo.toml
@@ -17,7 +17,9 @@ env_logger = "0.9.0"
 notify = "4.0"
 parity-scale-codec = "2.3.1"
 portpicker = "0.1.1"
+serde = "1.0"
 serde_json = "1.0.64"
+sp-core = { git = "https://github.com/librelois/substrate.git", branch = "duniter-monthly-2022-02" }
 sp-keyring = { git = "https://github.com/librelois/substrate.git", branch = "duniter-monthly-2022-02" }
 subxt = { git = 'https://github.com/librelois/subxt.git', branch = 'duniter-monthly-2022-02' }
 tokio = { version = "1.15.0", features = ["macros"] }
@@ -25,3 +27,7 @@ tokio = { version = "1.15.0", features = ["macros"] }
 [[test]]
 name = "cucumber_tests"
 harness = false  # allows Cucumber to print output instead of libtest
+
+[[test]]
+name = "smoldot_tests"
+harness = true
diff --git a/end2end-tests/smoldot-server/index.js b/end2end-tests/smoldot-server/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..39ba36490bbfebe980fd70155070aee78034e0ad
--- /dev/null
+++ b/end2end-tests/smoldot-server/index.js
@@ -0,0 +1,139 @@
+// This file launches a WebSocket server that exposes the JSON-RPC API of a smoldot light client.
+
+import * as smoldot from "@substrate/smoldot-light";
+import { default as websocket } from "websocket";
+import * as http from "node:http";
+import * as process from "node:process";
+import * as fs from "node:fs";
+import * as util from "node:util";
+
+// File logger
+const logFile = fs.createWriteStream('smoldot.log', {flags : 'w'});
+const logStdout = process.stdout;
+const fileLogger = function () {
+  logFile.write(util.format.apply(null, arguments) + '\n');
+}
+console.log = function () {
+  logFile.write(util.format.apply(null, arguments) + '\n');
+  logStdout.write(util.format.apply(null, arguments) + '\n');
+}
+console.error = console.log;
+
+// Chain spec
+const gdev = fs.readFileSync(process.env.CHAIN_SPEC_FILEPATH || "../../node/specs/gdev-raw.json", "utf8");
+
+const client = smoldot.start({
+  maxLogLevel: 4, // Can be increased for more verbosity
+  forbidTcp: false,
+  forbidWs: false,
+  forbidNonLocalWs: false,
+  forbidWss: false,
+  logCallback: (level, target, message) => {
+    // As incredible as it seems, there is currently no better way to print the current time
+    // formatted in a certain way.
+    const now = new Date();
+    const hours = ("0" + now.getHours()).slice(-2);
+    const minutes = ("0" + now.getMinutes()).slice(-2);
+    const seconds = ("0" + now.getSeconds()).slice(-2);
+    const milliseconds = ("00" + now.getMilliseconds()).slice(-3);
+    if (level <= 3) {
+      console.log(
+        "[%s:%s:%s.%s] [%s] %s",
+        hours,
+        minutes,
+        seconds,
+        milliseconds,
+        target,
+        message
+      );
+    } else {
+      fileLogger(
+        "[%s:%s:%s.%s] [%s] %s",
+        hours,
+        minutes,
+        seconds,
+        milliseconds,
+        target,
+        message
+      );
+    }
+  },
+});
+
+client
+    .addChain({ chainSpec: gdev })
+    .catch((error) => {
+        console.error("Error while adding chain: " + error);
+        process.exit(1);
+    });
+
+// Start the WebSocket server listening on port 9943.
+let server = http.createServer(function (request, response) {
+  response.writeHead(404);
+  response.end();
+});
+let ws_port = process.env.WS_PORT || 9943;
+server.listen(ws_port, function () {
+  console.log("JSON-RPC server now listening on port " + ws_port);
+  console.log(
+    "Please visit: https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A" + ws_port
+  );
+  console.log("");
+});
+let wsServer = new websocket.server({
+  httpServer: server,
+  autoAcceptConnections: false,
+});
+
+wsServer.on("request", function (request) {
+  let chain = (async () => {
+    return {
+      gdev: await client.addChain({
+        chainSpec: gdev,
+        jsonRpcCallback: (resp) => {
+          connection.sendUTF(resp);
+        },
+      }),
+    };
+  })();
+
+  const connection = request.accept(
+    request.requestedProtocols[0],
+    request.origin
+  );
+  console.log("New JSON-RPC client connected: " + request.remoteAddress + ".");
+
+  chain.catch((error) => {
+    console.error("Error while adding chain gdev: " + error);
+    connection.close(400);
+  });
+
+  // Receiving a message from the connection. This is a JSON-RPC request.
+  connection.on("message", function (message) {
+    if (message.type === "utf8") {
+      chain
+        .then((chain) => {
+          if (chain.gdev) chain.gdev.sendJsonRpc(message.utf8Data);
+          else  console.error("Unknown chain");
+        })
+        .catch((error) => {
+          console.error("Error during JSON-RPC request: " + error);
+          process.exit(1);
+        });
+    } else {
+      connection.close(400);
+    }
+  });
+
+  // When the connection closes, remove the chains that have been added.
+  connection.on("close", function (reasonCode, description) {
+    console.log(
+      "JSON-RPC client " + connection.remoteAddress + " disconnected."
+    );
+    chain
+      .then((chain) => {
+        if (chain.gdev) chain.gdev.remove();
+      })
+      .catch(() => {});
+  });
+});
diff --git a/end2end-tests/smoldot-server/package-lock.json b/end2end-tests/smoldot-server/package-lock.json
new file mode 100644
index 0000000000000000000000000000000000000000..a2e7cb5439ca639c85a4e9ddaa637a1de0bbc019
--- /dev/null
+++ b/end2end-tests/smoldot-server/package-lock.json
@@ -0,0 +1,459 @@
+{
+  "name": "smoldot-test-server",
+  "version": "0.0.1",
+  "lockfileVersion": 2,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "smoldot-test-server",
+      "version": "0.0.1",
+      "dependencies": {
+        "@substrate/smoldot-light": "^0.6.17",
+        "websocket": "^1.0.34"
+      },
+      "devDependencies": {
+        "@types/node": "^17.0.38",
+        "@types/websocket": "^1.0.5",
+        "typescript": "^4.7.2"
+      }
+    },
+    "node_modules/@substrate/smoldot-light": {
+      "version": "0.6.17",
+      "resolved": "https://registry.npmjs.org/@substrate/smoldot-light/-/smoldot-light-0.6.17.tgz",
+      "integrity": "sha512-C8KYYvocfxO7I+9WdSoqfu+bbpM0a09c8f6PGfPphMPLm4hjuNPBo00WyJhCFcCMQBfPu3FprCUPDImFYELTdA==",
+      "dependencies": {
+        "buffer": "^6.0.1",
+        "pako": "^2.0.4",
+        "websocket": "^1.0.32"
+      }
+    },
+    "node_modules/@types/node": {
+      "version": "17.0.38",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.38.tgz",
+      "integrity": "sha512-5jY9RhV7c0Z4Jy09G+NIDTsCZ5G0L5n+Z+p+Y7t5VJHM30bgwzSjVtlcBxqAj+6L/swIlvtOSzr8rBk/aNyV2g==",
+      "dev": true
+    },
+    "node_modules/@types/websocket": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/@types/websocket/-/websocket-1.0.5.tgz",
+      "integrity": "sha512-NbsqiNX9CnEfC1Z0Vf4mE1SgAJ07JnRYcNex7AJ9zAVzmiGHmjKFEk7O4TJIsgv2B1sLEb6owKFZrACwdYngsQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/base64-js": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/buffer": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+      "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "dependencies": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.2.1"
+      }
+    },
+    "node_modules/bufferutil": {
+      "version": "4.0.6",
+      "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.6.tgz",
+      "integrity": "sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw==",
+      "hasInstallScript": true,
+      "dependencies": {
+        "node-gyp-build": "^4.3.0"
+      },
+      "engines": {
+        "node": ">=6.14.2"
+      }
+    },
+    "node_modules/d": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
+      "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
+      "dependencies": {
+        "es5-ext": "^0.10.50",
+        "type": "^1.0.1"
+      }
+    },
+    "node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/es5-ext": {
+      "version": "0.10.61",
+      "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.61.tgz",
+      "integrity": "sha512-yFhIqQAzu2Ca2I4SE2Au3rxVfmohU9Y7wqGR+s7+H7krk26NXhIRAZDgqd6xqjCEFUomDEA3/Bo/7fKmIkW1kA==",
+      "hasInstallScript": true,
+      "dependencies": {
+        "es6-iterator": "^2.0.3",
+        "es6-symbol": "^3.1.3",
+        "next-tick": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/es6-iterator": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+      "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
+      "dependencies": {
+        "d": "1",
+        "es5-ext": "^0.10.35",
+        "es6-symbol": "^3.1.1"
+      }
+    },
+    "node_modules/es6-symbol": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
+      "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
+      "dependencies": {
+        "d": "^1.0.1",
+        "ext": "^1.1.2"
+      }
+    },
+    "node_modules/ext": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz",
+      "integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==",
+      "dependencies": {
+        "type": "^2.5.0"
+      }
+    },
+    "node_modules/ext/node_modules/type": {
+      "version": "2.6.0",
+      "resolved": "https://registry.npmjs.org/type/-/type-2.6.0.tgz",
+      "integrity": "sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ=="
+    },
+    "node_modules/ieee754": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/is-typedarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+      "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
+    },
+    "node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+    },
+    "node_modules/next-tick": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
+      "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
+    },
+    "node_modules/node-gyp-build": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz",
+      "integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==",
+      "bin": {
+        "node-gyp-build": "bin.js",
+        "node-gyp-build-optional": "optional.js",
+        "node-gyp-build-test": "build-test.js"
+      }
+    },
+    "node_modules/pako": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/pako/-/pako-2.0.4.tgz",
+      "integrity": "sha512-v8tweI900AUkZN6heMU/4Uy4cXRc2AYNRggVmTR+dEncawDJgCdLMximOVA2p4qO57WMynangsfGRb5WD6L1Bg=="
+    },
+    "node_modules/type": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
+      "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg=="
+    },
+    "node_modules/typedarray-to-buffer": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
+      "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
+      "dependencies": {
+        "is-typedarray": "^1.0.0"
+      }
+    },
+    "node_modules/typescript": {
+      "version": "4.7.2",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.2.tgz",
+      "integrity": "sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A==",
+      "dev": true,
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=4.2.0"
+      }
+    },
+    "node_modules/utf-8-validate": {
+      "version": "5.0.9",
+      "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.9.tgz",
+      "integrity": "sha512-Yek7dAy0v3Kl0orwMlvi7TPtiCNrdfHNd7Gcc/pLq4BLXqfAmd0J7OWMizUQnTTJsyjKn02mU7anqwfmUP4J8Q==",
+      "hasInstallScript": true,
+      "dependencies": {
+        "node-gyp-build": "^4.3.0"
+      },
+      "engines": {
+        "node": ">=6.14.2"
+      }
+    },
+    "node_modules/websocket": {
+      "version": "1.0.34",
+      "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz",
+      "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==",
+      "dependencies": {
+        "bufferutil": "^4.0.1",
+        "debug": "^2.2.0",
+        "es5-ext": "^0.10.50",
+        "typedarray-to-buffer": "^3.1.5",
+        "utf-8-validate": "^5.0.2",
+        "yaeti": "^0.0.6"
+      },
+      "engines": {
+        "node": ">=4.0.0"
+      }
+    },
+    "node_modules/yaeti": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz",
+      "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=",
+      "engines": {
+        "node": ">=0.10.32"
+      }
+    }
+  },
+  "dependencies": {
+    "@substrate/smoldot-light": {
+      "version": "0.6.17",
+      "resolved": "https://registry.npmjs.org/@substrate/smoldot-light/-/smoldot-light-0.6.17.tgz",
+      "integrity": "sha512-C8KYYvocfxO7I+9WdSoqfu+bbpM0a09c8f6PGfPphMPLm4hjuNPBo00WyJhCFcCMQBfPu3FprCUPDImFYELTdA==",
+      "requires": {
+        "buffer": "^6.0.1",
+        "pako": "^2.0.4",
+        "websocket": "^1.0.32"
+      }
+    },
+    "@types/node": {
+      "version": "17.0.38",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.38.tgz",
+      "integrity": "sha512-5jY9RhV7c0Z4Jy09G+NIDTsCZ5G0L5n+Z+p+Y7t5VJHM30bgwzSjVtlcBxqAj+6L/swIlvtOSzr8rBk/aNyV2g==",
+      "dev": true
+    },
+    "@types/websocket": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/@types/websocket/-/websocket-1.0.5.tgz",
+      "integrity": "sha512-NbsqiNX9CnEfC1Z0Vf4mE1SgAJ07JnRYcNex7AJ9zAVzmiGHmjKFEk7O4TJIsgv2B1sLEb6owKFZrACwdYngsQ==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*"
+      }
+    },
+    "base64-js": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
+    },
+    "buffer": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+      "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+      "requires": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.2.1"
+      }
+    },
+    "bufferutil": {
+      "version": "4.0.6",
+      "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.6.tgz",
+      "integrity": "sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw==",
+      "requires": {
+        "node-gyp-build": "^4.3.0"
+      }
+    },
+    "d": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
+      "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
+      "requires": {
+        "es5-ext": "^0.10.50",
+        "type": "^1.0.1"
+      }
+    },
+    "debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "requires": {
+        "ms": "2.0.0"
+      }
+    },
+    "es5-ext": {
+      "version": "0.10.61",
+      "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.61.tgz",
+      "integrity": "sha512-yFhIqQAzu2Ca2I4SE2Au3rxVfmohU9Y7wqGR+s7+H7krk26NXhIRAZDgqd6xqjCEFUomDEA3/Bo/7fKmIkW1kA==",
+      "requires": {
+        "es6-iterator": "^2.0.3",
+        "es6-symbol": "^3.1.3",
+        "next-tick": "^1.1.0"
+      }
+    },
+    "es6-iterator": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+      "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
+      "requires": {
+        "d": "1",
+        "es5-ext": "^0.10.35",
+        "es6-symbol": "^3.1.1"
+      }
+    },
+    "es6-symbol": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
+      "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
+      "requires": {
+        "d": "^1.0.1",
+        "ext": "^1.1.2"
+      }
+    },
+    "ext": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz",
+      "integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==",
+      "requires": {
+        "type": "^2.5.0"
+      },
+      "dependencies": {
+        "type": {
+          "version": "2.6.0",
+          "resolved": "https://registry.npmjs.org/type/-/type-2.6.0.tgz",
+          "integrity": "sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ=="
+        }
+      }
+    },
+    "ieee754": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
+    },
+    "is-typedarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+      "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
+    },
+    "ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+    },
+    "next-tick": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
+      "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
+    },
+    "node-gyp-build": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz",
+      "integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ=="
+    },
+    "pako": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/pako/-/pako-2.0.4.tgz",
+      "integrity": "sha512-v8tweI900AUkZN6heMU/4Uy4cXRc2AYNRggVmTR+dEncawDJgCdLMximOVA2p4qO57WMynangsfGRb5WD6L1Bg=="
+    },
+    "type": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
+      "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg=="
+    },
+    "typedarray-to-buffer": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
+      "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
+      "requires": {
+        "is-typedarray": "^1.0.0"
+      }
+    },
+    "typescript": {
+      "version": "4.7.2",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.2.tgz",
+      "integrity": "sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A==",
+      "dev": true
+    },
+    "utf-8-validate": {
+      "version": "5.0.9",
+      "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.9.tgz",
+      "integrity": "sha512-Yek7dAy0v3Kl0orwMlvi7TPtiCNrdfHNd7Gcc/pLq4BLXqfAmd0J7OWMizUQnTTJsyjKn02mU7anqwfmUP4J8Q==",
+      "requires": {
+        "node-gyp-build": "^4.3.0"
+      }
+    },
+    "websocket": {
+      "version": "1.0.34",
+      "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz",
+      "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==",
+      "requires": {
+        "bufferutil": "^4.0.1",
+        "debug": "^2.2.0",
+        "es5-ext": "^0.10.50",
+        "typedarray-to-buffer": "^3.1.5",
+        "utf-8-validate": "^5.0.2",
+        "yaeti": "^0.0.6"
+      }
+    },
+    "yaeti": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz",
+      "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc="
+    }
+  }
+}
diff --git a/end2end-tests/smoldot-server/package.json b/end2end-tests/smoldot-server/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..fb0f67f73457b969822e96f0e49f618dbb5bf0f6
--- /dev/null
+++ b/end2end-tests/smoldot-server/package.json
@@ -0,0 +1,21 @@
+{
+  "name": "smoldot-test-server",
+  "version": "0.0.1",
+  "description": "Light client that connects to Polkadot and Substrate-based blockchains",
+  "files": [
+    "dist"
+  ],
+  "type": "module",
+  "scripts": {
+    "start": "node index.js"
+  },
+  "dependencies": {
+    "@substrate/smoldot-light": "^0.6.17",
+    "websocket": "^1.0.34"
+  },
+  "devDependencies": {
+    "@types/node": "^17.0.38",
+    "@types/websocket": "^1.0.5",
+    "typescript": "^4.7.2"
+  }
+}
diff --git a/end2end-tests/tests/common/balances.rs b/end2end-tests/tests/common/balances.rs
index 781abf549e229cb28f20a18c387e60e4ad80ed46..7efc5109a94f5571e9ea2a13a14a79cca09bf46a 100644
--- a/end2end-tests/tests/common/balances.rs
+++ b/end2end-tests/tests/common/balances.rs
@@ -48,6 +48,7 @@ pub async fn set_balance(
 pub async fn transfer(
     api: &Api,
     client: &Client,
+    create_block: bool,
     from: AccountKeyring,
     amount: u64,
     to: AccountKeyring,
@@ -55,15 +56,25 @@ pub async fn transfer(
     let from = PairSigner::new(from.pair());
     let to = to.to_account_id();
 
-    let _events = create_block_with_extrinsic(
-        client,
+    if create_block {
+        let _events = create_block_with_extrinsic(
+            client,
+            api.tx()
+                .balances()
+                .transfer(to.clone().into(), amount)
+                .create_signed(&from, ())
+                .await?,
+        )
+        .await?;
+    } else {
         api.tx()
             .balances()
             .transfer(to.clone().into(), amount)
-            .create_signed(&from, ())
-            .await?,
-    )
-    .await?;
+            .sign_and_submit_then_watch(&from)
+            .await?
+            .wait_for_in_block()
+            .await?;
+    }
 
     Ok(())
 }
diff --git a/end2end-tests/tests/common/mod.rs b/end2end-tests/tests/common/mod.rs
index 078abd747617b2e2c04a6392e796d5e5ccd75507..51809a8f7f65ff46ac1654b66f95a8bdbc2bc263 100644
--- a/end2end-tests/tests/common/mod.rs
+++ b/end2end-tests/tests/common/mod.rs
@@ -83,6 +83,105 @@ pub async fn spawn_node(maybe_genesis_conf_file: Option<PathBuf>) -> (Api, Clien
     (api, client, process)
 }
 
+pub async fn spawn_full_node_and_smoldot_node() -> (Api, Client, Process, Process) {
+    let duniter_binary_path = std::env::var("DUNITER_BINARY_PATH")
+        .unwrap_or_else(|_| "../target/debug/duniter".to_owned());
+
+    // Generate raw chain spec
+    let output = Command::new(&duniter_binary_path)
+        .args(["build-spec", "--chain=local", "--raw"])
+        .env("DUNITER_BABE_EPOCH_DURATION", "5")
+        .output()
+        .expect("Fail to generate chain spec");
+
+    if !output.status.success() {
+        panic!("Fail to generate chain spec: status != success");
+    }
+
+    // Load raw chain spec
+    let mut chain_spec_json: serde_json::Value =
+        serde_json::from_slice(&output.stdout).expect("Error parsing raw chain spec");
+
+    // Write chain spec for the full node
+    let mut file = std::fs::File::create("gdev-local-spec-for-full-node.json")
+        .expect("Fail to create chain spec file for full node");
+    file.write_all(chain_spec_json.to_string().as_bytes())
+        .expect("Fail to write chain spec file for full node");
+
+    // Spawn the full node
+    let FullNode {
+        process: full_node_process,
+        p2p_port,
+        ws_port: _,
+    } = spawn_full_node(
+        &[
+            "--alice",
+            "--chain=gdev-local-spec-for-full-node.json",
+            "--node-key=0000000000000000000000000000000000000000000000000000000000000001",
+        ],
+        &duniter_binary_path,
+        None,
+    );
+
+    // Update the bootnodes in chain spec
+    let bootnode = format!(
+        "/ip4/127.0.0.1/tcp/{}/p2p/12D3KooWEyoppNCUx8Yx66oV9fJnriXwCcXwDDUA2kj6vnc6iDEp",
+        p2p_port
+    );
+    if let Some(chain_spec_obj) = chain_spec_json.as_object_mut() {
+        if let Some(boot_nodes) = chain_spec_obj.get_mut("bootNodes") {
+            *boot_nodes = serde_json::Value::Array(vec![serde_json::Value::String(bootnode)]);
+        }
+    }
+
+    // Write chain spec for smoldot
+    let mut file = std::fs::File::create("gdev-local-spec-for-smoldot.json")
+        .expect("Fail to create chain spec file for smoldot");
+    file.write_all(chain_spec_json.to_string().as_bytes())
+        .expect("Fail to write chain spec file for smoldot");
+
+    // Spawn the light node (smoldot)
+    let ws_port = portpicker::pick_unused_port().expect("No ports free");
+    let current_dir =
+        std::fs::canonicalize("smoldot-server").expect("fail to canonicalize current_dir");
+    let log_file_path = format!("smoldot-{}.log", ws_port);
+    let log_file = std::fs::File::create(&log_file_path).expect("fail to create log file");
+    let process = Process(
+        Command::new("npm")
+            .current_dir(current_dir)
+            .args(["run", "start"])
+            .env("CHAIN_SPEC_FILEPATH", "../gdev-local-spec-for-smoldot.json")
+            .env("WS_PORT", ws_port.to_string())
+            .stdout(log_file)
+            .spawn()
+            .expect("failed to spawn node"),
+    );
+
+    let timeout =
+        if let Ok(duration_string) = std::env::var("DUNITER_END2END_TESTS_SPAWN_NODE_TIMEOUT") {
+            duration_string.parse().unwrap_or(8)
+        } else {
+            8
+        };
+
+    wait_until_log_line(
+        "Finalized block runtime ready. Spec version:",
+        &log_file_path,
+        std::time::Duration::from_secs(timeout),
+    );
+
+    let client = ClientBuilder::new()
+        .set_url(format!("ws://127.0.0.1:{}", ws_port))
+        .build()
+        .await
+        .expect("fail to connect to node");
+    let api = client.clone().to_runtime_api::<Api>();
+
+    println!("***** NETWORK FULLY STARTED *****");
+
+    (api, client, process, full_node_process)
+}
+
 pub async fn create_empty_block(client: &Client) -> Result<()> {
     // Create an empty block
     let _: Value = client
@@ -121,6 +220,103 @@ pub async fn create_block_with_extrinsic(
         .map_err(Into::into)
 }
 
+#[derive(Debug, serde::Deserialize)]
+#[serde(tag = "event")]
+#[serde(rename_all = "camelCase")]
+enum SmoldotChainHeadFollowEvent {
+    #[serde(rename_all = "camelCase")]
+    Initialized {
+        finalized_block_hash: String,
+    },
+    #[serde(rename_all = "camelCase")]
+    NewBlock {
+        block_hash: String,
+    },
+    Stop,
+    #[serde(other)]
+    Unknown,
+}
+
+#[derive(Debug, Clone, serde::Deserialize)]
+#[serde(tag = "event")]
+pub enum SmoldotChainHeadCallEvent {
+    #[serde(rename = "done")]
+    Done { output: String },
+    #[serde(rename = "inaccessible")]
+    Inaccessible { error: String },
+    #[serde(rename = "error")]
+    Error { error: String },
+    #[serde(rename = "disjoint")]
+    Disjoint {},
+}
+
+pub async fn dry_run_extrinsic(
+    block_hash: &sp_core::H256,
+    client: &Client,
+    extrinsic: subxt::UncheckedExtrinsic<DefaultConfig, DefaultExtra<DefaultConfig>>,
+) -> Result<bool> {
+    // Get a followSubscriptionId
+    let sub: subxt::rpc::Subscription<SmoldotChainHeadFollowEvent> = client
+        .rpc()
+        .client
+        .subscribe(
+            "chainHead_unstable_follow",
+            rpc_params![true],
+            "chainHead_unstable_unfollow",
+        )
+        .await?;
+    let follow_subscription_id: Value = sub
+        .get_subscription_id()
+        .expect("chainHead_unstable_follow must return a subscription id")
+        .into();
+
+    println!(
+        "TMP DEBUG: follow_subscription_id={:?}",
+        &follow_subscription_id
+    );
+
+    use parity_scale_codec::Encode as _;
+    let block_hash_bytes: sp_core::Bytes = block_hash.encode().into();
+    let extrinsic_bytes: sp_core::Bytes = extrinsic.encode().into();
+    let mut sub: subxt::rpc::Subscription<SmoldotChainHeadCallEvent> = client
+        .rpc()
+        .client
+        .subscribe(
+            "chainHead_unstable_call",
+            rpc_params![
+                follow_subscription_id,
+                block_hash_bytes, // Block hash
+                "BlockBuilder_apply_extrinsic",
+                extrinsic_bytes, // SCALE encoded extrinsic
+                Value::Null      // Network config
+            ],
+            "chainHead_unstable_call_unwatch",
+        )
+        .await?;
+
+    loop {
+        if let Some(event) = sub.next().await {
+            println!("TMP DEBUG: event={:?}", &event);
+        } else {
+            panic!("subscription closed");
+        }
+    }
+
+    todo!()
+    /*println!("TMP DEBUG: result={:?}", &result);
+
+    Ok(result
+        .as_str()
+        .ok_or("chainHead_unstable_call must return an opaque string")?
+        == "1")*/
+}
+
+pub fn encode_to_json<T: parity_scale_codec::Encode>(t: &T) -> Value {
+    use parity_scale_codec::Encode as _;
+    let bytes: sp_core::Bytes = t.encode().into();
+    serde_json::to_value(bytes).unwrap()
+}
+
 fn spawn_full_node(
     args: &[&str],
     duniter_binary_path: &str,
diff --git a/end2end-tests/tests/cucumber_tests.rs b/end2end-tests/tests/cucumber_tests.rs
index ffe54030a61315e4f916611d0b95c6003594f379..98ae9b725a90e9018f668cc9af8d3c7fa2c0c91d 100644
--- a/end2end-tests/tests/cucumber_tests.rs
+++ b/end2end-tests/tests/cucumber_tests.rs
@@ -151,7 +151,7 @@ async fn transfer(
     if is_ud {
         common::balances::transfer_ud(world.api(), world.client(), from, amount, to).await
     } else {
-        common::balances::transfer(world.api(), world.client(), from, amount, to).await
+        common::balances::transfer(world.api(), world.client(), true, from, amount, to).await
     }
 }
 
diff --git a/end2end-tests/tests/smoldot_tests.rs b/end2end-tests/tests/smoldot_tests.rs
new file mode 100644
index 0000000000000000000000000000000000000000..83d30d21b9aa6647e02e485e574be668bcf16484
--- /dev/null
+++ b/end2end-tests/tests/smoldot_tests.rs
@@ -0,0 +1,63 @@
+// Copyright 2021 Axiom-Team
+//
+// This file is part of Substrate-Libre-Currency.
+//
+// Substrate-Libre-Currency 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, version 3 of the License.
+//
+// Substrate-Libre-Currency 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 Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
+
+mod common;
+
+use common::*;
+use sp_keyring::AccountKeyring;
+
+#[tokio::test(flavor = "current_thread")]
+//#[ignore]
+async fn smoldot_test1() {
+    let (api, client, _process, _full_node_process) = spawn_full_node_and_smoldot_node().await;
+
+    /*let mut blocks = client.rpc().subscribe_blocks().await.unwrap();
+
+    loop {
+        let header = blocks.next().await.unwrap().unwrap();
+        println!("header.number: {}", header.number);
+        if header.number > 20 {
+            break;
+        }
+    }
+
+    common::balances::transfer(&api, &client, false, AccountKeyring::Alice, 500, AccountKeyring::Bob)
+        .await
+        .expect("fail to submit extrinsic balances.transfer");*/
+
+    // get last finalized hash
+    /*let block_hash = client
+        .rpc()
+        .finalized_head()
+        .await
+        .expect("fail to get last finalized hash");
+
+    let from = subxt::PairSigner::new(AccountKeyring::Alice.pair());
+    let _ = common::dry_run_extrinsic(
+        &block_hash,
+        &client,
+        api.tx()
+            .balances()
+            .transfer(AccountKeyring::Bob.to_account_id().into(), 5_000)
+            .create_signed(&from, ())
+            .await
+            .expect("fail to generate extrinsic"),
+    )
+    .await
+    .expect("fail to dry run extrinsic");*/
+
+    std::thread::sleep(std::time::Duration::from_secs(20_000));
+}
diff --git a/node/src/chain_spec/gdev.rs b/node/src/chain_spec/gdev.rs
index 87611694e0c9a4bc6990e87064664a1f4495164f..61c4335ce1fd96ef2ae50a9994dd6fa3f38b19ef 100644
--- a/node/src/chain_spec/gdev.rs
+++ b/node/src/chain_spec/gdev.rs
@@ -279,6 +279,9 @@ fn gen_genesis_for_local_chain(
             )
         })
         .collect::<BTreeMap<IdtyName, AccountId>>();
+    let initial_balances = (0..initial_identities_len)
+        .map(|i| (get_account_id_from_seed::<sr25519::Public>(NAMES[i]), 1000))
+        .collect::<Vec<_>>();
 
     gdev_runtime::GenesisConfig {
         system: SystemConfig {
@@ -340,7 +343,7 @@ fn gen_genesis_for_local_chain(
                 .collect(),
         },
         balances: BalancesConfig {
-            balances: Default::default(),
+            balances: initial_balances,
         },
         babe: BabeConfig {
             authorities: Vec::with_capacity(0),
@@ -421,7 +424,7 @@ fn gen_genesis_for_local_chain(
         universal_dividend: UniversalDividendConfig {
             first_reeval: 100,
             first_ud: 1_000,
-            initial_monetary_mass: 0,
+            initial_monetary_mass: initial_identities_len as u64 * 1_000,
         },
         treasury: Default::default(),
     }
diff --git a/scripts/run_smoldot_tests.sh b/scripts/run_smoldot_tests.sh
new file mode 100755
index 0000000000000000000000000000000000000000..f5725e2ec553a31526ba0840fb4660265242b061
--- /dev/null
+++ b/scripts/run_smoldot_tests.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+# This script is meant to be run on Unix/Linux based systems
+set -e
+
+echo "*** Run smoldot compatibility tests ***"
+
+cargo clean -p duniter
+cargo build
+cd end2end-tests/smoldot-server
+npm i
+cd ../..
+cargo smoldot --nocapture