diff --git a/.cargo/config b/.cargo/config
index 25ae43580a079384a24e03beae0a3a63e39babc8..3527f8783469aade58728a6a2c86c2cc4c8dfd4a 100644
--- a/.cargo/config
+++ b/.cargo/config
@@ -1,3 +1,5 @@
 [alias]
 cucumber = "test -p duniter-end2end-tests --test cucumber_tests --"
 tu = "test --workspace --exclude duniter-end2end-tests"
+xtask = "run --package xtask --"
+
diff --git a/Cargo.lock b/Cargo.lock
index a22e6dc49bed79c7a2e93ecd44f62016759d81e3..97f877f894414a3ded87e00d6d00d9204b31a5c0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -353,9 +353,9 @@ dependencies = [
 
 [[package]]
 name = "autocfg"
-version = "1.0.1"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 
 [[package]]
 name = "backtrace"
@@ -1500,7 +1500,7 @@ dependencies = [
  "log",
  "num-traits",
  "parity-scale-codec",
- "parking_lot",
+ "parking_lot 0.11.2",
  "scale-info",
 ]
 
@@ -1784,6 +1784,10 @@ name = "fsio"
 version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c1fd087255f739f4f1aeea69f11b72f8080e9c2e7645cd06955dad4a178a49e3"
+dependencies = [
+ "rand 0.7.3",
+ "users",
+]
 
 [[package]]
 name = "fuchsia-zircon"
@@ -2811,7 +2815,7 @@ dependencies = [
  "jsonrpc-server-utils",
  "log",
  "net2",
- "parking_lot",
+ "parking_lot 0.11.2",
  "unicase",
 ]
 
@@ -2826,7 +2830,7 @@ dependencies = [
  "jsonrpc-server-utils",
  "log",
  "parity-tokio-ipc",
- "parking_lot",
+ "parking_lot 0.11.2",
  "tower-service",
 ]
 
@@ -2840,7 +2844,7 @@ dependencies = [
  "jsonrpc-core",
  "lazy_static",
  "log",
- "parking_lot",
+ "parking_lot 0.11.2",
  "rand 0.7.3",
  "serde",
 ]
@@ -2874,7 +2878,7 @@ dependencies = [
  "jsonrpc-server-utils",
  "log",
  "parity-ws",
- "parking_lot",
+ "parking_lot 0.11.2",
  "slab",
 ]
 
@@ -3028,7 +3032,7 @@ checksum = "c3b6b85fc643f5acd0bffb2cc8a6d150209379267af0d41db72170021841f9f5"
 dependencies = [
  "kvdb",
  "parity-util-mem",
- "parking_lot",
+ "parking_lot 0.11.2",
 ]
 
 [[package]]
@@ -3043,7 +3047,7 @@ dependencies = [
  "num_cpus",
  "owning_ref",
  "parity-util-mem",
- "parking_lot",
+ "parking_lot 0.11.2",
  "regex",
  "rocksdb",
  "smallvec",
@@ -3128,7 +3132,7 @@ dependencies = [
  "libp2p-websocket",
  "libp2p-yamux",
  "multiaddr",
- "parking_lot",
+ "parking_lot 0.11.2",
  "pin-project",
  "smallvec",
  "wasm-timer",
@@ -3153,7 +3157,7 @@ dependencies = [
  "multiaddr",
  "multihash 0.14.0",
  "multistream-select",
- "parking_lot",
+ "parking_lot 0.11.2",
  "pin-project",
  "prost",
  "prost-build",
@@ -3327,7 +3331,7 @@ dependencies = [
  "libp2p-core",
  "log",
  "nohash-hasher",
- "parking_lot",
+ "parking_lot 0.11.2",
  "rand 0.7.3",
  "smallvec",
  "unsigned-varint 0.7.0",
@@ -3560,7 +3564,7 @@ checksum = "4e7362abb8867d7187e7e93df17f460d554c997fc5c8ac57dc1259057f6889af"
 dependencies = [
  "futures 0.3.19",
  "libp2p-core",
- "parking_lot",
+ "parking_lot 0.11.2",
  "thiserror",
  "yamux",
 ]
@@ -3663,10 +3667,11 @@ dependencies = [
 
 [[package]]
 name = "lock_api"
-version = "0.4.5"
+version = "0.4.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
+checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
 dependencies = [
+ "autocfg",
  "scopeguard",
 ]
 
@@ -4222,11 +4227,11 @@ dependencies = [
 
 [[package]]
 name = "once_cell"
-version = "1.8.0"
+version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
+checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
 dependencies = [
- "parking_lot",
+ "parking_lot 0.12.0",
 ]
 
 [[package]]
@@ -4820,7 +4825,7 @@ dependencies = [
  "log",
  "lz4",
  "memmap2 0.2.3",
- "parking_lot",
+ "parking_lot 0.11.2",
  "rand 0.8.4",
  "snap",
 ]
@@ -4881,7 +4886,7 @@ dependencies = [
  "hashbrown",
  "impl-trait-for-tuples",
  "parity-util-mem-derive",
- "parking_lot",
+ "parking_lot 0.11.2",
  "primitive-types",
  "smallvec",
  "winapi 0.3.9",
@@ -4945,7 +4950,17 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
 dependencies = [
  "instant",
  "lock_api",
- "parking_lot_core",
+ "parking_lot_core 0.8.5",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58"
+dependencies = [
+ "lock_api",
+ "parking_lot_core 0.9.3",
 ]
 
 [[package]]
@@ -4962,6 +4977,19 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
+[[package]]
+name = "parking_lot_core"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929"
+dependencies = [
+ "cfg-if 1.0.0",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-sys",
+]
+
 [[package]]
 name = "paste"
 version = "1.0.5"
@@ -5260,7 +5288,7 @@ dependencies = [
  "fnv",
  "lazy_static",
  "memchr",
- "parking_lot",
+ "parking_lot 0.11.2",
  "thiserror",
 ]
 
@@ -5593,6 +5621,15 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
+[[package]]
+name = "run_script"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70f5efb6762d8cafcab5b2a5545dad239d896989b15304e7d1a03cc6cf1aa626"
+dependencies = [
+ "fsio",
+]
+
 [[package]]
 name = "rustc-demangle"
 version = "0.1.20"
@@ -5865,7 +5902,7 @@ dependencies = [
  "hash-db",
  "log",
  "parity-scale-codec",
- "parking_lot",
+ "parking_lot 0.11.2",
  "sc-executor",
  "sc-transaction-pool-api",
  "sc-utils",
@@ -5896,7 +5933,7 @@ dependencies = [
  "log",
  "parity-db",
  "parity-scale-codec",
- "parking_lot",
+ "parking_lot 0.11.2",
  "sc-client-api",
  "sc-state-db",
  "sp-arithmetic",
@@ -5918,7 +5955,7 @@ dependencies = [
  "futures-timer",
  "libp2p",
  "log",
- "parking_lot",
+ "parking_lot 0.11.2",
  "sc-client-api",
  "sc-utils",
  "serde",
@@ -5975,7 +6012,7 @@ dependencies = [
  "num-rational 0.2.4",
  "num-traits",
  "parity-scale-codec",
- "parking_lot",
+ "parking_lot 0.11.2",
  "rand 0.7.3",
  "retain_mut",
  "sc-client-api",
@@ -6099,7 +6136,7 @@ dependencies = [
  "log",
  "lru 0.6.6",
  "parity-scale-codec",
- "parking_lot",
+ "parking_lot 0.11.2",
  "sc-executor-common",
  "sc-executor-wasmi",
  "sp-api",
@@ -6162,7 +6199,7 @@ dependencies = [
  "futures-timer",
  "log",
  "parity-scale-codec",
- "parking_lot",
+ "parking_lot 0.11.2",
  "rand 0.8.4",
  "sc-block-builder",
  "sc-chain-spec",
@@ -6211,7 +6248,7 @@ source = "git+https://github.com/librelois/substrate.git?branch=duniter-monthly-
 dependencies = [
  "async-trait",
  "hex",
- "parking_lot",
+ "parking_lot 0.11.2",
  "serde_json",
  "sp-application-crypto",
  "sp-core",
@@ -6243,7 +6280,7 @@ dependencies = [
  "log",
  "lru 0.7.2",
  "parity-scale-codec",
- "parking_lot",
+ "parking_lot 0.11.2",
  "pin-project",
  "prost",
  "prost-build",
@@ -6300,7 +6337,7 @@ dependencies = [
  "num_cpus",
  "once_cell",
  "parity-scale-codec",
- "parking_lot",
+ "parking_lot 0.11.2",
  "rand 0.7.3",
  "sc-client-api",
  "sc-network",
@@ -6346,7 +6383,7 @@ dependencies = [
  "jsonrpc-pubsub",
  "log",
  "parity-scale-codec",
- "parking_lot",
+ "parking_lot 0.11.2",
  "sc-block-builder",
  "sc-chain-spec",
  "sc-client-api",
@@ -6378,7 +6415,7 @@ dependencies = [
  "jsonrpc-pubsub",
  "log",
  "parity-scale-codec",
- "parking_lot",
+ "parking_lot 0.11.2",
  "sc-chain-spec",
  "sc-transaction-pool-api",
  "serde",
@@ -6424,7 +6461,7 @@ dependencies = [
  "log",
  "parity-scale-codec",
  "parity-util-mem",
- "parking_lot",
+ "parking_lot 0.11.2",
  "pin-project",
  "rand 0.7.3",
  "sc-block-builder",
@@ -6481,7 +6518,7 @@ dependencies = [
  "parity-scale-codec",
  "parity-util-mem",
  "parity-util-mem-derive",
- "parking_lot",
+ "parking_lot 0.11.2",
  "sc-client-api",
  "sp-core",
 ]
@@ -6495,7 +6532,7 @@ dependencies = [
  "futures 0.3.19",
  "libp2p",
  "log",
- "parking_lot",
+ "parking_lot 0.11.2",
  "pin-project",
  "rand 0.7.3",
  "serde",
@@ -6516,7 +6553,7 @@ dependencies = [
  "libc",
  "log",
  "once_cell",
- "parking_lot",
+ "parking_lot 0.11.2",
  "regex",
  "rustc-hash",
  "sc-client-api",
@@ -6557,7 +6594,7 @@ dependencies = [
  "log",
  "parity-scale-codec",
  "parity-util-mem",
- "parking_lot",
+ "parking_lot 0.11.2",
  "retain_mut",
  "sc-client-api",
  "sc-transaction-pool-api",
@@ -6594,7 +6631,7 @@ dependencies = [
  "futures 0.3.19",
  "futures-timer",
  "lazy_static",
- "parking_lot",
+ "parking_lot 0.11.2",
  "prometheus",
 ]
 
@@ -7102,7 +7139,7 @@ dependencies = [
  "log",
  "lru 0.7.2",
  "parity-scale-codec",
- "parking_lot",
+ "parking_lot 0.11.2",
  "sp-api",
  "sp-consensus",
  "sp-database",
@@ -7218,7 +7255,7 @@ dependencies = [
  "num-traits",
  "parity-scale-codec",
  "parity-util-mem",
- "parking_lot",
+ "parking_lot 0.11.2",
  "primitive-types",
  "rand 0.7.3",
  "regex",
@@ -7273,7 +7310,7 @@ version = "4.0.0-dev"
 source = "git+https://github.com/librelois/substrate.git?branch=duniter-monthly-2022-02#8fbc011c06ee051577022c8fd84f2a018123efd3"
 dependencies = [
  "kvdb",
- "parking_lot",
+ "parking_lot 0.11.2",
 ]
 
 [[package]]
@@ -7339,7 +7376,7 @@ dependencies = [
  "libsecp256k1",
  "log",
  "parity-scale-codec",
- "parking_lot",
+ "parking_lot 0.11.2",
  "sp-core",
  "sp-externalities",
  "sp-keystore",
@@ -7373,7 +7410,7 @@ dependencies = [
  "futures 0.3.19",
  "merlin",
  "parity-scale-codec",
- "parking_lot",
+ "parking_lot 0.11.2",
  "schnorrkel",
  "serde",
  "sp-core",
@@ -7525,7 +7562,7 @@ dependencies = [
  "log",
  "num-traits",
  "parity-scale-codec",
- "parking_lot",
+ "parking_lot 0.11.2",
  "rand 0.7.3",
  "smallvec",
  "sp-core",
@@ -8259,7 +8296,7 @@ dependencies = [
  "chrono",
  "lazy_static",
  "matchers",
- "parking_lot",
+ "parking_lot 0.11.2",
  "regex",
  "serde",
  "serde_json",
@@ -8330,7 +8367,7 @@ dependencies = [
  "lazy_static",
  "log",
  "lru-cache",
- "parking_lot",
+ "parking_lot 0.11.2",
  "resolv-conf",
  "smallvec",
  "thiserror",
@@ -8506,6 +8543,16 @@ dependencies = [
  "percent-encoding 2.1.0",
 ]
 
+[[package]]
+name = "users"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa4227e95324a443c9fcb06e03d4d85e91aabe9a5a02aa818688b6918b6af486"
+dependencies = [
+ "libc",
+ "log",
+]
+
 [[package]]
 name = "value-bag"
 version = "1.0.0-alpha.7"
@@ -8522,6 +8569,12 @@ version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
 
+[[package]]
+name = "version-compare"
+version = "0.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c18c859eead79d8b95d09e4678566e8d70105c4e7b251f707a03df32442661b"
+
 [[package]]
 name = "version_check"
 version = "0.9.3"
@@ -8667,7 +8720,7 @@ checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f"
 dependencies = [
  "futures 0.3.19",
  "js-sys",
- "parking_lot",
+ "parking_lot 0.11.2",
  "pin-utils",
  "wasm-bindgen",
  "wasm-bindgen-futures",
@@ -8815,6 +8868,49 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
+[[package]]
+name = "windows-sys"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
+dependencies = [
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
+
 [[package]]
 name = "winreg"
 version = "0.6.2"
@@ -8851,6 +8947,20 @@ dependencies = [
  "zeroize",
 ]
 
+[[package]]
+name = "xtask"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "clap",
+ "frame-metadata",
+ "parity-scale-codec",
+ "run_script",
+ "scale-info",
+ "version-compare",
+ "version_check",
+]
+
 [[package]]
 name = "yamux"
 version = "0.9.0"
@@ -8860,7 +8970,7 @@ dependencies = [
  "futures 0.3.19",
  "log",
  "nohash-hasher",
- "parking_lot",
+ "parking_lot 0.11.2",
  "rand 0.8.4",
  "static_assertions",
 ]
diff --git a/Cargo.toml b/Cargo.toml
index f189aa11a2ee230b062f5a3f96258c9d0dafb385..a7d8042684aaaeb75e0ef3957083c91d22057792 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -122,6 +122,7 @@ members = [
     'primitives/membership',
     'runtime/common',
     'runtime/gdev',
+	'xtask',
 ]
 
 # The list of dependencies below (which can be both direct and indirect dependencies) are crates
diff --git a/README.md b/README.md
index 4e7cb2a1bd6a5f889c9a5396568a3ea313802037..f404a727bea695d83c5f02e7af588f82aa13dd3e 100644
--- a/README.md
+++ b/README.md
@@ -36,7 +36,7 @@ Other docker-compose files are suggested in the `docker/compose-examples` folder
 
 ## Setup
 
-First, complete the [basic setup instructions](./docs/setup.md).
+First, complete the [basic setup instructions](./docs/dev/setup.md).
 
 ## Build
 
diff --git a/docs/api/runtime-calls.md b/docs/api/runtime-calls.md
new file mode 100644
index 0000000000000000000000000000000000000000..8e594bb09ba68a97fc51a0c1e752f847561a1ba2
--- /dev/null
+++ b/docs/api/runtime-calls.md
@@ -0,0 +1,2126 @@
+# Runtime calls
+
+Calls are categorized according to the dispatch origin they require:
+
+1. User calls: the dispatch origin for this kind of call must be Signed by
+the transactor. This is the only call category that can be submitted with an extrinsic.
+1. Root calls: This kind of call requires a special origin that can only be invoked
+through on-chain governance mechanisms.
+1. Inherent calls: This kind of call is invoked by the author of the block itself
+(usually automatically by the node).
+
+
+## User calls
+
+There are **52** user calls organized in **17** pallets.
+
+### 2: Scheduler
+
+<details><summary>0: schedule(when, maybe_periodic, priority, call)</summary>
+<p>
+
+### Index
+
+`0`
+
+### Documentation
+
+Anonymously schedule a task.
+
+### Types of parameters
+
+```rust
+when: T::BlockNumber,
+maybe_periodic: Option<schedule::Period<T::BlockNumber>>,
+priority: schedule::Priority,
+call: Box<CallOrHashOf<T>>
+```
+
+</p>
+</details>
+
+<details><summary>1: cancel(when, index)</summary>
+<p>
+
+### Index
+
+`1`
+
+### Documentation
+
+Cancel an anonymously scheduled task.
+
+### Types of parameters
+
+```rust
+when: T::BlockNumber,
+index: u32
+```
+
+</p>
+</details>
+
+<details><summary>2: schedule_named(id, when, maybe_periodic, priority, call)</summary>
+<p>
+
+### Index
+
+`2`
+
+### Documentation
+
+Schedule a named task.
+
+### Types of parameters
+
+```rust
+id: Vec<u8>,
+when: T::BlockNumber,
+maybe_periodic: Option<schedule::Period<T::BlockNumber>>,
+priority: schedule::Priority,
+call: Box<CallOrHashOf<T>>
+```
+
+</p>
+</details>
+
+<details><summary>3: cancel_named(id)</summary>
+<p>
+
+### Index
+
+`3`
+
+### Documentation
+
+Cancel a named scheduled task.
+
+### Types of parameters
+
+```rust
+id: Vec<u8>
+```
+
+</p>
+</details>
+
+<details><summary>4: schedule_after(after, maybe_periodic, priority, call)</summary>
+<p>
+
+### Index
+
+`4`
+
+### Documentation
+
+Anonymously schedule a task after a delay.
+
+
+### Types of parameters
+
+```rust
+after: T::BlockNumber,
+maybe_periodic: Option<schedule::Period<T::BlockNumber>>,
+priority: schedule::Priority,
+call: Box<CallOrHashOf<T>>
+```
+
+</p>
+</details>
+
+<details><summary>5: schedule_named_after(id, after, maybe_periodic, priority, call)</summary>
+<p>
+
+### Index
+
+`5`
+
+### Documentation
+
+Schedule a named task after a delay.
+
+
+### Types of parameters
+
+```rust
+id: Vec<u8>,
+after: T::BlockNumber,
+maybe_periodic: Option<schedule::Period<T::BlockNumber>>,
+priority: schedule::Priority,
+call: Box<CallOrHashOf<T>>
+```
+
+</p>
+</details>
+
+
+### 3: Babe
+
+<details><summary>0: report_equivocation(equivocation_proof, key_owner_proof)</summary>
+<p>
+
+### Index
+
+`0`
+
+### Documentation
+
+Report authority equivocation/misbehavior. This method will verify
+the equivocation proof and validate the given key ownership proof
+against the extracted offender. If both are valid, the offence will
+be reported.
+
+### Types of parameters
+
+```rust
+equivocation_proof: Box<EquivocationProof<T::Header>>,
+key_owner_proof: T::KeyOwnerProof
+```
+
+</p>
+</details>
+
+
+### 6: Balances
+
+<details><summary>0: transfer(dest, value)</summary>
+<p>
+
+### Index
+
+`0`
+
+### Documentation
+
+Transfer some liquid free balance to another account.
+
+`transfer` will set the `FreeBalance` of the sender and receiver.
+If the sender's account is below the existential deposit as a result
+of the transfer, the account will be reaped.
+
+The dispatch origin for this call must be `Signed` by the transactor.
+
+
+### Types of parameters
+
+```rust
+dest: <T::Lookup as StaticLookup>::Source,
+value: T::Balance
+```
+
+</p>
+</details>
+
+<details><summary>3: transfer_keep_alive(dest, value)</summary>
+<p>
+
+### Index
+
+`3`
+
+### Documentation
+
+Same as the [`transfer`] call, but with a check that the transfer will not kill the
+origin account.
+
+99% of the time you want [`transfer`] instead.
+
+[`transfer`]: struct.Pallet.html#method.transfer
+
+### Types of parameters
+
+```rust
+dest: <T::Lookup as StaticLookup>::Source,
+value: T::Balance
+```
+
+</p>
+</details>
+
+<details><summary>4: transfer_all(dest, keep_alive)</summary>
+<p>
+
+### Index
+
+`4`
+
+### Documentation
+
+Transfer the entire transferable balance from the caller account.
+
+NOTE: This function only attempts to transfer _transferable_ balances. This means that
+any locked, reserved, or existential deposits (when `keep_alive` is `true`), will not be
+transferred by this function. To ensure that this function results in a killed account,
+you might need to prepare the account by removing any reference counters, storage
+deposits, etc...
+
+The dispatch origin of this call must be Signed.
+
+- `dest`: The recipient of the transfer.
+- `keep_alive`: A boolean to determine if the `transfer_all` operation should send all
+  of the funds the account has, causing the sender account to be killed (false), or
+  transfer everything except at least the existential deposit, which will guarantee to
+  keep the sender account alive (true). # <weight>
+- O(1). Just like transfer, but reading the user's transferable balance first.
+  #</weight>
+
+### Types of parameters
+
+```rust
+dest: <T::Lookup as StaticLookup>::Source,
+keep_alive: bool
+```
+
+</p>
+</details>
+
+
+### 10: AuthorityMembers
+
+<details><summary>0: go_offline()</summary>
+<p>
+
+### Index
+
+`0`
+
+### Documentation
+
+
+
+</p>
+</details>
+
+<details><summary>1: go_online()</summary>
+<p>
+
+### Index
+
+`1`
+
+### Documentation
+
+
+
+</p>
+</details>
+
+<details><summary>2: set_session_keys(keys)</summary>
+<p>
+
+### Index
+
+`2`
+
+### Documentation
+
+
+
+### Types of parameters
+
+```rust
+keys: T::KeysWrapper
+```
+
+</p>
+</details>
+
+
+### 15: Grandpa
+
+<details><summary>0: report_equivocation(equivocation_proof, key_owner_proof)</summary>
+<p>
+
+### Index
+
+`0`
+
+### Documentation
+
+Report voter equivocation/misbehavior. This method will verify the
+equivocation proof and validate the given key ownership proof
+against the extracted offender. If both are valid, the offence
+will be reported.
+
+### Types of parameters
+
+```rust
+equivocation_proof: Box<EquivocationProof<T::Hash, T::BlockNumber>>,
+key_owner_proof: T::KeyOwnerProof
+```
+
+</p>
+</details>
+
+
+### 31: UniversalDividend
+
+<details><summary>0: transfer_ud(dest, value)</summary>
+<p>
+
+### Index
+
+`0`
+
+### Documentation
+
+Transfer some liquid free balance to another account, in milliUD.
+
+### Types of parameters
+
+```rust
+dest: <T::Lookup as StaticLookup>::Source,
+value: BalanceOf<T>
+```
+
+</p>
+</details>
+
+<details><summary>1: transfer_ud_keep_alive(dest, value)</summary>
+<p>
+
+### Index
+
+`1`
+
+### Documentation
+
+Transfer some liquid free balance to another account, in milliUD.
+
+### Types of parameters
+
+```rust
+dest: <T::Lookup as StaticLookup>::Source,
+value: BalanceOf<T>
+```
+
+</p>
+</details>
+
+
+### 41: Identity
+
+<details><summary>0: create_identity(owner_key)</summary>
+<p>
+
+### Index
+
+`0`
+
+### Documentation
+
+
+
+### Types of parameters
+
+```rust
+owner_key: T::AccountId
+```
+
+</p>
+</details>
+
+<details><summary>1: confirm_identity(idty_name)</summary>
+<p>
+
+### Index
+
+`1`
+
+### Documentation
+
+
+
+### Types of parameters
+
+```rust
+idty_name: IdtyName
+```
+
+</p>
+</details>
+
+<details><summary>2: validate_identity(idty_index)</summary>
+<p>
+
+### Index
+
+`2`
+
+### Documentation
+
+
+
+### Types of parameters
+
+```rust
+idty_index: T::IdtyIndex
+```
+
+</p>
+</details>
+
+<details><summary>3: revoke_identity(payload, payload_sig)</summary>
+<p>
+
+### Index
+
+`3`
+
+### Documentation
+
+
+
+### Types of parameters
+
+```rust
+payload: RevocationPayload<T::AccountId, T::Hash>,
+payload_sig: T::RevocationSignature
+```
+
+</p>
+</details>
+
+
+### 42: Membership
+
+<details><summary>1: request_membership(metadata)</summary>
+<p>
+
+### Index
+
+`1`
+
+### Documentation
+
+
+
+### Types of parameters
+
+```rust
+metadata: T::MetaData
+```
+
+</p>
+</details>
+
+<details><summary>3: renew_membership(maybe_idty_id)</summary>
+<p>
+
+### Index
+
+`3`
+
+### Documentation
+
+
+
+### Types of parameters
+
+```rust
+maybe_idty_id: Option<T::IdtyId>
+```
+
+</p>
+</details>
+
+
+### 43: Cert
+
+<details><summary>1: add_cert(receiver)</summary>
+<p>
+
+### Index
+
+`1`
+
+### Documentation
+
+
+
+### Types of parameters
+
+```rust
+receiver: T::AccountId
+```
+
+</p>
+</details>
+
+
+### 52: SmithsMembership
+
+<details><summary>1: request_membership(metadata)</summary>
+<p>
+
+### Index
+
+`1`
+
+### Documentation
+
+
+
+### Types of parameters
+
+```rust
+metadata: T::MetaData
+```
+
+</p>
+</details>
+
+<details><summary>3: renew_membership(maybe_idty_id)</summary>
+<p>
+
+### Index
+
+`3`
+
+### Documentation
+
+
+
+### Types of parameters
+
+```rust
+maybe_idty_id: Option<T::IdtyId>
+```
+
+</p>
+</details>
+
+<details><summary>4: revoke_membership(maybe_idty_id)</summary>
+<p>
+
+### Index
+
+`4`
+
+### Documentation
+
+
+
+### Types of parameters
+
+```rust
+maybe_idty_id: Option<T::IdtyId>
+```
+
+</p>
+</details>
+
+
+### 53: SmithsCert
+
+<details><summary>1: add_cert(receiver)</summary>
+<p>
+
+### Index
+
+`1`
+
+### Documentation
+
+
+
+### Types of parameters
+
+```rust
+receiver: T::AccountId
+```
+
+</p>
+</details>
+
+
+### 54: SmithsCollective
+
+<details><summary>1: execute(proposal, length_bound)</summary>
+<p>
+
+### Index
+
+`1`
+
+### Documentation
+
+Dispatch a proposal from a member using the `Member` origin.
+
+Origin must be a member of the collective.
+
+
+### Types of parameters
+
+```rust
+proposal: Box<<T as Config<I>>::Proposal>,
+length_bound: u32
+```
+
+</p>
+</details>
+
+<details><summary>2: propose(threshold, proposal, length_bound)</summary>
+<p>
+
+### Index
+
+`2`
+
+### Documentation
+
+Add a new proposal to either be voted on or executed directly.
+
+Requires the sender to be member.
+
+`threshold` determines whether `proposal` is executed directly (`threshold < 2`)
+or put up for voting.
+
+
+### Types of parameters
+
+```rust
+threshold: MemberCount,
+proposal: Box<<T as Config<I>>::Proposal>,
+length_bound: u32
+```
+
+</p>
+</details>
+
+<details><summary>3: vote(proposal, index, approve)</summary>
+<p>
+
+### Index
+
+`3`
+
+### Documentation
+
+Add an aye or nay vote for the sender to the given proposal.
+
+Requires the sender to be a member.
+
+Transaction fees will be waived if the member is voting on any particular proposal
+for the first time and the call is successful. Subsequent vote changes will charge a
+fee.
+
+### Types of parameters
+
+```rust
+proposal: T::Hash,
+index: ProposalIndex,
+approve: bool
+```
+
+</p>
+</details>
+
+<details><summary>4: close(proposal_hash, index, proposal_weight_bound, length_bound)</summary>
+<p>
+
+### Index
+
+`4`
+
+### Documentation
+
+Close a vote that is either approved, disapproved or whose voting period has ended.
+
+May be called by any signed account in order to finish voting and close the proposal.
+
+If called before the end of the voting period it will only close the vote if it is
+has enough votes to be approved or disapproved.
+
+If called after the end of the voting period abstentions are counted as rejections
+unless there is a prime member set and the prime member cast an approval.
+
+If the close operation completes successfully with disapproval, the transaction fee will
+be waived. Otherwise execution of the approved operation will be charged to the caller.
+
++ `proposal_weight_bound`: The maximum amount of weight consumed by executing the closed
+proposal.
++ `length_bound`: The upper bound for the length of the proposal in storage. Checked via
+`storage::read` so it is `size_of::<u32>() == 4` larger than the pure length.
+
+
+### Types of parameters
+
+```rust
+proposal_hash: T::Hash,
+index: ProposalIndex,
+proposal_weight_bound: Weight,
+length_bound: u32
+```
+
+</p>
+</details>
+
+
+### 60: AtomicSwap
+
+<details><summary>0: create_swap(target, hashed_proof, action, duration)</summary>
+<p>
+
+### Index
+
+`0`
+
+### Documentation
+
+Register a new atomic swap, declaring an intention to send funds from origin to target
+on the current blockchain. The target can claim the fund using the revealed proof. If
+the fund is not claimed after `duration` blocks, then the sender can cancel the swap.
+
+The dispatch origin for this call must be _Signed_.
+
+- `target`: Receiver of the atomic swap.
+- `hashed_proof`: The blake2_256 hash of the secret proof.
+- `balance`: Funds to be sent from origin.
+- `duration`: Locked duration of the atomic swap. For safety reasons, it is recommended
+  that the revealer uses a shorter duration than the counterparty, to prevent the
+  situation where the revealer reveals the proof too late around the end block.
+
+### Types of parameters
+
+```rust
+target: T::AccountId,
+hashed_proof: HashedProof,
+action: T::SwapAction,
+duration: T::BlockNumber
+```
+
+</p>
+</details>
+
+<details><summary>1: claim_swap(proof, action)</summary>
+<p>
+
+### Index
+
+`1`
+
+### Documentation
+
+Claim an atomic swap.
+
+The dispatch origin for this call must be _Signed_.
+
+- `proof`: Revealed proof of the claim.
+- `action`: Action defined in the swap, it must match the entry in blockchain. Otherwise
+  the operation fails. This is used for weight calculation.
+
+### Types of parameters
+
+```rust
+proof: Vec<u8>,
+action: T::SwapAction
+```
+
+</p>
+</details>
+
+<details><summary>2: cancel_swap(target, hashed_proof)</summary>
+<p>
+
+### Index
+
+`2`
+
+### Documentation
+
+Cancel an atomic swap. Only possible after the originally set duration has passed.
+
+The dispatch origin for this call must be _Signed_.
+
+- `target`: Target of the original atomic swap.
+- `hashed_proof`: Hashed proof of the original atomic swap.
+
+### Types of parameters
+
+```rust
+target: T::AccountId,
+hashed_proof: HashedProof
+```
+
+</p>
+</details>
+
+
+### 61: Multisig
+
+<details><summary>0: as_multi_threshold_1(other_signatories, call)</summary>
+<p>
+
+### Index
+
+`0`
+
+### Documentation
+
+Immediately dispatch a multi-signature call using a single approval from the caller.
+
+The dispatch origin for this call must be _Signed_.
+
+- `other_signatories`: The accounts (other than the sender) who are part of the
+multi-signature, but do not participate in the approval process.
+- `call`: The call to be executed.
+
+Result is equivalent to the dispatched result.
+
+
+### Types of parameters
+
+```rust
+other_signatories: Vec<T::AccountId>,
+call: Box<<T as Config>::Call>
+```
+
+</p>
+</details>
+
+<details><summary>1: as_multi(threshold, other_signatories, maybe_timepoint, call, store_call, max_weight)</summary>
+<p>
+
+### Index
+
+`1`
+
+### Documentation
+
+Register approval for a dispatch to be made from a deterministic composite account if
+approved by a total of `threshold - 1` of `other_signatories`.
+
+If there are enough, then dispatch the call.
+
+Payment: `DepositBase` will be reserved if this is the first approval, plus
+`threshold` times `DepositFactor`. It is returned once this dispatch happens or
+is cancelled.
+
+The dispatch origin for this call must be _Signed_.
+
+- `threshold`: The total number of approvals for this dispatch before it is executed.
+- `other_signatories`: The accounts (other than the sender) who can approve this
+dispatch. May not be empty.
+- `maybe_timepoint`: If this is the first approval, then this must be `None`. If it is
+not the first approval, then it must be `Some`, with the timepoint (block number and
+transaction index) of the first approval transaction.
+- `call`: The call to be executed.
+
+NOTE: Unless this is the final approval, you will generally want to use
+`approve_as_multi` instead, since it only requires a hash of the call.
+
+Result is equivalent to the dispatched result if `threshold` is exactly `1`. Otherwise
+on success, result is `Ok` and the result from the interior call, if it was executed,
+may be found in the deposited `MultisigExecuted` event.
+
+
+### Types of parameters
+
+```rust
+threshold: u16,
+other_signatories: Vec<T::AccountId>,
+maybe_timepoint: Option<Timepoint<T::BlockNumber>>,
+call: OpaqueCall<T>,
+store_call: bool,
+max_weight: Weight
+```
+
+</p>
+</details>
+
+<details><summary>2: approve_as_multi(threshold, other_signatories, maybe_timepoint, call_hash, max_weight)</summary>
+<p>
+
+### Index
+
+`2`
+
+### Documentation
+
+Register approval for a dispatch to be made from a deterministic composite account if
+approved by a total of `threshold - 1` of `other_signatories`.
+
+Payment: `DepositBase` will be reserved if this is the first approval, plus
+`threshold` times `DepositFactor`. It is returned once this dispatch happens or
+is cancelled.
+
+The dispatch origin for this call must be _Signed_.
+
+- `threshold`: The total number of approvals for this dispatch before it is executed.
+- `other_signatories`: The accounts (other than the sender) who can approve this
+dispatch. May not be empty.
+- `maybe_timepoint`: If this is the first approval, then this must be `None`. If it is
+not the first approval, then it must be `Some`, with the timepoint (block number and
+transaction index) of the first approval transaction.
+- `call_hash`: The hash of the call to be executed.
+
+NOTE: If this is the final approval, you will want to use `as_multi` instead.
+
+
+### Types of parameters
+
+```rust
+threshold: u16,
+other_signatories: Vec<T::AccountId>,
+maybe_timepoint: Option<Timepoint<T::BlockNumber>>,
+call_hash: [u8; 32],
+max_weight: Weight
+```
+
+</p>
+</details>
+
+<details><summary>3: cancel_as_multi(threshold, other_signatories, timepoint, call_hash)</summary>
+<p>
+
+### Index
+
+`3`
+
+### Documentation
+
+Cancel a pre-existing, on-going multisig transaction. Any deposit reserved previously
+for this operation will be unreserved on success.
+
+The dispatch origin for this call must be _Signed_.
+
+- `threshold`: The total number of approvals for this dispatch before it is executed.
+- `other_signatories`: The accounts (other than the sender) who can approve this
+dispatch. May not be empty.
+- `timepoint`: The timepoint (block number and transaction index) of the first approval
+transaction for this dispatch.
+- `call_hash`: The hash of the call to be executed.
+
+
+### Types of parameters
+
+```rust
+threshold: u16,
+other_signatories: Vec<T::AccountId>,
+timepoint: Timepoint<T::BlockNumber>,
+call_hash: [u8; 32]
+```
+
+</p>
+</details>
+
+
+### 62: ProvideRandomness
+
+<details><summary>0: request(randomness_type, salt)</summary>
+<p>
+
+### Index
+
+`0`
+
+### Documentation
+
+Request a randomness
+
+### Types of parameters
+
+```rust
+randomness_type: RandomnessType,
+salt: H256
+```
+
+</p>
+</details>
+
+
+### 63: Proxy
+
+<details><summary>0: proxy(real, force_proxy_type, call)</summary>
+<p>
+
+### Index
+
+`0`
+
+### Documentation
+
+Dispatch the given `call` from an account that the sender is authorised for through
+`add_proxy`.
+
+Removes any corresponding announcement(s).
+
+The dispatch origin for this call must be _Signed_.
+
+Parameters:
+- `real`: The account that the proxy will make a call on behalf of.
+- `force_proxy_type`: Specify the exact proxy type to be used and checked for this call.
+- `call`: The call to be made by the `real` account.
+
+
+### Types of parameters
+
+```rust
+real: T::AccountId,
+force_proxy_type: Option<T::ProxyType>,
+call: Box<<T as Config>::Call>
+```
+
+</p>
+</details>
+
+<details><summary>1: add_proxy(delegate, proxy_type, delay)</summary>
+<p>
+
+### Index
+
+`1`
+
+### Documentation
+
+Register a proxy account for the sender that is able to make calls on its behalf.
+
+The dispatch origin for this call must be _Signed_.
+
+Parameters:
+- `proxy`: The account that the `caller` would like to make a proxy.
+- `proxy_type`: The permissions allowed for this proxy account.
+- `delay`: The announcement period required of the initial proxy. Will generally be
+zero.
+
+
+### Types of parameters
+
+```rust
+delegate: T::AccountId,
+proxy_type: T::ProxyType,
+delay: T::BlockNumber
+```
+
+</p>
+</details>
+
+<details><summary>2: remove_proxy(delegate, proxy_type, delay)</summary>
+<p>
+
+### Index
+
+`2`
+
+### Documentation
+
+Unregister a proxy account for the sender.
+
+The dispatch origin for this call must be _Signed_.
+
+Parameters:
+- `proxy`: The account that the `caller` would like to remove as a proxy.
+- `proxy_type`: The permissions currently enabled for the removed proxy account.
+
+
+### Types of parameters
+
+```rust
+delegate: T::AccountId,
+proxy_type: T::ProxyType,
+delay: T::BlockNumber
+```
+
+</p>
+</details>
+
+<details><summary>3: remove_proxies()</summary>
+<p>
+
+### Index
+
+`3`
+
+### Documentation
+
+Unregister all proxy accounts for the sender.
+
+The dispatch origin for this call must be _Signed_.
+
+WARNING: This may be called on accounts created by `anonymous`, however if done, then
+the unreserved fees will be inaccessible. **All access to this account will be lost.**
+
+
+</p>
+</details>
+
+<details><summary>4: anonymous(proxy_type, delay, index)</summary>
+<p>
+
+### Index
+
+`4`
+
+### Documentation
+
+Spawn a fresh new account that is guaranteed to be otherwise inaccessible, and
+initialize it with a proxy of `proxy_type` for `origin` sender.
+
+Requires a `Signed` origin.
+
+- `proxy_type`: The type of the proxy that the sender will be registered as over the
+new account. This will almost always be the most permissive `ProxyType` possible to
+allow for maximum flexibility.
+- `index`: A disambiguation index, in case this is called multiple times in the same
+transaction (e.g. with `utility::batch`). Unless you're using `batch` you probably just
+want to use `0`.
+- `delay`: The announcement period required of the initial proxy. Will generally be
+zero.
+
+Fails with `Duplicate` if this has already been called in this transaction, from the
+same sender, with the same parameters.
+
+Fails if there are insufficient funds to pay for deposit.
+
+
+### Types of parameters
+
+```rust
+proxy_type: T::ProxyType,
+delay: T::BlockNumber,
+index: u16
+```
+
+</p>
+</details>
+
+<details><summary>5: kill_anonymous(spawner, proxy_type, index, height, ext_index)</summary>
+<p>
+
+### Index
+
+`5`
+
+### Documentation
+
+Removes a previously spawned anonymous proxy.
+
+WARNING: **All access to this account will be lost.** Any funds held in it will be
+inaccessible.
+
+Requires a `Signed` origin, and the sender account must have been created by a call to
+`anonymous` with corresponding parameters.
+
+- `spawner`: The account that originally called `anonymous` to create this account.
+- `index`: The disambiguation index originally passed to `anonymous`. Probably `0`.
+- `proxy_type`: The proxy type originally passed to `anonymous`.
+- `height`: The height of the chain when the call to `anonymous` was processed.
+- `ext_index`: The extrinsic index in which the call to `anonymous` was processed.
+
+Fails with `NoPermission` in case the caller is not a previously created anonymous
+account whose `anonymous` call has corresponding parameters.
+
+
+### Types of parameters
+
+```rust
+spawner: T::AccountId,
+proxy_type: T::ProxyType,
+index: u16,
+height: T::BlockNumber,
+ext_index: u32
+```
+
+</p>
+</details>
+
+<details><summary>6: announce(real, call_hash)</summary>
+<p>
+
+### Index
+
+`6`
+
+### Documentation
+
+Publish the hash of a proxy-call that will be made in the future.
+
+This must be called some number of blocks before the corresponding `proxy` is attempted
+if the delay associated with the proxy relationship is greater than zero.
+
+No more than `MaxPending` announcements may be made at any one time.
+
+This will take a deposit of `AnnouncementDepositFactor` as well as
+`AnnouncementDepositBase` if there are no other pending announcements.
+
+The dispatch origin for this call must be _Signed_ and a proxy of `real`.
+
+Parameters:
+- `real`: The account that the proxy will make a call on behalf of.
+- `call_hash`: The hash of the call to be made by the `real` account.
+
+
+### Types of parameters
+
+```rust
+real: T::AccountId,
+call_hash: CallHashOf<T>
+```
+
+</p>
+</details>
+
+<details><summary>7: remove_announcement(real, call_hash)</summary>
+<p>
+
+### Index
+
+`7`
+
+### Documentation
+
+Remove a given announcement.
+
+May be called by a proxy account to remove a call they previously announced and return
+the deposit.
+
+The dispatch origin for this call must be _Signed_.
+
+Parameters:
+- `real`: The account that the proxy will make a call on behalf of.
+- `call_hash`: The hash of the call to be made by the `real` account.
+
+
+### Types of parameters
+
+```rust
+real: T::AccountId,
+call_hash: CallHashOf<T>
+```
+
+</p>
+</details>
+
+<details><summary>8: reject_announcement(delegate, call_hash)</summary>
+<p>
+
+### Index
+
+`8`
+
+### Documentation
+
+Remove the given announcement of a delegate.
+
+May be called by a target (proxied) account to remove a call that one of their delegates
+(`delegate`) has announced they want to execute. The deposit is returned.
+
+The dispatch origin for this call must be _Signed_.
+
+Parameters:
+- `delegate`: The account that previously announced the call.
+- `call_hash`: The hash of the call to be made.
+
+
+### Types of parameters
+
+```rust
+delegate: T::AccountId,
+call_hash: CallHashOf<T>
+```
+
+</p>
+</details>
+
+<details><summary>9: proxy_announced(delegate, real, force_proxy_type, call)</summary>
+<p>
+
+### Index
+
+`9`
+
+### Documentation
+
+Dispatch the given `call` from an account that the sender is authorized for through
+`add_proxy`.
+
+Removes any corresponding announcement(s).
+
+The dispatch origin for this call must be _Signed_.
+
+Parameters:
+- `real`: The account that the proxy will make a call on behalf of.
+- `force_proxy_type`: Specify the exact proxy type to be used and checked for this call.
+- `call`: The call to be made by the `real` account.
+
+
+### Types of parameters
+
+```rust
+delegate: T::AccountId,
+real: T::AccountId,
+force_proxy_type: Option<T::ProxyType>,
+call: Box<<T as Config>::Call>
+```
+
+</p>
+</details>
+
+
+### 64: Utility
+
+<details><summary>0: batch(calls)</summary>
+<p>
+
+### Index
+
+`0`
+
+### Documentation
+
+Send a batch of dispatch calls.
+
+May be called from any origin.
+
+- `calls`: The calls to be dispatched from the same origin. The number of call must not
+  exceed the constant: `batched_calls_limit` (available in constant metadata).
+
+If origin is root then call are dispatch without checking origin filter. (This includes
+bypassing `frame_system::Config::BaseCallFilter`).
+
+
+### Types of parameters
+
+```rust
+calls: Vec<<T as Config>::Call>
+```
+
+</p>
+</details>
+
+<details><summary>1: as_derivative(index, call)</summary>
+<p>
+
+### Index
+
+`1`
+
+### Documentation
+
+Send a call through an indexed pseudonym of the sender.
+
+Filter from origin are passed along. The call will be dispatched with an origin which
+use the same filter as the origin of this call.
+
+NOTE: If you need to ensure that any account-based filtering is not honored (i.e.
+because you expect `proxy` to have been used prior in the call stack and you do not want
+the call restrictions to apply to any sub-accounts), then use `as_multi_threshold_1`
+in the Multisig pallet instead.
+
+NOTE: Prior to version *12, this was called `as_limited_sub`.
+
+The dispatch origin for this call must be _Signed_.
+
+### Types of parameters
+
+```rust
+index: u16,
+call: Box<<T as Config>::Call>
+```
+
+</p>
+</details>
+
+<details><summary>2: batch_all(calls)</summary>
+<p>
+
+### Index
+
+`2`
+
+### Documentation
+
+Send a batch of dispatch calls and atomically execute them.
+The whole transaction will rollback and fail if any of the calls failed.
+
+May be called from any origin.
+
+- `calls`: The calls to be dispatched from the same origin. The number of call must not
+  exceed the constant: `batched_calls_limit` (available in constant metadata).
+
+If origin is root then call are dispatch without checking origin filter. (This includes
+bypassing `frame_system::Config::BaseCallFilter`).
+
+
+### Types of parameters
+
+```rust
+calls: Vec<<T as Config>::Call>
+```
+
+</p>
+</details>
+
+
+
+## Root calls
+
+There are **28** root calls organized in **12** pallets.
+
+### 0: System
+
+<details><summary>0: fill_block(ratio)</summary>
+<p>
+
+### Index
+
+`0`
+
+### Documentation
+
+A dispatch that will fill the block weight up to the given ratio.
+
+### Types of parameters
+
+```rust
+ratio: Perbill
+```
+
+</p>
+</details>
+
+<details><summary>2: set_heap_pages(pages)</summary>
+<p>
+
+### Index
+
+`2`
+
+### Documentation
+
+Set the number of pages in the WebAssembly environment's heap.
+
+### Types of parameters
+
+```rust
+pages: u64
+```
+
+</p>
+</details>
+
+<details><summary>3: set_code(code)</summary>
+<p>
+
+### Index
+
+`3`
+
+### Documentation
+
+Set the new runtime code.
+
+
+### Types of parameters
+
+```rust
+code: Vec<u8>
+```
+
+</p>
+</details>
+
+<details><summary>4: set_code_without_checks(code)</summary>
+<p>
+
+### Index
+
+`4`
+
+### Documentation
+
+Set the new runtime code without doing any checks of the given `code`.
+
+
+### Types of parameters
+
+```rust
+code: Vec<u8>
+```
+
+</p>
+</details>
+
+<details><summary>5: set_storage(items)</summary>
+<p>
+
+### Index
+
+`5`
+
+### Documentation
+
+Set some items of storage.
+
+### Types of parameters
+
+```rust
+items: Vec<KeyValue>
+```
+
+</p>
+</details>
+
+<details><summary>6: kill_storage(keys)</summary>
+<p>
+
+### Index
+
+`6`
+
+### Documentation
+
+Kill some items from storage.
+
+### Types of parameters
+
+```rust
+keys: Vec<Key>
+```
+
+</p>
+</details>
+
+<details><summary>7: kill_prefix(prefix, subkeys)</summary>
+<p>
+
+### Index
+
+`7`
+
+### Documentation
+
+Kill all storage items with a key that starts with the given prefix.
+
+**NOTE:** We rely on the Root origin to provide us the number of subkeys under
+the prefix we are removing to accurately calculate the weight of this function.
+
+### Types of parameters
+
+```rust
+prefix: Key,
+subkeys: u32
+```
+
+</p>
+</details>
+
+
+### 3: Babe
+
+<details><summary>2: plan_config_change(config)</summary>
+<p>
+
+### Index
+
+`2`
+
+### Documentation
+
+Plan an epoch config change. The epoch config change is recorded and will be enacted on
+the next call to `enact_epoch_change`. The config will be activated one epoch after.
+Multiple calls to this method will replace any existing planned config change that had
+not been enacted yet.
+
+### Types of parameters
+
+```rust
+config: NextConfigDescriptor
+```
+
+</p>
+</details>
+
+
+### 6: Balances
+
+<details><summary>1: set_balance(who, new_free, new_reserved)</summary>
+<p>
+
+### Index
+
+`1`
+
+### Documentation
+
+Set the balances of a given account.
+
+This will alter `FreeBalance` and `ReservedBalance` in storage. it will
+also alter the total issuance of the system (`TotalIssuance`) appropriately.
+If the new free or reserved balance is below the existential deposit,
+it will reset the account nonce (`frame_system::AccountNonce`).
+
+The dispatch origin for this call is `root`.
+
+### Types of parameters
+
+```rust
+who: <T::Lookup as StaticLookup>::Source,
+new_free: T::Balance,
+new_reserved: T::Balance
+```
+
+</p>
+</details>
+
+<details><summary>2: force_transfer(source, dest, value)</summary>
+<p>
+
+### Index
+
+`2`
+
+### Documentation
+
+Exactly as `transfer`, except the origin must be root and the source account may be
+specified.
+
+### Types of parameters
+
+```rust
+source: <T::Lookup as StaticLookup>::Source,
+dest: <T::Lookup as StaticLookup>::Source,
+value: T::Balance
+```
+
+</p>
+</details>
+
+<details><summary>5: force_unreserve(who, amount)</summary>
+<p>
+
+### Index
+
+`5`
+
+### Documentation
+
+Unreserve some balance from a user by force.
+
+Can only be called by ROOT.
+
+### Types of parameters
+
+```rust
+who: <T::Lookup as StaticLookup>::Source,
+amount: T::Balance
+```
+
+</p>
+</details>
+
+
+### 10: AuthorityMembers
+
+<details><summary>3: prune_account_id_of(members_ids)</summary>
+<p>
+
+### Index
+
+`3`
+
+### Documentation
+
+
+
+### Types of parameters
+
+```rust
+members_ids: Vec<T::MemberId>
+```
+
+</p>
+</details>
+
+<details><summary>4: remove_member(member_id)</summary>
+<p>
+
+### Index
+
+`4`
+
+### Documentation
+
+
+
+### Types of parameters
+
+```rust
+member_id: T::MemberId
+```
+
+</p>
+</details>
+
+
+### 15: Grandpa
+
+<details><summary>2: note_stalled(delay, best_finalized_block_number)</summary>
+<p>
+
+### Index
+
+`2`
+
+### Documentation
+
+Note that the current authority set of the GRANDPA finality gadget has
+stalled. This will trigger a forced authority set change at the beginning
+of the next session, to be enacted `delay` blocks after that. The delay
+should be high enough to safely assume that the block signalling the
+forced change will not be re-orged (e.g. 1000 blocks). The GRANDPA voters
+will start the new authority set using the given finalized block as base.
+Only callable by root.
+
+### Types of parameters
+
+```rust
+delay: T::BlockNumber,
+best_finalized_block_number: T::BlockNumber
+```
+
+</p>
+</details>
+
+
+### 41: Identity
+
+<details><summary>4: remove_identity(idty_index, idty_name)</summary>
+<p>
+
+### Index
+
+`4`
+
+### Documentation
+
+
+
+### Types of parameters
+
+```rust
+idty_index: T::IdtyIndex,
+idty_name: Option<IdtyName>
+```
+
+</p>
+</details>
+
+<details><summary>5: prune_item_identities_names(names)</summary>
+<p>
+
+### Index
+
+`5`
+
+### Documentation
+
+
+
+### Types of parameters
+
+```rust
+names: Vec<IdtyName>
+```
+
+</p>
+</details>
+
+<details><summary>6: prune_item_identity_index_of(accounts_ids)</summary>
+<p>
+
+### Index
+
+`6`
+
+### Documentation
+
+
+
+### Types of parameters
+
+```rust
+accounts_ids: Vec<T::AccountId>
+```
+
+</p>
+</details>
+
+
+### 42: Membership
+
+<details><summary>0: force_request_membership(idty_id, metadata)</summary>
+<p>
+
+### Index
+
+`0`
+
+### Documentation
+
+
+
+### Types of parameters
+
+```rust
+idty_id: T::IdtyId,
+metadata: T::MetaData
+```
+
+</p>
+</details>
+
+
+### 43: Cert
+
+<details><summary>0: force_add_cert(issuer, receiver, verify_rules)</summary>
+<p>
+
+### Index
+
+`0`
+
+### Documentation
+
+
+
+### Types of parameters
+
+```rust
+issuer: T::IdtyIndex,
+receiver: T::IdtyIndex,
+verify_rules: bool
+```
+
+</p>
+</details>
+
+<details><summary>2: del_cert(issuer, receiver)</summary>
+<p>
+
+### Index
+
+`2`
+
+### Documentation
+
+
+
+### Types of parameters
+
+```rust
+issuer: T::IdtyIndex,
+receiver: T::IdtyIndex
+```
+
+</p>
+</details>
+
+<details><summary>3: remove_all_certs_received_by(idty_index)</summary>
+<p>
+
+### Index
+
+`3`
+
+### Documentation
+
+
+
+### Types of parameters
+
+```rust
+idty_index: T::IdtyIndex
+```
+
+</p>
+</details>
+
+
+### 52: SmithsMembership
+
+<details><summary>0: force_request_membership(idty_id, metadata)</summary>
+<p>
+
+### Index
+
+`0`
+
+### Documentation
+
+
+
+### Types of parameters
+
+```rust
+idty_id: T::IdtyId,
+metadata: T::MetaData
+```
+
+</p>
+</details>
+
+
+### 53: SmithsCert
+
+<details><summary>0: force_add_cert(issuer, receiver, verify_rules)</summary>
+<p>
+
+### Index
+
+`0`
+
+### Documentation
+
+
+
+### Types of parameters
+
+```rust
+issuer: T::IdtyIndex,
+receiver: T::IdtyIndex,
+verify_rules: bool
+```
+
+</p>
+</details>
+
+<details><summary>2: del_cert(issuer, receiver)</summary>
+<p>
+
+### Index
+
+`2`
+
+### Documentation
+
+
+
+### Types of parameters
+
+```rust
+issuer: T::IdtyIndex,
+receiver: T::IdtyIndex
+```
+
+</p>
+</details>
+
+<details><summary>3: remove_all_certs_received_by(idty_index)</summary>
+<p>
+
+### Index
+
+`3`
+
+### Documentation
+
+
+
+### Types of parameters
+
+```rust
+idty_index: T::IdtyIndex
+```
+
+</p>
+</details>
+
+
+### 54: SmithsCollective
+
+<details><summary>0: set_members(new_members, prime, old_count)</summary>
+<p>
+
+### Index
+
+`0`
+
+### Documentation
+
+Set the collective's membership.
+
+- `new_members`: The new member list. Be nice to the chain and provide it sorted.
+- `prime`: The prime member whose vote sets the default.
+- `old_count`: The upper bound for the previous number of members in storage. Used for
+  weight estimation.
+
+Requires root origin.
+
+NOTE: Does not enforce the expected `MaxMembers` limit on the amount of members, but
+      the weight estimations rely on it to estimate dispatchable weight.
+
+# WARNING:
+
+The `pallet-collective` can also be managed by logic outside of the pallet through the
+implementation of the trait [`ChangeMembers`].
+Any call to `set_members` must be careful that the member set doesn't get out of sync
+with other logic managing the member set.
+
+
+### Types of parameters
+
+```rust
+new_members: Vec<T::AccountId>,
+prime: Option<T::AccountId>,
+old_count: MemberCount
+```
+
+</p>
+</details>
+
+<details><summary>5: disapprove_proposal(proposal_hash)</summary>
+<p>
+
+### Index
+
+`5`
+
+### Documentation
+
+Disapprove a proposal, close, and remove it from the system, regardless of its current
+state.
+
+Must be called by the Root origin.
+
+Parameters:
+* `proposal_hash`: The hash of the proposal that should be disapproved.
+
+
+### Types of parameters
+
+```rust
+proposal_hash: T::Hash
+```
+
+</p>
+</details>
+
+
+### 64: Utility
+
+<details><summary>3: dispatch_as(as_origin, call)</summary>
+<p>
+
+### Index
+
+`3`
+
+### Documentation
+
+Dispatches a function call with a provided origin.
+
+The dispatch origin for this call must be _Root_.
+
+
+### Types of parameters
+
+```rust
+as_origin: Box<T::PalletsOrigin>,
+call: Box<<T as Config>::Call>
+```
+
+</p>
+</details>
+
diff --git a/docs/setup.md b/docs/dev/setup.md
similarity index 100%
rename from docs/setup.md
rename to docs/dev/setup.md
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..43fefae3b990d0bb6f201a4c725ff0a2da4d34bd
--- /dev/null
+++ b/xtask/Cargo.toml
@@ -0,0 +1,23 @@
+[package]
+authors = ["elois <elois@duniter.org>"]
+description = "Duniter-v2s xtask"
+edition = "2018"
+license = "AGPL-3.0"
+name = "xtask"
+repository = "https://git.duniter.org/nodes/typescript/duniter"
+version = "0.1.0"
+
+[[bin]]
+bench = false
+path = "src/main.rs"
+name = "xtask"
+
+[dependencies]
+anyhow = "1.0.32"
+clap = { version = "3.0", features = ["derive"] }
+codec = { package = "parity-scale-codec", version = "2", default-features = false, features = ["derive", "full", "bit-vec"] }
+frame-metadata = "14.0.0"
+run_script = "0.6.3"
+scale-info = { version = "1.0.0", features = ["bit-vec"] }
+version_check = "0.9.2"
+version-compare = "0.0.11"
diff --git a/xtask/src/gen_calls_doc.rs b/xtask/src/gen_calls_doc.rs
new file mode 100644
index 0000000000000000000000000000000000000000..87c795fdece1553f9999fd8ada6d0b7605bee3f8
--- /dev/null
+++ b/xtask/src/gen_calls_doc.rs
@@ -0,0 +1,331 @@
+// 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/>.
+
+use anyhow::{anyhow, bail, Context, Result};
+use codec::Decode;
+use scale_info::form::PortableForm;
+use std::{
+    fs::File,
+    io::{Read, Write},
+};
+
+const CALLS_DOC_FILEPATH: &str = "docs/api/runtime-calls.md";
+
+type RuntimeCalls = Vec<Pallet>;
+
+enum CallCategory {
+    Disabled,
+    Inherent,
+    OtherOrigin,
+    Root,
+    Sudo,
+    User,
+}
+
+impl CallCategory {
+    fn is(pallet_name: &str, call_name: &str) -> Self {
+        match (pallet_name, call_name) {
+            ("System", "remark" | "remark_with_event") => Self::Disabled,
+            ("System", _) => Self::Root,
+            ("Babe", "report_equivocation_unsigned") => Self::Inherent,
+            ("Babe", "plan_config_change") => Self::Root,
+            ("Timestamp", _) => Self::Inherent,
+            ("Balances", "set_balance" | "force_transfer" | "force_unreserve") => Self::Root,
+            ("AuthorityMembers", "prune_account_id_of" | "remove_member") => Self::Root,
+            ("Authorship", _) => Self::Inherent,
+            ("Session", _) => Self::Disabled,
+            ("Grandpa", "report_equivocation_unsigned") => Self::Inherent,
+            ("Grandpa", "note_stalled") => Self::Root,
+            ("UpgradeOrigin", "dispatch_as_root") => Self::OtherOrigin,
+            ("ImOnline", _) => Self::Inherent,
+            ("Sudo", _) => Self::Sudo,
+            (
+                "Identity",
+                "remove_identity" | "prune_item_identities_names" | "prune_item_identity_index_of",
+            ) => Self::Root,
+            ("Membership", "force_request_membership") => Self::Root,
+            ("Membership", "claim_membership" | "revoke_membership") => Self::Disabled,
+            ("Cert", "force_add_cert" | "del_cert" | "remove_all_certs_received_by") => Self::Root,
+            ("SmithsMembership", "force_request_membership") => Self::Root,
+            ("SmithsMembership", "claim_membership") => Self::Disabled,
+            ("SmithsCert", "force_add_cert" | "del_cert" | "remove_all_certs_received_by") => {
+                Self::Root
+            }
+            ("SmithsCollective", "set_members" | "disapprove_proposal") => Self::Root,
+            ("Utility", "dispatch_as") => Self::Root,
+            _ => Self::User,
+        }
+    }
+    fn is_root(pallet_name: &str, call_name: &str) -> bool {
+        if let Self::Root = Self::is(pallet_name, call_name) {
+            true
+        } else {
+            false
+        }
+    }
+    fn is_user(pallet_name: &str, call_name: &str) -> bool {
+        if let Self::User = Self::is(pallet_name, call_name) {
+            true
+        } else {
+            false
+        }
+    }
+}
+
+#[derive(Clone)]
+struct Pallet {
+    index: u8,
+    name: String,
+    calls: Vec<Call>,
+}
+
+impl Pallet {
+    fn new(
+        index: u8,
+        name: String,
+        scale_type_def: &scale_info::TypeDef<PortableForm>,
+    ) -> Result<Self> {
+        if let scale_info::TypeDef::Variant(calls_enum) = scale_type_def {
+            Ok(Self {
+                index,
+                name,
+                calls: calls_enum.variants().iter().map(Into::into).collect(),
+            })
+        } else {
+            bail!("Invalid metadata")
+        }
+    }
+}
+
+#[derive(Clone)]
+struct Call {
+    docs: Vec<String>,
+    index: u8,
+    name: String,
+    params: Vec<CallParam>,
+}
+
+impl From<&scale_info::Variant<PortableForm>> for Call {
+    fn from(variant: &scale_info::Variant<PortableForm>) -> Self {
+        Self {
+            docs: variant.docs().to_vec(),
+            index: variant.index(),
+            name: variant.name().to_owned(),
+            params: variant.fields().iter().map(Into::into).collect(),
+        }
+    }
+}
+
+#[derive(Clone)]
+struct CallParam {
+    docs: Vec<String>,
+    name: String,
+    type_name: String,
+}
+
+impl From<&scale_info::Field<PortableForm>> for CallParam {
+    fn from(field: &scale_info::Field<PortableForm>) -> Self {
+        Self {
+            docs: field.docs().to_vec(),
+            name: field.name().cloned().unwrap_or_default(),
+            type_name: field.type_name().cloned().unwrap_or_default(),
+        }
+    }
+}
+
+pub(super) fn gen_calls_doc() -> Result<()> {
+    // Read metadata
+    let mut file = std::fs::File::open("resources/metadata.scale")
+        .with_context(|| "Failed to open metadata file")?;
+
+    let mut bytes = Vec::new();
+    file.read_to_end(&mut bytes)
+        .with_context(|| "Failed to read metadata file")?;
+
+    let metadata = frame_metadata::RuntimeMetadataPrefixed::decode(&mut &bytes[..])
+        .with_context(|| "Failed to decode metadata")?;
+
+    println!("Metadata successfully loaded!");
+
+    let runtime_calls = if let frame_metadata::RuntimeMetadata::V14(metadata_v14) = metadata.1 {
+        get_calls_from_metadata_v14(metadata_v14)?
+    } else {
+        bail!("unsuported metadata version")
+    };
+
+    let output = print_runtime_calls(runtime_calls);
+
+    let mut file = File::create(CALLS_DOC_FILEPATH)
+        .with_context(|| format!("Failed to create file '{}'", CALLS_DOC_FILEPATH))?;
+    file.write_all(output.as_bytes())
+        .with_context(|| format!("Failed to write to file '{}'", CALLS_DOC_FILEPATH))?;
+
+    Ok(())
+}
+
+fn get_calls_from_metadata_v14(
+    metadata_v14: frame_metadata::v14::RuntimeMetadataV14,
+) -> Result<RuntimeCalls> {
+    println!("Number of pallets: {}", metadata_v14.pallets.len());
+    let mut pallets = Vec::new();
+    for pallet in metadata_v14.pallets {
+        if let Some(calls) = pallet.calls {
+            if let Some(calls_type) = metadata_v14.types.resolve(calls.ty.id()) {
+                let pallet = Pallet::new(pallet.index, pallet.name.clone(), calls_type.type_def())?;
+                let calls_len = pallet.calls.len();
+                println!("{}: {} ({} calls)", pallet.index, pallet.name, calls_len);
+                pallets.push(pallet);
+            } else {
+                bail!("Invalid metadata")
+            }
+        } else {
+            println!("{}: {} (0 calls)", pallet.index, pallet.name);
+        }
+    }
+    Ok(pallets)
+}
+
+fn print_runtime_calls(pallets: RuntimeCalls) -> String {
+    let mut user_calls_counter = 0;
+    let user_calls_pallets: RuntimeCalls = pallets
+        .iter()
+        .cloned()
+        .filter_map(|mut pallet| {
+            let pallet_name = pallet.name.clone();
+            pallet
+                .calls
+                .retain(|call| CallCategory::is_user(&pallet_name, &call.name));
+            if pallet.calls.is_empty() {
+                None
+            } else {
+                user_calls_counter += pallet.calls.len();
+                Some(pallet)
+            }
+        })
+        .collect();
+    let mut root_calls_counter = 0;
+    let root_calls_pallets: RuntimeCalls = pallets
+        .iter()
+        .cloned()
+        .filter_map(|mut pallet| {
+            let pallet_name = pallet.name.clone();
+            pallet
+                .calls
+                .retain(|call| CallCategory::is_root(&pallet_name, &call.name));
+            if pallet.calls.is_empty() {
+                None
+            } else {
+                root_calls_counter += pallet.calls.len();
+                Some(pallet)
+            }
+        })
+        .collect();
+
+    let mut output = String::new();
+
+    output.push_str("# Runtime calls\n\n");
+    output.push_str("Calls are categorized according to the dispatch origin they require:\n\n");
+    output.push_str(
+        r#"1. User calls: the dispatch origin for this kind of call must be Signed by
+the transactor. This is the only call category that can be submitted with an extrinsic.
+"#,
+    );
+    output.push_str(
+        r#"1. Root calls: This kind of call requires a special origin that can only be invoked
+through on-chain governance mechanisms.
+"#,
+    );
+    output.push_str(
+        r#"1. Inherent calls: This kind of call is invoked by the author of the block itself
+(usually automatically by the node).
+"#,
+    );
+
+    output.push_str("\n\n## User calls\n\n");
+    output.push_str(&print_calls_category(
+        user_calls_counter,
+        "user",
+        user_calls_pallets,
+    ));
+
+    output.push_str("\n\n## Root calls\n\n");
+    output.push_str(&print_calls_category(
+        root_calls_counter,
+        "root",
+        root_calls_pallets,
+    ));
+
+    output
+}
+
+fn print_calls_category(calls_counter: usize, category_name: &str, pallets: Vec<Pallet>) -> String {
+    let mut output = String::new();
+    output.push_str(&format!(
+        "There are **{}** {} calls organized in **{}** pallets.\n",
+        calls_counter,
+        category_name,
+        pallets.len()
+    ));
+
+    for pallet in pallets {
+        output.push_str(&format!("\n### {}: {}\n\n", pallet.index, pallet.name));
+        for call in pallet.calls {
+            output.push_str(&format!(
+                "<details><summary>{}: {}({})</summary>\n<p>\n\n{}</p>\n</details>\n\n",
+                call.index,
+                call.name,
+                print_call_params(&call.params),
+                print_call_details(&call),
+            ));
+        }
+    }
+    output
+}
+
+fn print_call_details(call: &Call) -> String {
+    let mut output = String::new();
+    output.push_str(&format!("### Index\n\n`{}`\n\n", call.index));
+    output.push_str(&format!(
+        "### Documentation\n\n{}\n\n",
+        call.docs
+            .iter()
+            .take_while(|line| !line.starts_with("# <weight>"))
+            .cloned()
+            .collect::<Vec<_>>()
+            .join("\n")
+    ));
+    if !call.params.is_empty() {
+        output.push_str("### Types of parameters\n\n```rust\n");
+        output.push_str(
+            &call
+                .params
+                .iter()
+                .map(|param| format!("{}: {}", param.name, param.type_name))
+                .collect::<Vec<_>>()
+                .join(",\n"),
+        );
+        output.push_str("\n```\n\n");
+    }
+    output
+}
+
+fn print_call_params(call_params: &[CallParam]) -> String {
+    call_params
+        .iter()
+        .map(|param| param.name.clone())
+        .collect::<Vec<_>>()
+        .join(", ")
+}
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
new file mode 100644
index 0000000000000000000000000000000000000000..56a0573c35fc114385775cb5034818db604419fe
--- /dev/null
+++ b/xtask/src/main.rs
@@ -0,0 +1,93 @@
+// 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 gen_calls_doc;
+
+use anyhow::Result;
+use clap::Parser;
+use std::process::Command;
+
+const MIN_RUST_VERSION: &str = "1.58.0";
+
+#[derive(Debug, clap::Parser)]
+struct DuniterXTask {
+    #[clap(subcommand)]
+    command: DuniterXTaskCommand,
+}
+
+#[derive(Debug, clap::Subcommand)]
+enum DuniterXTaskCommand {
+    /// Build duniter binary
+    Build {
+        #[clap(long)]
+        production: bool,
+    },
+    /// Generate calls documentation
+    GenCallsDoc,
+    /// Execute unit tests and integration tests
+    /// End2tests are skipped
+    Test,
+}
+
+fn main() -> Result<()> {
+    let args = DuniterXTask::parse();
+
+    if !version_check::is_min_version(MIN_RUST_VERSION).unwrap_or(false)
+        && exec_should_success(Command::new("rustup").args(&["update", "stable"])).is_err()
+    {
+        eprintln!(
+                "Duniter requires stable Rust {} or higher. If you installed the Rust toolchain via rustup, please execute the command `rustup update stable`.",
+                MIN_RUST_VERSION
+            );
+        std::process::exit(1);
+    }
+    Command::new("rustc").arg("--version").status()?;
+    Command::new("cargo").arg("--version").status()?;
+
+    match args.command {
+        DuniterXTaskCommand::Build { production } => build(production),
+        DuniterXTaskCommand::GenCallsDoc => gen_calls_doc::gen_calls_doc(),
+        DuniterXTaskCommand::Test => test(),
+    }
+}
+
+fn build(production: bool) -> Result<()> {
+    exec_should_success(Command::new("cargo").args(&["clean", "-p", "duniter"]))?;
+    exec_should_success(Command::new("cargo").args(&["build", "--locked"]))?;
+    exec_should_success(Command::new("mkdir").args(&["build"]))?;
+    exec_should_success(Command::new("mv").args(&["target/debug/duniter", "build/duniter"]))?;
+
+    Ok(())
+}
+
+fn test() -> Result<()> {
+    exec_should_success(Command::new("cargo").args(&[
+        "test",
+        "--workspace",
+        "--exclude",
+        "duniter-end2end-tests",
+    ]))?;
+
+    Ok(())
+}
+
+fn exec_should_success(command: &mut Command) -> Result<()> {
+    if !command.status()?.success() {
+        std::process::exit(1);
+    } else {
+        Ok(())
+    }
+}