diff --git a/Cargo.lock b/Cargo.lock
index 478913025b1d09c674a27b537a0635d3ce5cffb2..1bf7ce434008f3f266662023ecb34cd6e0219b39 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -14,6 +14,11 @@ dependencies = [
  "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "arrayref"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "arrayvec"
 version = "0.4.7"
@@ -86,6 +91,20 @@ name = "bitflags"
 version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "block-buffer"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "byte-tools"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "byteorder"
 version = "1.2.3"
@@ -170,6 +189,14 @@ name = "difference"
 version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "digest"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "dirs"
 version = "1.0.2"
@@ -287,7 +314,8 @@ dependencies = [
  "duniter-crypto 0.2.0-a0.1",
  "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pest 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pest_derive 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.78 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -463,6 +491,11 @@ dependencies = [
  "synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "fake-simd"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "foreign-types"
 version = "0.3.2"
@@ -495,6 +528,14 @@ name = "gcc"
 version = "0.3.54"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "generic-array"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "httparse"
 version = "1.3.0"
@@ -580,6 +621,11 @@ dependencies = [
  "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "maplit"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "matches"
 version = "0.1.6"
@@ -703,6 +749,45 @@ name = "percent-encoding"
 version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "pest"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "ucd-trie 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "pest_derive"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "pest 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pest_generator 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "pest_generator"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "pest 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pest_meta 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "pest_meta"
+version = "2.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pest 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sha-1 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "pkg-config"
 version = "0.3.11"
@@ -900,6 +985,17 @@ dependencies = [
  "serde 1.0.78 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "sha-1"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "sha1"
 version = "0.6.0"
@@ -1067,6 +1163,16 @@ dependencies = [
  "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "typenum"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "ucd-trie"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "ucd-util"
 version = "0.1.1"
@@ -1198,6 +1304,7 @@ dependencies = [
 [metadata]
 "checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"
 "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
 "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
 "checksum atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1"
 "checksum backtrace 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dbdd17cd962b570302f5297aea8648d5923e22e555c2ed2d8b2e34eca646bf6d"
@@ -1207,6 +1314,8 @@ dependencies = [
 "checksum bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f2fb9e29e72fd6bc12071533d5dc7664cb01480c59406f656d7ac25c7bd8ff7"
 "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
 "checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789"
+"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab"
+"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
 "checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9"
 "checksum bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dd32989a66957d3f0cba6588f15d4281a733f4e9ffc43fcd2385f57d3bf99ff"
 "checksum cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "49ec142f5768efb5b7622aebc3fdbdbb8950a4b9ba996393cb76ef7466e8747d"
@@ -1217,16 +1326,19 @@ dependencies = [
 "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150"
 "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
 "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
+"checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90"
 "checksum dirs 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "37a76dd8b997af7107d0bb69d43903cf37153a18266f8b3fdb9911f28efb5444"
 "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
 "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
 "checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82"
 "checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b"
+"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
 "checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
 "checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
 "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
 "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
 "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
+"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
 "checksum httparse 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "422d5a93b40dbfbd8c8c24d1b4b5ef455973ef3afffc172487429fecd05bde42"
 "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d"
 "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
@@ -1239,6 +1351,7 @@ dependencies = [
 "checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e"
 "checksum log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6fddaa003a65722a7fb9e26b0ce95921fe4ba590542ced664d8ce2fa26f9f3ac"
 "checksum log-panics 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ae0136257df209261daa18d6c16394757c63e032e27aafd8b07788b051082bef"
+"checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43"
 "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
 "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
 "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
@@ -1253,6 +1366,10 @@ dependencies = [
 "checksum openssl-sys 0.9.33 (registry+https://github.com/rust-lang/crates.io-index)" = "d8abc04833dcedef24221a91852931df2f63e3369ae003134e70aff3645775cc"
 "checksum pbr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "deb73390ab68d81992bd994d145f697451bb0b54fd39738e72eef32458ad6907"
 "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
+"checksum pest 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a677051ad923732bb5c70f2d45f8985a96e3eee2e2bff86697e3b11b0c3fcfde"
+"checksum pest_derive 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b76f477146419bc539a63f4ef40e902166cb43b3e51cecc71d9136fd12c567e7"
+"checksum pest_generator 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ebee4e9680be4fd162e6f3394ae4192a6b60b1e4d17d845e631f0c68d1a3386"
+"checksum pest_meta 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1f6d5f6f0e6082578c86af197d780dc38328e3f768cec06aac9bc46d714e8221"
 "checksum pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "110d5ee3593dbb73f56294327fe5668bcc997897097cbc76b51e7aed3f52452f"
 "checksum pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a029430f0d744bc3d15dd474d591bed2402b645d024583082b9f63bb936dac6"
 "checksum proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "effdb53b25cdad54f8f48843d67398f7ef2e14f12c1b4cb4effc549a6462a4d6"
@@ -1277,6 +1394,7 @@ dependencies = [
 "checksum serde 1.0.78 (registry+https://github.com/rust-lang/crates.io-index)" = "92ec94e2754699adddbbc4f555791bd3acc2a2f5574cba16c93a4a9cf4a04415"
 "checksum serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "0a90213fa7e0f5eac3f7afe2d5ff6b088af515052cc7303bd68c7e3b91a3fb79"
 "checksum serde_json 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "eb40600c756f02d7ea34943626cefa85732fdae5f95b90b31f9797b3c526d1e6"
+"checksum sha-1 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9d1f3b5de8a167ab06834a7c883bd197f2191e1dda1a22d9ccfeedbf9aded"
 "checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
 "checksum simplelog 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9cc12b39fdf4c9a07f88bffac2d628f0118ed5ac077a4b0feece61fadf1429e5"
 "checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23"
@@ -1297,6 +1415,8 @@ dependencies = [
 "checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
 "checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865"
 "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b"
+"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
+"checksum ucd-trie 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "71a9c5b1fe77426cf144cc30e49e955270f5086e31a6441dfa8b32efc09b9d77"
 "checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d"
 "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
 "checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25"
diff --git a/blockchain/apply_valid_block.rs b/blockchain/apply_valid_block.rs
index 69e72f3059f5292d8f2c63110cde29a5bdaf6221..698ff0417a4ad647860439eca91948eac8989c8e 100644
--- a/blockchain/apply_valid_block.rs
+++ b/blockchain/apply_valid_block.rs
@@ -18,10 +18,10 @@ use duniter_dal::block::DALBlock;
 use duniter_dal::sources::SourceAmount;
 use duniter_dal::writers::requests::*;
 use duniter_dal::{BinDB, ForkId};
-use duniter_documents::blockchain::v10::documents::transaction::{TxAmount, TxBase};
-use duniter_documents::blockchain::v10::documents::BlockDocument;
-use duniter_documents::blockchain::Document;
+use duniter_documents::v10::transaction::{TxAmount, TxBase};
+use duniter_documents::v10::BlockDocument;
 use duniter_documents::BlockId;
+use duniter_documents::Document;
 use durs_wot::data::{NewLinkResult, RemLinkResult};
 use durs_wot::{NodeId, WebOfTrust};
 use std::collections::{HashMap, HashSet};
diff --git a/blockchain/check_and_apply_block.rs b/blockchain/check_and_apply_block.rs
index 3c601f47215dff775a375b3c7f6971d44d2ce3ee..8b5b7e35702f597ff6d1b38bca0431ed0bac1ce2 100644
--- a/blockchain/check_and_apply_block.rs
+++ b/blockchain/check_and_apply_block.rs
@@ -19,7 +19,7 @@ use apply_valid_block::*;
 use duniter_crypto::keys::*;
 use duniter_dal::block::DALBlock;
 use duniter_dal::*;
-use duniter_documents::blockchain::Document;
+use duniter_documents::Document;
 use duniter_documents::{BlockHash, BlockId, Blockstamp, PreviousBlockstamp};
 use duniter_network::NetworkBlock;
 use *;
diff --git a/blockchain/dbex.rs b/blockchain/dbex.rs
index 34ede624a757e188ef0d2042b296e38940ed4a7d..5e7736d92789903ff3c402bf059a1bccbe068ed9 100644
--- a/blockchain/dbex.rs
+++ b/blockchain/dbex.rs
@@ -15,7 +15,7 @@
 
 use duniter_crypto::keys::*;
 use duniter_dal::identity::DALIdentity;
-use duniter_documents::blockchain::v10::documents::transaction::*;
+use duniter_documents::v10::transaction::*;
 use duniter_module::DuniterConf;
 use durs_wot::data::rusty::RustyWebOfTrust;
 use durs_wot::operations::distance::{DistanceCalculator, WotDistance, WotDistanceParameters};
diff --git a/blockchain/lib.rs b/blockchain/lib.rs
index 50397e5f7a97d6a464997bdda5545b9092fe808c..02e0a4ff21752e222bcc32fe6154eb1583a348ac 100644
--- a/blockchain/lib.rs
+++ b/blockchain/lib.rs
@@ -70,9 +70,9 @@ use duniter_dal::dal_requests::{DALReqBlockchain, DALRequest, DALResBlockchain,
 use duniter_dal::identity::DALIdentity;
 use duniter_dal::writers::requests::BlocksDBsWriteQuery;
 use duniter_dal::*;
-use duniter_documents::blockchain::v10::documents::{BlockDocument, V10Document};
-use duniter_documents::blockchain::{BlockchainProtocol, Document};
+use duniter_documents::v10::{BlockDocument, V10Document};
 use duniter_documents::*;
+use duniter_documents::{BlockchainProtocol, Document};
 use duniter_message::*;
 use duniter_module::*;
 use duniter_network::{
diff --git a/blockchain/revert_block.rs b/blockchain/revert_block.rs
index 3ea7afc0bc654a0c3ea142a5fbb3766444dc4322..1492efb6ca0f1507e24a1071618775eb5e30bd1d 100644
--- a/blockchain/revert_block.rs
+++ b/blockchain/revert_block.rs
@@ -19,9 +19,9 @@ use duniter_dal::sources::SourceAmount;
 use duniter_dal::writers::requests::*;
 use duniter_dal::writers::transaction::DALTxV10;
 use duniter_dal::{BinDB, ForkId, TxV10Datas};
-use duniter_documents::blockchain::v10::documents::block::TxDocOrTxHash;
-use duniter_documents::blockchain::v10::documents::transaction::{TxAmount, TxBase};
-use duniter_documents::blockchain::Document;
+use duniter_documents::v10::block::TxDocOrTxHash;
+use duniter_documents::v10::transaction::{TxAmount, TxBase};
+use duniter_documents::Document;
 use durs_wot::data::{NewLinkResult, RemLinkResult};
 use durs_wot::{NodeId, WebOfTrust};
 use std::collections::HashMap;
diff --git a/blockchain/ts_parsers.rs b/blockchain/ts_parsers.rs
index e41c1f009fd4b4bed8e0155f957e8acf4d5706f4..26e32387f0561bcab5ae62c4824235ae824747a8 100644
--- a/blockchain/ts_parsers.rs
+++ b/blockchain/ts_parsers.rs
@@ -18,13 +18,13 @@ extern crate sqlite;
 
 use duniter_crypto::hashs::Hash;
 use duniter_crypto::keys::*;
-use duniter_documents::blockchain::v10::documents::block::{BlockV10Parameters, TxDocOrTxHash};
-use duniter_documents::blockchain::v10::documents::identity::IdentityDocumentBuilder;
-use duniter_documents::blockchain::v10::documents::membership::*;
-use duniter_documents::blockchain::v10::documents::transaction::*;
-use duniter_documents::blockchain::v10::documents::*;
-use duniter_documents::blockchain::DocumentBuilder;
+use duniter_documents::v10::block::{BlockV10Parameters, TxDocOrTxHash};
+use duniter_documents::v10::identity::*;
+use duniter_documents::v10::membership::*;
+use duniter_documents::v10::transaction::*;
+use duniter_documents::v10::*;
 use duniter_documents::CurrencyName;
+use duniter_documents::DocumentBuilder;
 use duniter_documents::{BlockHash, BlockId, Blockstamp};
 use duniter_network::{NetworkBlock, NetworkBlockV10};
 use std::str::FromStr;
@@ -329,7 +329,7 @@ pub fn parse_transaction(
     let mut inputs = Vec::with_capacity(inputs_array.len());
     for input in inputs_array {
         let input_str = input.as_str()?;
-        match TransactionInput::parse_from_str(input_str) {
+        match TransactionInput::from_str(input_str) {
             Ok(input) => inputs.push(input),
             Err(_) => {
                 return None;
@@ -339,7 +339,7 @@ pub fn parse_transaction(
     let unlocks_array = source.get("unlocks")?.as_array()?;
     let mut unlocks = Vec::with_capacity(unlocks_array.len());
     for unlock in unlocks_array {
-        match TransactionInputUnlocks::parse_from_str(unlock.as_str()?) {
+        match TransactionInputUnlocks::from_str(unlock.as_str()?) {
             Ok(unlock) => unlocks.push(unlock),
             Err(_) => {
                 return None;
@@ -350,7 +350,7 @@ pub fn parse_transaction(
     let mut outputs = Vec::with_capacity(outputs_array.len());
     for output in outputs_array {
         outputs.push(
-            TransactionOutput::parse_from_str(
+            TransactionOutput::from_str(
                 output
                     .as_str()
                     .unwrap_or_else(|| panic!("Fail to parse output : {:?}", output)),
diff --git a/dal/block.rs b/dal/block.rs
index 5a35d938ac91cfa05385839b3208c6acf3953228..2dc072dd9194460311d26988127d36c6cb55f13c 100644
--- a/dal/block.rs
+++ b/dal/block.rs
@@ -15,8 +15,8 @@
 
 use super::constants::MAX_FORKS;
 use duniter_crypto::keys::*;
-use duniter_documents::blockchain::v10::documents::BlockDocument;
-use duniter_documents::blockchain::Document;
+use duniter_documents::v10::BlockDocument;
+use duniter_documents::Document;
 use duniter_documents::{BlockHash, BlockId, Blockstamp, PreviousBlockstamp};
 use durs_wot::NodeId;
 use std::collections::HashMap;
diff --git a/dal/currency_params.rs b/dal/currency_params.rs
index e0ab8a0ce3d4474036c780b5660b5b8a01d7294e..5b902385b2b6b41658279da0027fd56bd8852784 100644
--- a/dal/currency_params.rs
+++ b/dal/currency_params.rs
@@ -14,7 +14,7 @@
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 use constants::*;
-use duniter_documents::blockchain::v10::documents::block::BlockV10Parameters;
+use duniter_documents::v10::block::BlockV10Parameters;
 use duniter_documents::CurrencyName;
 use *;
 
diff --git a/dal/dal_event.rs b/dal/dal_event.rs
index cdc27e5e97d70bfdd6ae6b275b49a78797409bd6..9a487dee7ff9337a133e88a79eba1e9d07376f9f 100644
--- a/dal/dal_event.rs
+++ b/dal/dal_event.rs
@@ -13,9 +13,8 @@
 // You should have received a copy of the GNU Affero General Public License
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-use duniter_documents::blockchain::v10::documents::BlockDocument;
-use duniter_documents::blockchain::BlockchainProtocol;
-use duniter_documents::Blockstamp;
+use duniter_documents::v10::block::BlockDocument;
+use duniter_documents::*;
 
 #[derive(Debug, Clone)]
 /// Event to be transmitted to the other modules
diff --git a/dal/dal_requests.rs b/dal/dal_requests.rs
index 52fc8383f1bacf147dad27372376629fd7d3951d..9a3a8604595602ffaea196588eb40540a28dcec7 100644
--- a/dal/dal_requests.rs
+++ b/dal/dal_requests.rs
@@ -19,9 +19,11 @@ extern crate serde;
 use self::duniter_module::ModuleReqId;
 use duniter_crypto::hashs::Hash;
 use duniter_crypto::keys::*;
-use duniter_documents::blockchain::v10::documents::{
-    BlockDocument, CertificationDocument, IdentityDocument, MembershipDocument, RevocationDocument,
-};
+use duniter_documents::v10::block::BlockDocument;
+use duniter_documents::v10::certification::CertificationDocument;
+use duniter_documents::v10::identity::IdentityDocument;
+use duniter_documents::v10::membership::MembershipDocument;
+use duniter_documents::v10::revocation::RevocationDocument;
 use duniter_documents::Blockstamp;
 use std::collections::HashMap;
 
diff --git a/dal/identity.rs b/dal/identity.rs
index 30d36b4e7b0ccd0392085948173f18d9210a25c9..86dad5ac355d5754bde64b7fd585a5e7dffc788a 100644
--- a/dal/identity.rs
+++ b/dal/identity.rs
@@ -15,7 +15,7 @@
 
 use currency_params::CurrencyParameters;
 use duniter_crypto::keys::*;
-use duniter_documents::blockchain::v10::documents::IdentityDocument;
+use duniter_documents::v10::identity::IdentityDocument;
 use duniter_documents::{BlockId, Blockstamp};
 use durs_wot::NodeId;
 use std::collections::HashMap;
diff --git a/dal/lib.rs b/dal/lib.rs
index b0181eb049e78eeb8e0a89378894edacc80286fb..07093a9a59880a41ba9e73f1f7e2628ca9d7fb17 100644
--- a/dal/lib.rs
+++ b/dal/lib.rs
@@ -81,8 +81,8 @@ pub mod writers;
 
 use duniter_crypto::hashs::Hash;
 use duniter_crypto::keys::*;
-use duniter_documents::blockchain::v10::documents::block::BlockV10Parameters;
-use duniter_documents::blockchain::v10::documents::transaction::*;
+use duniter_documents::v10::block::BlockV10Parameters;
+use duniter_documents::v10::transaction::*;
 use duniter_documents::CurrencyName;
 use duniter_documents::{BlockHash, BlockId, Blockstamp, PreviousBlockstamp};
 use durs_wot::{NodeId, WebOfTrust};
diff --git a/dal/parsers/certifications.rs b/dal/parsers/certifications.rs
index 675894f56f4e211e49d4902b98e6ed217d04545c..e575398682c7a32e5dea0efae6627a87d95b3016 100644
--- a/dal/parsers/certifications.rs
+++ b/dal/parsers/certifications.rs
@@ -17,8 +17,8 @@ extern crate serde;
 extern crate serde_json;
 
 use duniter_crypto::keys::*;
-use duniter_documents::blockchain::v10::documents::certification::CompactCertificationDocument;
-use duniter_documents::blockchain::v10::documents::{CertificationDocument, TextDocumentFormat};
+use duniter_documents::v10::certification::{CertificationDocument, CompactCertificationDocument};
+use duniter_documents::v10::TextDocumentFormat;
 use duniter_documents::BlockId;
 
 /// Parse array of certification json documents into vector of `CompactCertificationDocument`
diff --git a/dal/parsers/revoked.rs b/dal/parsers/revoked.rs
index 03779cdfc6cdd98e47f9407cd86bd549f6a1947a..2b22e996e14ccd8026a8eba8d66c9874de117cc3 100644
--- a/dal/parsers/revoked.rs
+++ b/dal/parsers/revoked.rs
@@ -16,8 +16,8 @@
 extern crate serde_json;
 
 use duniter_crypto::keys::*;
-use duniter_documents::blockchain::v10::documents::revocation::CompactRevocationDocument;
-use duniter_documents::blockchain::v10::documents::{RevocationDocument, TextDocumentFormat};
+use duniter_documents::v10::revocation::{CompactRevocationDocument, RevocationDocument};
+use duniter_documents::v10::TextDocumentFormat;
 
 /// Parse array of revocations json documents into vector of `CompactRevocationDocument`
 pub fn parse_revocations_into_compact(
diff --git a/dal/sources.rs b/dal/sources.rs
index 54a40a54ff021c8d698c78d05d9e3ec340e4c184..8d020059eb31a2927e15478f5c98c339640bd94d 100644
--- a/dal/sources.rs
+++ b/dal/sources.rs
@@ -18,7 +18,7 @@ extern crate duniter_documents;
 
 use duniter_crypto::hashs::Hash;
 use duniter_crypto::keys::PubKey;
-use duniter_documents::blockchain::v10::documents::transaction::*;
+use duniter_documents::v10::transaction::*;
 use duniter_documents::BlockId;
 use std::cmp::Ordering;
 use std::ops::{Add, Sub};
diff --git a/dal/writers/block.rs b/dal/writers/block.rs
index d447ad41666b55d09ebb301e736b9c21a422b59a..a716aa4473228376a676da7f86120fbb247549b3 100644
--- a/dal/writers/block.rs
+++ b/dal/writers/block.rs
@@ -14,7 +14,7 @@
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 use block::DALBlock;
-use duniter_documents::blockchain::Document;
+use duniter_documents::Document;
 use duniter_documents::{BlockHash, BlockId, PreviousBlockstamp};
 use std::collections::HashMap;
 use ForkId;
diff --git a/dal/writers/certification.rs b/dal/writers/certification.rs
index bb01dfd1a793267f7907515312a24944a98f3335..bb61ffe80b7ffd6c638ca3c9f66cd3c653f43ace 100644
--- a/dal/writers/certification.rs
+++ b/dal/writers/certification.rs
@@ -18,7 +18,7 @@ extern crate serde_json;
 
 use currency_params::CurrencyParameters;
 use duniter_crypto::keys::*;
-use duniter_documents::blockchain::v10::documents::certification::CompactCertificationDocument;
+use duniter_documents::v10::certification::CompactCertificationDocument;
 use duniter_documents::BlockId;
 use durs_wot::NodeId;
 use {BinDB, CertsExpirV10Datas, DALError, IdentitiesV10Datas};
diff --git a/dal/writers/dividend.rs b/dal/writers/dividend.rs
index 648240fbecc6b8c7d9b86a8a99efe78f3b87d9d3..4b2b97a283e93a2556dd025be4b112d3b42ebfa8 100644
--- a/dal/writers/dividend.rs
+++ b/dal/writers/dividend.rs
@@ -14,7 +14,7 @@
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 use duniter_crypto::keys::PubKey;
-use duniter_documents::blockchain::v10::documents::transaction::*;
+use duniter_documents::v10::transaction::*;
 use duniter_documents::BlockId;
 use sources::SourceAmount;
 use std::collections::{HashMap, HashSet};
diff --git a/dal/writers/identity.rs b/dal/writers/identity.rs
index 93f2bef0b3936c7c04803aa4ef9664504b4e815d..a491d0060d6446ca315993e16b522f93e2d85508 100644
--- a/dal/writers/identity.rs
+++ b/dal/writers/identity.rs
@@ -15,8 +15,8 @@
 
 use currency_params::CurrencyParameters;
 use duniter_crypto::keys::PubKey;
-use duniter_documents::blockchain::v10::documents::IdentityDocument;
-use duniter_documents::blockchain::Document;
+use duniter_documents::v10::identity::IdentityDocument;
+use duniter_documents::Document;
 use duniter_documents::{BlockId, Blockstamp};
 use durs_wot::NodeId;
 use identity::{DALIdentity, DALIdentityState};
diff --git a/dal/writers/requests.rs b/dal/writers/requests.rs
index 825a14af3f91f04f5359f3f0b0fc8783ff7d44bc..5e00a01d9076c33e5f2c7a6011a6a80b6485883b 100644
--- a/dal/writers/requests.rs
+++ b/dal/writers/requests.rs
@@ -19,8 +19,8 @@ extern crate serde_json;
 use block::DALBlock;
 use currency_params::CurrencyParameters;
 use duniter_crypto::keys::PubKey;
-use duniter_documents::blockchain::v10::documents::certification::CompactCertificationDocument;
-use duniter_documents::blockchain::v10::documents::identity::IdentityDocument;
+use duniter_documents::v10::certification::CompactCertificationDocument;
+use duniter_documents::v10::identity::IdentityDocument;
 use duniter_documents::Blockstamp;
 use durs_wot::NodeId;
 use identity::DALIdentity;
diff --git a/dal/writers/transaction.rs b/dal/writers/transaction.rs
index b0733ebe4ef73a29fd9aed9233e478ec3973dd6f..a7c23d1ff9d7881ff4ec7134b67ec9fa387101bb 100644
--- a/dal/writers/transaction.rs
+++ b/dal/writers/transaction.rs
@@ -13,7 +13,8 @@
 // You should have received a copy of the GNU Affero General Public License
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-use duniter_documents::blockchain::v10::documents::transaction::*;
+use duniter_documents::v10::transaction::*;
+
 use sources::{SourceAmount, SourceIndexV10, UTXOIndexV10, UTXOV10};
 use *;
 
@@ -413,7 +414,8 @@ pub fn apply_and_write_tx(
 #[cfg(test)]
 mod tests {
     use super::*;
-    use duniter_documents::blockchain::{Document, DocumentBuilder, VerificationResult};
+    use duniter_documents::{Document, DocumentBuilder, VerificationResult};
+    use std::str::FromStr;
 
     fn build_first_tx_of_g1() -> TransactionDocument {
         let pubkey = PubKey::Ed25519(
@@ -432,18 +434,19 @@ mod tests {
             blockstamp: &block,
             locktime: &0,
             issuers: &vec![pubkey],
-            inputs: &vec![TransactionInput::parse_from_str(
+            inputs: &vec![TransactionInput::from_str(
                 "1000:0:D:2ny7YAdmzReQxAayyJZsyVYwYhVyax2thKcGknmQy5nQ:1",
             )
             .expect("fail to parse input !")],
-            unlocks: &vec![TransactionInputUnlocks::parse_from_str("0:SIG(0)")
-                .expect("fail to parse unlock !")],
+            unlocks: &vec![
+                TransactionInputUnlocks::from_str("0:SIG(0)").expect("fail to parse unlock !")
+            ],
             outputs: &vec![
-                TransactionOutput::parse_from_str(
+                TransactionOutput::from_str(
                     "1:0:SIG(Com8rJukCozHZyFao6AheSsfDQdPApxQRnz7QYFf64mm)",
                 )
                 .expect("fail to parse output !"),
-                TransactionOutput::parse_from_str(
+                TransactionOutput::from_str(
                     "999:0:SIG(2ny7YAdmzReQxAayyJZsyVYwYhVyax2thKcGknmQy5nQ)",
                 )
                 .expect("fail to parse output !"),
diff --git a/documents/Cargo.toml b/documents/Cargo.toml
index 0f6fd6ff01c1ff0d37fab7097e9a8d19ec22358e..a0633f8044ce03868f2794803e7c5b179efa1641 100644
--- a/documents/Cargo.toml
+++ b/documents/Cargo.toml
@@ -9,7 +9,7 @@ keywords = ["duniter", "blockchain", "cryptocurrency", "document"]
 license = "AGPL-3.0"
 
 [lib]
-path = "lib.rs"
+path = "src/lib.rs"
 
 [dependencies]
 base58 = "0.1.*"
@@ -18,7 +18,8 @@ byteorder = "1.2.3"
 duniter-crypto = { path = "../crypto" }
 lazy_static = "1.0.*"
 linked-hash-map = "0.5.*"
-regex = "1.0.*"
+pest = "2.0"
+pest_derive = "2.0"
 rust-crypto = "0.2.*"
 serde = "1.0.*"
 serde_derive = "1.0.*"
diff --git a/documents/blockchain/v10/mod.rs b/documents/blockchain/v10/mod.rs
deleted file mode 100644
index 9b3d159d6d576877e01a5822ed3e720793bb3775..0000000000000000000000000000000000000000
--- a/documents/blockchain/v10/mod.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-//  Copyright (C) 2018  The Duniter Project Developers.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as
-// published by the Free Software Foundation, either version 3 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-//! Provide wrappers around Duniter V10 documents and events.
-
-pub mod documents;
diff --git a/documents/lib.rs b/documents/lib.rs
deleted file mode 100644
index 04f20fac89bd112f3273fd01787a3d5ac0923b98..0000000000000000000000000000000000000000
--- a/documents/lib.rs
+++ /dev/null
@@ -1,271 +0,0 @@
-//  Copyright (C) 2018  The Duniter Project Developers.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as
-// published by the Free Software Foundation, either version 3 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-//! Implements the Duniter Documents Protocol.
-
-#![cfg_attr(feature = "strict", deny(warnings))]
-#![deny(
-    missing_docs,
-    missing_debug_implementations,
-    missing_copy_implementations,
-    trivial_casts,
-    trivial_numeric_casts,
-    unsafe_code,
-    unstable_features,
-    unused_import_braces,
-    unused_qualifications
-)]
-
-#[macro_use]
-extern crate lazy_static;
-#[macro_use]
-extern crate serde_derive;
-
-extern crate base58;
-extern crate base64;
-extern crate byteorder;
-extern crate crypto;
-extern crate duniter_crypto;
-extern crate linked_hash_map;
-extern crate regex;
-extern crate serde;
-
-use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
-use currencies_codes::*;
-use duniter_crypto::hashs::Hash;
-use std::cmp::Ordering;
-use std::fmt::{Debug, Display, Error, Formatter};
-use std::io::Cursor;
-use std::mem;
-
-pub mod blockchain;
-mod currencies_codes;
-
-/// Currency name
-#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, Hash)]
-pub struct CurrencyName(pub String);
-
-impl Default for CurrencyName {
-    fn default() -> CurrencyName {
-        CurrencyName(String::from("default_currency"))
-    }
-}
-
-impl Display for CurrencyName {
-    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
-        write!(f, "{}", self.0)
-    }
-}
-
-/// CurrencyCodeError
-#[derive(Debug)]
-pub enum CurrencyCodeError {
-    /// UnknowCurrencyCode
-    UnknowCurrencyCode(),
-    /// IoError
-    IoError(::std::io::Error),
-    /// UnknowCurrencyName
-    UnknowCurrencyName(),
-}
-
-impl From<::std::io::Error> for CurrencyCodeError {
-    fn from(error: ::std::io::Error) -> Self {
-        CurrencyCodeError::IoError(error)
-    }
-}
-
-impl CurrencyName {
-    /// Convert bytes to CurrencyName
-    pub fn from(currency_code: [u8; 2]) -> Result<Self, CurrencyCodeError> {
-        let mut currency_code_bytes = Cursor::new(currency_code.to_vec());
-        let currency_code = currency_code_bytes.read_u16::<BigEndian>()?;
-        Self::from_u16(currency_code)
-    }
-    /// Convert u16 to CurrencyName
-    pub fn from_u16(currency_code: u16) -> Result<Self, CurrencyCodeError> {
-        match currency_code {
-            tmp if tmp == *CURRENCY_NULL => Ok(CurrencyName(String::from(""))),
-            tmp if tmp == *CURRENCY_G1 => Ok(CurrencyName(String::from("g1"))),
-            tmp if tmp == *CURRENCY_G1_TEST => Ok(CurrencyName(String::from("g1-test"))),
-            _ => Err(CurrencyCodeError::UnknowCurrencyCode()),
-        }
-    }
-    /// Convert CurrencyName to bytes
-    pub fn to_bytes(&self) -> Result<[u8; 2], CurrencyCodeError> {
-        let currency_code = match self.0.as_str() {
-            "g1" => *CURRENCY_G1,
-            "g1-test" => *CURRENCY_G1_TEST,
-            _ => return Err(CurrencyCodeError::UnknowCurrencyName()),
-        };
-        let mut buffer = [0u8; mem::size_of::<u16>()];
-        buffer
-            .as_mut()
-            .write_u16::<BigEndian>(currency_code)
-            .expect("Unable to write");
-        Ok(buffer)
-    }
-}
-
-/// A block Id.
-#[derive(Copy, Clone, Debug, Deserialize, Ord, PartialEq, PartialOrd, Eq, Hash, Serialize)]
-pub struct BlockId(pub u32);
-
-impl Display for BlockId {
-    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
-        write!(f, "{}", self.0)
-    }
-}
-
-/// Wrapper of a block hash.
-#[derive(Copy, Clone, Default, Deserialize, Eq, Ord, PartialEq, PartialOrd, Hash, Serialize)]
-pub struct BlockHash(pub Hash);
-
-impl Display for BlockHash {
-    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
-        write!(f, "{}", self.0.to_hex())
-    }
-}
-
-impl Debug for BlockHash {
-    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
-        write!(f, "BlockHash({})", self)
-    }
-}
-
-/// Type of errors for [`BlockUId`] parsing.
-///
-/// [`BlockUId`]: struct.BlockUId.html
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum BlockUIdParseError {
-    /// Given string have invalid format
-    InvalidFormat(),
-    /// [`BlockId`](struct.BlockHash.html) part is not a valid number.
-    InvalidBlockId(),
-    /// [`BlockHash`](struct.BlockHash.html) part is not a valid hex number.
-    InvalidBlockHash(),
-}
-
-/// A blockstamp (Unique ID).
-///
-/// It's composed of the [`BlockId`] and
-/// the [`BlockHash`] of the block.
-///
-/// Thanks to blockchain immutability and frequent block production, it can
-/// be used to date information.
-///
-/// [`BlockId`]: struct.BlockId.html
-/// [`BlockHash`]: struct.BlockHash.html
-
-#[derive(Copy, Clone, Deserialize, PartialEq, Eq, Hash, Serialize)]
-pub struct Blockstamp {
-    /// Block Id.
-    pub id: BlockId,
-    /// Block hash.
-    pub hash: BlockHash,
-}
-
-/// Previous blockstamp (BlockId-1, previous_hash)
-pub type PreviousBlockstamp = Blockstamp;
-
-impl Blockstamp {
-    /// Blockstamp size (in bytes).
-    pub const SIZE_IN_BYTES: usize = 36;
-}
-
-impl Display for Blockstamp {
-    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
-        write!(f, "{}-{}", self.id, self.hash)
-    }
-}
-
-impl Debug for Blockstamp {
-    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
-        write!(f, "BlockUId({})", self)
-    }
-}
-
-impl Default for Blockstamp {
-    fn default() -> Blockstamp {
-        Blockstamp {
-            id: BlockId(0),
-            hash: BlockHash(Hash::default()),
-        }
-    }
-}
-
-impl PartialOrd for Blockstamp {
-    fn partial_cmp(&self, other: &Blockstamp) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-impl Ord for Blockstamp {
-    fn cmp(&self, other: &Blockstamp) -> Ordering {
-        if self.id == other.id {
-            self.hash.cmp(&other.hash)
-        } else {
-            self.id.cmp(&other.id)
-        }
-    }
-}
-
-#[derive(Debug)]
-/// Error when converting a byte vector to Blockstamp
-pub enum ReadBytesBlockstampError {
-    /// Bytes vector is too short
-    TooShort(),
-    /// Bytes vector is too long
-    TooLong(),
-    /// IoError
-    IoError(::std::io::Error),
-}
-
-impl From<::std::io::Error> for ReadBytesBlockstampError {
-    fn from(e: ::std::io::Error) -> Self {
-        ReadBytesBlockstampError::IoError(e)
-    }
-}
-
-impl Blockstamp {
-    /// Create a `BlockUId` from a text.
-    pub fn from_string(src: &str) -> Result<Blockstamp, BlockUIdParseError> {
-        let mut split = src.split('-');
-
-        if split.clone().count() != 2 {
-            Err(BlockUIdParseError::InvalidFormat())
-        } else {
-            let id = split.next().unwrap().parse::<u32>();
-            let hash = Hash::from_hex(split.next().unwrap());
-
-            if id.is_err() {
-                Err(BlockUIdParseError::InvalidBlockId())
-            } else if hash.is_err() {
-                Err(BlockUIdParseError::InvalidBlockHash())
-            } else {
-                Ok(Blockstamp {
-                    id: BlockId(id.unwrap()),
-                    hash: BlockHash(
-                        hash.expect("Try to get hash of an uncompleted or reduce block !"),
-                    ),
-                })
-            }
-        }
-    }
-
-    /// Convert a `BlockUId` to its text format.
-    pub fn to_string(&self) -> String {
-        format!("{}", self)
-    }
-}
diff --git a/documents/src/blockstamp.rs b/documents/src/blockstamp.rs
new file mode 100644
index 0000000000000000000000000000000000000000..a81d70af7bfbfd866fb3ebdc81ef9cf86fc65fd5
--- /dev/null
+++ b/documents/src/blockstamp.rs
@@ -0,0 +1,144 @@
+//  Copyright (C) 2018  The Duniter Project Developers.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+//! Wrapper for blockstamp
+
+use *;
+
+/// Type of errors for [`BlockUId`] parsing.
+///
+/// [`BlockUId`]: struct.BlockUId.html
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum BlockstampParseError {
+    /// Given string have invalid format
+    InvalidFormat(),
+    /// [`BlockId`](struct.BlockHash.html) part is not a valid number.
+    InvalidBlockId(),
+    /// [`BlockHash`](struct.BlockHash.html) part is not a valid hex number.
+    InvalidBlockHash(),
+}
+
+/// A blockstamp (Unique ID).
+///
+/// It's composed of the [`BlockId`] and
+/// the [`BlockHash`] of the block.
+///
+/// Thanks to blockchain immutability and frequent block production, it can
+/// be used to date information.
+///
+/// [`BlockId`]: struct.BlockId.html
+/// [`BlockHash`]: struct.BlockHash.html
+
+#[derive(Copy, Clone, Deserialize, PartialEq, Eq, Hash, Serialize)]
+pub struct Blockstamp {
+    /// Block Id.
+    pub id: BlockId,
+    /// Block hash.
+    pub hash: BlockHash,
+}
+
+/// Previous blockstamp (BlockId-1, previous_hash)
+pub type PreviousBlockstamp = Blockstamp;
+
+impl Blockstamp {
+    /// Blockstamp size (in bytes).
+    pub const SIZE_IN_BYTES: usize = 36;
+}
+
+impl Display for Blockstamp {
+    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
+        write!(f, "{}-{}", self.id, self.hash)
+    }
+}
+
+impl Debug for Blockstamp {
+    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
+        write!(f, "BlockUId({})", self)
+    }
+}
+
+impl Default for Blockstamp {
+    fn default() -> Blockstamp {
+        Blockstamp {
+            id: BlockId(0),
+            hash: BlockHash(Hash::default()),
+        }
+    }
+}
+
+impl PartialOrd for Blockstamp {
+    fn partial_cmp(&self, other: &Blockstamp) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Ord for Blockstamp {
+    fn cmp(&self, other: &Blockstamp) -> Ordering {
+        if self.id == other.id {
+            self.hash.cmp(&other.hash)
+        } else {
+            self.id.cmp(&other.id)
+        }
+    }
+}
+
+#[derive(Debug)]
+/// Error when converting a byte vector to Blockstamp
+pub enum ReadBytesBlockstampError {
+    /// Bytes vector is too short
+    TooShort(),
+    /// Bytes vector is too long
+    TooLong(),
+    /// IoError
+    IoError(::std::io::Error),
+}
+
+impl From<::std::io::Error> for ReadBytesBlockstampError {
+    fn from(e: ::std::io::Error) -> Self {
+        ReadBytesBlockstampError::IoError(e)
+    }
+}
+
+impl Blockstamp {
+    /// Create a `BlockUId` from a text.
+    pub fn from_string(src: &str) -> Result<Blockstamp, BlockstampParseError> {
+        let mut split = src.split('-');
+
+        if split.clone().count() != 2 {
+            Err(BlockstampParseError::InvalidFormat())
+        } else {
+            let id = split.next().unwrap().parse::<u32>();
+            let hash = Hash::from_hex(split.next().unwrap());
+
+            if id.is_err() {
+                Err(BlockstampParseError::InvalidBlockId())
+            } else if hash.is_err() {
+                Err(BlockstampParseError::InvalidBlockHash())
+            } else {
+                Ok(Blockstamp {
+                    id: BlockId(id.unwrap()),
+                    hash: BlockHash(
+                        hash.expect("Try to get hash of an uncompleted or reduce block !"),
+                    ),
+                })
+            }
+        }
+    }
+
+    /// Convert a `BlockUId` to its text format.
+    pub fn to_string(&self) -> String {
+        format!("{}", self)
+    }
+}
diff --git a/documents/currencies_codes.rs b/documents/src/currencies_codes.rs
similarity index 100%
rename from documents/currencies_codes.rs
rename to documents/src/currencies_codes.rs
diff --git a/documents/src/documents_grammar.pest b/documents/src/documents_grammar.pest
new file mode 100644
index 0000000000000000000000000000000000000000..cc509f5f63eb02674d7660f57081eff17e5b8dd4
--- /dev/null
+++ b/documents/src/documents_grammar.pest
@@ -0,0 +1,162 @@
+nl = _{ "\n" }
+hexa = { ASCII_DIGIT | 'A'..'F' }
+base58 = { !("O" | "I" | "l") ~ ASCII_ALPHANUMERIC }
+base64 = { ASCII_ALPHANUMERIC | "+" | "/" }
+
+integer = @{ "0" | ('1'..'9' ~ ASCII_DIGIT*) }
+hash = @{ hexa{64} }
+
+currency = @{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "-" | "_")* }
+pubkey = @{ base58{43,44} }
+uid = @{ ASCII_ALPHA+ }
+block_id = @{ integer }
+blockstamp =  ${ block_id ~ "-" ~ hash }
+ed25519_sig = @{ base64{86,88} ~ "="{0,2} }
+
+v10 = _{ "Version: 10" }
+
+idty_v10 = ${
+    v10 ~ nl ~
+    "Type: Identity" ~ nl ~
+    "Currency: " ~ currency ~ nl ~
+    "Issuer: " ~ pubkey ~ nl ~
+    "UniqueID: " ~ uid ~ nl ~
+    "Timestamp: " ~ blockstamp ~ nl ~
+    ed25519_sig? ~ nl*
+}
+
+idty = ${
+    SOI ~
+    (&(v10 ~ nl) ~ idty_v10)
+    ~ EOI
+}
+
+membership_in = @{ "IN" }
+membership_out = @{ "OUT" }
+
+membership_v10 = ${
+    v10 ~ nl ~
+    "Type: Membership" ~ nl ~
+    "Currency: " ~ currency ~ nl ~
+    "Issuer: " ~ pubkey ~ nl ~
+    "Block: " ~ blockstamp ~ nl ~
+    "Membership: " ~ (membership_in | membership_out) ~ nl ~
+    "UserID: " ~ uid ~ nl ~
+    "CertTS: " ~ blockstamp ~ nl ~
+    ed25519_sig? ~ nl*
+}
+
+membership = ${
+    SOI ~
+    (&("Version: 10" ~ nl) ~ membership_v10)
+    ~ EOI
+}
+
+cert_v10 = ${
+    v10 ~ nl ~
+    "Type: Certification" ~ nl ~
+    "Currency: " ~ currency ~ nl ~
+    "Issuer: " ~ pubkey ~ nl ~
+    "IdtyIssuer: " ~ pubkey ~ nl ~
+    "IdtyUniqueID: " ~ uid ~ nl ~
+    "IdtyTimestamp: " ~ blockstamp ~ nl ~
+    "IdtySignature: " ~ ed25519_sig ~ nl ~
+    "CertTimestamp: " ~ blockstamp ~ nl ~
+    ed25519_sig? ~ nl*
+}
+
+cert = ${
+    SOI ~
+    (&("Version: 10" ~ nl) ~ cert_v10)
+    ~ EOI
+}
+
+revoc_v10 = ${
+    v10 ~ nl ~
+    "Type: Revocation" ~ nl ~
+    "Currency: " ~ currency ~ nl ~
+    "Issuer: " ~ pubkey ~ nl ~
+    "IdtyUniqueID: " ~ uid ~ nl ~
+    "IdtyTimestamp: " ~ blockstamp ~ nl ~
+    "IdtySignature: " ~ ed25519_sig ~ nl ~
+    ed25519_sig? ~ nl*
+}
+
+revoc = ${
+    SOI ~
+    (&("Version: 10" ~ nl) ~ revoc_v10)
+    ~ EOI
+}
+
+tx_locktime = @{ integer }
+tx_amount =  @{ integer }
+tx_amount_base =  @{ integer }
+du_block_id = @{ integer }
+tx_index =  @{ integer }
+input_index = @{ integer }
+issuer_index = @{ integer }
+xhx_secret = @ { ASCII_ALPHANUMERIC+ }
+csv_duration = @{ integer }
+cltv_timestamp = @{ integer }
+
+tx_input = ${ tx_input_du | tx_input_tx }
+tx_input_du = ${ tx_amount ~ ":" ~ tx_amount_base ~ ":D:" ~ pubkey ~ ":" ~ du_block_id }
+tx_input_tx = ${ tx_amount ~ ":" ~ tx_amount_base ~ ":T:" ~ hash ~ ":" ~ tx_index }
+
+tx_unlock = ${ input_index ~ ":" ~ unlock_cond ~ (" " ~ unlock_cond)* }
+unlock_cond = _{ unlock_sig | unlock_xhx }
+unlock_sig = ${ "SIG(" ~ issuer_index ~ ")" }
+unlock_xhx = ${ "XHX(" ~ xhx_secret ~ ")" }
+
+tx_output = ${ tx_amount ~ ":" ~ tx_amount_base ~ ":" ~ output_conds_group }
+output_conds_group = _{ output_and_group | output_or_group | output_single_cond }
+output_and_group = ${ "(" ~ output_conds_group ~ (" && " ~ output_conds_group)+ ~ ")" }
+output_or_group = ${ "(" ~ output_conds_group ~ (" || " ~ output_conds_group)+ ~ ")" }
+output_single_cond = _{ output_cond_sig | output_cond_xhx | output_cond_csv | output_cond_cltv }
+output_cond_sig = ${ "SIG(" ~ pubkey ~ ")"? }
+output_cond_xhx = ${ "XHX(" ~ hash ~ ")"? }
+output_cond_csv = ${ "CSV(" ~ csv_duration ~ ")"? }
+output_cond_cltv = ${ "CLTV(" ~ cltv_timestamp ~ ")"? }
+
+tx_comment_char = {
+    ASCII_ALPHANUMERIC | "\\" | ":" | "/" | ";" | "*" | "[" | "]" | "(" | ")" | "?" | "!" | "^" 
+    | "+" | "=" | "@" | "&" | "~" | "#" | "{" | "}" | "|" | "<" | ">" | "%" | "." | " " | "-" 
+}
+tx_comment = @{ tx_comment_char{0,255} }
+
+tx_v10 = ${
+    "Version: 10" ~ nl ~
+    "Type: Transaction" ~ nl ~
+    "Currency: " ~ currency ~ nl ~
+    "Blockstamp: " ~ blockstamp ~ nl ~
+    "Locktime: " ~ tx_locktime ~ nl ~
+    "Issuers:" ~ nl ~ (pubkey ~ nl)+ ~
+    "Inputs:" ~ nl ~ (tx_input ~ nl)+ ~
+    "Unlocks:" ~ nl ~ (tx_unlock ~ nl)+ ~
+    "Outputs:" ~ nl ~ (tx_output ~ nl)+ ~
+    "Comment: " ~ tx_comment ~ nl ~
+    (ed25519_sig ~ nl)* ~ // intermediate signatures (zero if the transaction has only one signature)
+    ed25519_sig? ~ nl* // last signature
+}
+
+tx = ${
+    SOI ~
+    (&("Version: 10" ~ nl) ~ tx_v10)
+    ~ EOI
+}
+
+document_v10 = ${
+    SOI ~
+    (&"Type: Identity" ~ idty_v10) | 
+    (&"Type: Membership" ~ membership_v10) | 
+    (&"Type: Certification" ~ cert_v10) | 
+    (&"Type: Revocation" ~ revoc_v10) |
+    (&"Type: Transaction" ~ tx_v10)
+    ~ EOI
+}
+
+document = ${
+    SOI ~
+    (&("Version: 10" ~ nl) ~ document_v10)
+    ~ EOI
+}
diff --git a/documents/blockchain/mod.rs b/documents/src/lib.rs
similarity index 54%
rename from documents/blockchain/mod.rs
rename to documents/src/lib.rs
index 64edf826a48de9a18793acf829dde9dd8735e0bd..9ee020c3aa4625c09ee271f26064f3c97f3f53b2 100644
--- a/documents/blockchain/mod.rs
+++ b/documents/src/lib.rs
@@ -13,25 +13,152 @@
 // You should have received a copy of the GNU Affero General Public License
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-//! Provide wrappers around Duniter documents and events.
-
-use std::fmt::Debug;
+//! Implements the Duniter Documents Protocol.
+
+#![cfg_attr(feature = "strict", deny(warnings))]
+#![deny(
+    missing_debug_implementations,
+    missing_copy_implementations,
+    trivial_casts,
+    trivial_numeric_casts,
+    unsafe_code,
+    unstable_features,
+    unused_import_braces
+)]
+
+extern crate base58;
+extern crate base64;
+extern crate byteorder;
+extern crate crypto;
+extern crate duniter_crypto;
+extern crate linked_hash_map;
+extern crate pest;
+#[macro_use]
+extern crate pest_derive;
+extern crate serde;
+#[macro_use]
+extern crate serde_derive;
+
+pub mod blockstamp;
+mod currencies_codes;
+pub mod v10;
 
-use duniter_crypto::keys::{PrivateKey, PublicKey};
+use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
+use currencies_codes::*;
+use duniter_crypto::hashs::Hash;
+use duniter_crypto::keys::*;
+use std::cmp::Ordering;
+use std::fmt::{Debug, Display, Error, Formatter};
+use std::io::Cursor;
+use std::mem;
 
-use super::Blockstamp;
+pub use blockstamp::{Blockstamp, PreviousBlockstamp};
 
-pub mod v10;
+#[derive(Parser)]
+#[grammar = "documents_grammar.pest"]
+/// Parser for Documents
+struct DocumentsParser;
 
 /// List of blockchain protocol versions.
 #[derive(Debug, Clone)]
 pub enum BlockchainProtocol {
     /// Version 10.
-    V10(Box<v10::documents::V10Document>),
+    V10(Box<v10::V10Document>),
     /// Version 11. (not done yet, but defined for tests)
     V11(),
 }
 
+/// Currency name
+#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, Hash)]
+pub struct CurrencyName(pub String);
+
+impl Default for CurrencyName {
+    fn default() -> CurrencyName {
+        CurrencyName(String::from("default_currency"))
+    }
+}
+
+impl Display for CurrencyName {
+    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
+        write!(f, "{}", self.0)
+    }
+}
+
+/// CurrencyCodeError
+#[derive(Debug)]
+pub enum CurrencyCodeError {
+    /// UnknowCurrencyCode
+    UnknowCurrencyCode(),
+    /// IoError
+    IoError(::std::io::Error),
+    /// UnknowCurrencyName
+    UnknowCurrencyName(),
+}
+
+impl From<::std::io::Error> for CurrencyCodeError {
+    fn from(error: ::std::io::Error) -> Self {
+        CurrencyCodeError::IoError(error)
+    }
+}
+
+impl CurrencyName {
+    /// Convert bytes to CurrencyName
+    pub fn from(currency_code: [u8; 2]) -> Result<Self, CurrencyCodeError> {
+        let mut currency_code_bytes = Cursor::new(currency_code.to_vec());
+        let currency_code = currency_code_bytes.read_u16::<BigEndian>()?;
+        Self::from_u16(currency_code)
+    }
+    /// Convert u16 to CurrencyName
+    pub fn from_u16(currency_code: u16) -> Result<Self, CurrencyCodeError> {
+        match currency_code {
+            tmp if tmp == *CURRENCY_NULL => Ok(CurrencyName(String::from(""))),
+            tmp if tmp == *CURRENCY_G1 => Ok(CurrencyName(String::from("g1"))),
+            tmp if tmp == *CURRENCY_G1_TEST => Ok(CurrencyName(String::from("g1-test"))),
+            _ => Err(CurrencyCodeError::UnknowCurrencyCode()),
+        }
+    }
+    /// Convert CurrencyName to bytes
+    pub fn to_bytes(&self) -> Result<[u8; 2], CurrencyCodeError> {
+        let currency_code = match self.0.as_str() {
+            "g1" => *CURRENCY_G1,
+            "g1-test" => *CURRENCY_G1_TEST,
+            _ => return Err(CurrencyCodeError::UnknowCurrencyName()),
+        };
+        let mut buffer = [0u8; mem::size_of::<u16>()];
+        buffer
+            .as_mut()
+            .write_u16::<BigEndian>(currency_code)
+            .expect("Unable to write");
+        Ok(buffer)
+    }
+}
+
+/// A block Id.
+#[derive(Copy, Clone, Debug, Deserialize, Ord, PartialEq, PartialOrd, Eq, Hash, Serialize)]
+pub struct BlockId(pub u32);
+
+impl Display for BlockId {
+    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
+        write!(f, "{}", self.0)
+    }
+}
+
+/// Wrapper of a block hash.
+#[derive(Copy, Clone, Default, Deserialize, Eq, Ord, PartialEq, PartialOrd, Hash, Serialize)]
+pub struct BlockHash(pub Hash);
+
+impl Display for BlockHash {
+    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
+        write!(f, "{}", self.0.to_hex())
+    }
+}
+
+impl Debug for BlockHash {
+    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
+        write!(f, "BlockHash({})", self)
+    }
+}
+
 /// trait providing commun methods for any documents of any protocol version.
 ///
 /// # Design choice
@@ -139,134 +266,3 @@ pub trait DocumentParser<S, D, E> {
     /// Parse a source and return a document or an error.
     fn parse(source: S) -> Result<D, E>;
 }
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use duniter_crypto::keys::*;
-
-    // simple text document for signature testing
-    #[derive(Debug, Clone)]
-    struct PlainTextDocument {
-        pub text: &'static str,
-        pub issuers: Vec<PubKey>,
-        pub signatures: Vec<Sig>,
-    }
-
-    impl Document for PlainTextDocument {
-        type PublicKey = PubKey;
-        type CurrencyType = str;
-
-        fn version(&self) -> u16 {
-            unimplemented!()
-        }
-
-        fn currency(&self) -> &str {
-            unimplemented!()
-        }
-
-        fn blockstamp(&self) -> Blockstamp {
-            unimplemented!()
-        }
-
-        fn issuers(&self) -> &Vec<PubKey> {
-            &self.issuers
-        }
-
-        fn signatures(&self) -> &Vec<Sig> {
-            &self.signatures
-        }
-
-        fn as_bytes(&self) -> &[u8] {
-            self.text.as_bytes()
-        }
-    }
-
-    #[test]
-    fn verify_signatures() {
-        let text = "Version: 10
-Type: Identity
-Currency: duniter_unit_test_currency
-Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV
-UniqueID: tic
-Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
-";
-
-        // good pair
-        let issuer1 = PubKey::Ed25519(
-            ed25519::PublicKey::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV")
-                .unwrap(),
-        );
-
-        let sig1 = Sig::Ed25519(
-            ed25519::Signature::from_base64(
-                "1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGMM\
-                 mQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==",
-            )
-            .unwrap(),
-        );
-
-        // incorrect pair
-        let issuer2 = PubKey::Ed25519(
-            ed25519::PublicKey::from_base58("DNann1Lh55eZMEDXeYt32bzHbA3NJR46DeQYCS2qQdLV")
-                .unwrap(),
-        );
-
-        let sig2 = Sig::Ed25519(
-            ed25519::Signature::from_base64(
-                "1eubHHbuNfilHHH0G2bI30iZzebQ2cQ1PC7uPAw08FGMM\
-                 mQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==",
-            )
-            .unwrap(),
-        );
-
-        {
-            let doc = PlainTextDocument {
-                text,
-                issuers: vec![issuer1],
-                signatures: vec![sig1],
-            };
-
-            assert_eq!(doc.verify_signatures(), VerificationResult::Valid());
-        }
-
-        {
-            let doc = PlainTextDocument {
-                text,
-                issuers: vec![issuer1],
-                signatures: vec![sig2],
-            };
-
-            assert_eq!(
-                doc.verify_signatures(),
-                VerificationResult::Invalid(vec![0])
-            );
-        }
-
-        {
-            let doc = PlainTextDocument {
-                text,
-                issuers: vec![issuer1, issuer2],
-                signatures: vec![sig1],
-            };
-
-            assert_eq!(
-                doc.verify_signatures(),
-                VerificationResult::IncompletePairs(2, 1)
-            );
-        }
-
-        {
-            let doc = PlainTextDocument {
-                text,
-                issuers: vec![issuer1],
-                signatures: vec![sig1, sig2],
-            };
-
-            assert_eq!(
-                doc.verify_signatures(),
-                VerificationResult::IncompletePairs(1, 2)
-            );
-        }
-    }
-}
diff --git a/documents/blockchain/v10/documents/block.rs b/documents/src/v10/block.rs
similarity index 96%
rename from documents/blockchain/v10/documents/block.rs
rename to documents/src/v10/block.rs
index 72db06e6797dbf0ae367f04569200456de257148..b03e00f2d642692d654842d49335439292f0ac28 100644
--- a/documents/blockchain/v10/documents/block.rs
+++ b/documents/src/v10/block.rs
@@ -19,17 +19,16 @@ use crypto::digest::Digest;
 use crypto::sha2::Sha256;
 use duniter_crypto::hashs::Hash;
 use duniter_crypto::keys::*;
-
-use blockchain::v10::documents::certification::CertificationDocument;
-use blockchain::v10::documents::identity::IdentityDocument;
-use blockchain::v10::documents::membership::MembershipDocument;
-use blockchain::v10::documents::revocation::RevocationDocument;
-use blockchain::v10::documents::transaction::TransactionDocument;
-use blockchain::v10::documents::*;
-use blockchain::{BlockchainProtocol, Document, IntoSpecializedDocument};
 use std::ops::Deref;
-use CurrencyName;
-use {BlockHash, BlockId, Blockstamp};
+
+use blockstamp::Blockstamp;
+use v10::certification::CertificationDocument;
+use v10::identity::IdentityDocument;
+use v10::membership::MembershipDocument;
+use v10::revocation::RevocationDocument;
+use v10::transaction::TransactionDocument;
+use v10::*;
+use *;
 
 #[derive(Debug, Clone)]
 /// Store error in block parameters parsing
@@ -510,10 +509,11 @@ impl IntoSpecializedDocument<BlockchainProtocol> for BlockDocument {
 
 #[cfg(test)]
 mod tests {
+    use super::certification::CertificationDocumentParser;
+    use super::transaction::TransactionDocumentParser;
     use super::*;
-    use blockchain::v10::documents::V10DocumentParser;
-    use blockchain::{Document, DocumentParser, VerificationResult};
     use std::ops::Deref;
+    use {Document, VerificationResult};
 
     #[test]
     fn generate_and_verify_empty_block() {
@@ -575,7 +575,7 @@ mod tests {
 
     #[test]
     fn generate_and_verify_block() {
-        let cert1_ = V10DocumentParser::parse("Version: 10
+        let cert1 = CertificationDocumentParser::parse("Version: 10
 Type: Certification
 Currency: g1
 Issuer: 6TAzLWuNcSqgNDNpAutrKpPXcGJwy1ZEMeVvZSZNs2e3
@@ -584,13 +584,13 @@ IdtyUniqueID: PascaleM
 IdtyTimestamp: 97401-0000003821911909F98519CC773D2D3E5CFE3D5DBB39F4F4FF33B96B4D41800E
 IdtySignature: QncUVXxZ2NfARjdJOn6luILvDuG1NuK9qSoaU4CST2Ij8z7oeVtEgryHl+EXOjSe6XniALsCT0gU8wtadcA/Cw==
 CertTimestamp: 106669-000003682E6FE38C44433DCE92E8B2A26C69B6D7867A2BAED231E788DDEF4251
-UmseG2XKNwKcY8RFi6gUCT91udGnnNmSh7se10J1jeRVlwf+O2Tyb2Cccot9Dt7BO4+Kx2P6vFJB3oVGGHMxBA==").unwrap();
-        let cert1 = match cert1_ {
+UmseG2XKNwKcY8RFi6gUCT91udGnnNmSh7se10J1jeRVlwf+O2Tyb2Cccot9Dt7BO4+Kx2P6vFJB3oVGGHMxBA==", "g1").expect("Fail to parse cert1");
+        let cert1 = match cert1 {
             V10Document::Certification(doc) => (*doc.deref()).clone(),
             _ => panic!("Wrong document type"),
         };
 
-        let tx1_ = V10DocumentParser::parse("Version: 10
+        let tx1 = TransactionDocumentParser::parse("Version: 10
 Type: Transaction
 Currency: g1
 Blockstamp: 107982-000001242F6DA51C06A915A96C58BAA37AB3D1EB51F6E1C630C707845ACF764B
@@ -604,13 +604,13 @@ Unlocks:
 Outputs:
 1002:0:SIG(CitdnuQgZ45tNFCagay7Wh12gwwHM8VLej1sWmfHWnQX)
 Comment: DU symbolique pour demander le codage de nouvelles fonctionnalites cf. https://forum.monnaie-libre.fr/t/creer-de-nouvelles-fonctionnalites-dans-cesium-les-autres-applications/2025  Merci
-T0LlCcbIn7xDFws48H8LboN6NxxwNXXTovG4PROLf7tkUAueHFWjfwZFKQXeZEHxfaL1eYs3QspGtLWUHPRVCQ==").unwrap();
-        let tx1 = match tx1_ {
+T0LlCcbIn7xDFws48H8LboN6NxxwNXXTovG4PROLf7tkUAueHFWjfwZFKQXeZEHxfaL1eYs3QspGtLWUHPRVCQ==", "g1").expect("Fail to parse tx1");
+        let tx1 = match tx1 {
             V10Document::Transaction(doc) => (*doc.deref()).clone(),
             _ => panic!("Wrong document type"),
         };
 
-        let tx2_ = V10DocumentParser::parse("Version: 10
+        let tx2 = TransactionDocumentParser::parse("Version: 10
 Type: Transaction
 Currency: g1
 Blockstamp: 107982-000001242F6DA51C06A915A96C58BAA37AB3D1EB51F6E1C630C707845ACF764B
@@ -624,8 +624,8 @@ Unlocks:
 Outputs:
 1002:0:SIG(78ZwwgpgdH5uLZLbThUQH7LKwPgjMunYfLiCfUCySkM8)
 Comment: DU symbolique pour demander le codage de nouvelles fonctionnalites cf. https://forum.monnaie-libre.fr/t/creer-de-nouvelles-fonctionnalites-dans-cesium-les-autres-applications/2025  Merci
-a9PHPuSfw7jW8FRQHXFsGi/bnLjbtDnTYvEVgUC9u0WlR7GVofa+Xb+l5iy6NwuEXiwvueAkf08wPVY8xrNcCg==").unwrap();
-        let tx2 = match tx2_ {
+a9PHPuSfw7jW8FRQHXFsGi/bnLjbtDnTYvEVgUC9u0WlR7GVofa+Xb+l5iy6NwuEXiwvueAkf08wPVY8xrNcCg==", "g1").expect("Fail to parse tx2");
+        let tx2 = match tx2 {
             V10Document::Transaction(doc) => (*doc.deref()).clone(),
             _ => panic!("Wrong document type"),
         };
diff --git a/documents/blockchain/v10/documents/certification.rs b/documents/src/v10/certification.rs
similarity index 67%
rename from documents/blockchain/v10/documents/certification.rs
rename to documents/src/v10/certification.rs
index e03213f00917646239df20f8d8270860efa8c172..00ec4df88f087ec61f53eeda31862ac2d570fd84 100644
--- a/documents/blockchain/v10/documents/certification.rs
+++ b/documents/src/v10/certification.rs
@@ -16,18 +16,11 @@
 //! Wrappers around Certification documents.
 
 use duniter_crypto::keys::*;
-use regex::Regex;
+use pest::Parser;
 
-use blockchain::v10::documents::*;
-use blockchain::{BlockchainProtocol, Document, DocumentBuilder, IntoSpecializedDocument};
-use BlockId;
-use Blockstamp;
-
-lazy_static! {
-    static ref CERTIFICATION_REGEX: Regex = Regex::new(
-        "^Issuer: (?P<issuer>[1-9A-Za-z]{43,44})\nIdtyIssuer: (?P<target>[1-9A-Za-z]{43,44})\nIdtyUniqueID: (?P<idty_uid>[[:alnum:]_-]+)\nIdtyTimestamp: (?P<idty_blockstamp>[0-9]+-[0-9A-F]{64})\nIdtySignature: (?P<idty_sig>(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?)\nCertTimestamp: (?P<blockstamp>[0-9]+-[0-9A-F]{64})\n$"
-    ).unwrap();
-}
+use blockstamp::Blockstamp;
+use v10::*;
+use *;
 
 #[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
 /// Wrap an Compact Revocation document (in block content)
@@ -124,7 +117,7 @@ impl Document for CertificationDocument {
     }
 
     fn as_bytes(&self) -> &[u8] {
-        self.as_text().as_bytes()
+        self.as_text_without_signature().as_bytes()
     }
 }
 
@@ -228,47 +221,74 @@ CertTimestamp: {blockstamp}
 #[derive(Debug, Clone, Copy)]
 pub struct CertificationDocumentParser;
 
-impl StandardTextDocumentParser for CertificationDocumentParser {
-    fn parse_standard(
-        doc: &str,
-        body: &str,
-        currency: &str,
-        signatures: Vec<Sig>,
-    ) -> Result<V10Document, V10DocumentParsingError> {
-        if let Some(caps) = CERTIFICATION_REGEX.captures(body) {
-            let issuer = &caps["issuer"];
-            let target = &caps["target"];
-            let identity_username = &caps["idty_uid"];
-            let identity_blockstamp = &caps["idty_blockstamp"];
-            let identity_sig = &caps["idty_sig"];
-            let blockstamp = &caps["blockstamp"];
-
-            // Regex match so should not fail.
-            // TODO : Test it anyway
-            let issuer = PubKey::Ed25519(ed25519::PublicKey::from_base58(issuer).unwrap());
-            let target = PubKey::Ed25519(ed25519::PublicKey::from_base58(target).unwrap());
-            let identity_username = String::from(identity_username);
-            let identity_blockstamp = Blockstamp::from_string(identity_blockstamp).unwrap();
-            let identity_sig = Sig::Ed25519(ed25519::Signature::from_base64(identity_sig).unwrap());
-            let blockstamp = Blockstamp::from_string(blockstamp).unwrap();
-
-            Ok(V10Document::Certification(Box::new(
-                CertificationDocument {
-                    text: doc.to_owned(),
-                    issuers: vec![issuer],
-                    currency: currency.to_owned(),
-                    target,
-                    identity_username,
-                    identity_blockstamp,
-                    identity_sig,
-                    blockstamp,
-                    signatures,
-                },
-            )))
-        } else {
-            Err(V10DocumentParsingError::InvalidInnerFormat(
-                "Certification".to_string(),
-            ))
+impl TextDocumentParser for CertificationDocumentParser {
+    fn parse(doc: &str, currency: &str) -> Result<V10Document, V10DocumentParsingError> {
+        match DocumentsParser::parse(Rule::cert, doc) {
+            Ok(mut doc_ast) => {
+                let cert_ast = doc_ast.next().unwrap(); // get and unwrap the `cert` rule; never fails
+                let cert_vx_ast = cert_ast.into_inner().next().unwrap(); // get and unwrap the `cert_vX` rule; never fails
+
+                match cert_vx_ast.as_rule() {
+                    Rule::cert_v10 => {
+                        let mut pubkeys = Vec::with_capacity(2);
+                        let mut uid = "";
+                        let mut sigs = Vec::with_capacity(2);
+                        let mut blockstamps = Vec::with_capacity(2);
+                        for field in cert_vx_ast.into_inner() {
+                            match field.as_rule() {
+                                Rule::currency => {
+                                    if currency != field.as_str() {
+                                        return Err(V10DocumentParsingError::InvalidCurrency());
+                                    }
+                                }
+                                Rule::pubkey => pubkeys.push(PubKey::Ed25519(
+                                    ed25519::PublicKey::from_base58(field.as_str()).unwrap(), // Grammar ensures that we have a base58 string.
+                                )),
+                                Rule::uid => {
+                                    uid = field.as_str();
+                                }
+                                Rule::blockstamp => {
+                                    if blockstamps.len() > 1 {
+                                        return Err(V10DocumentParsingError::InvalidInnerFormat(
+                                            "Cert document must contain exactly two blockstamps !",
+                                        ));
+                                    }
+                                    let mut inner_rules = field.into_inner(); // { integer ~ "-" ~ hash }
+
+                                    let block_id: &str = inner_rules.next().unwrap().as_str();
+                                    let block_hash: &str = inner_rules.next().unwrap().as_str();
+                                    blockstamps.push(Blockstamp {
+                                        id: BlockId(block_id.parse().unwrap()), // Grammar ensures that we have a digits string.
+                                        hash: BlockHash(Hash::from_hex(block_hash).unwrap()), // Grammar ensures that we have an hexadecimal string.
+                                    });
+                                }
+                                Rule::ed25519_sig => {
+                                    sigs.push(Sig::Ed25519(
+                                        ed25519::Signature::from_base64(field.as_str()).unwrap(), // Grammar ensures that we have a base64 string.
+                                    ));
+                                }
+                                Rule::EOI => (),
+                                _ => panic!("unexpected rule"), // Grammar ensures that we never reach this line
+                            }
+                        }
+                        Ok(V10Document::Certification(Box::new(
+                            CertificationDocument {
+                                text: doc.to_owned(),
+                                issuers: vec![pubkeys[0]],
+                                currency: currency.to_owned(),
+                                target: pubkeys[1],
+                                identity_username: uid.to_owned(),
+                                identity_blockstamp: blockstamps[0],
+                                identity_sig: sigs[0],
+                                blockstamp: blockstamps[1],
+                                signatures: vec![sigs[1]],
+                            },
+                        )))
+                    }
+                    _ => Err(V10DocumentParsingError::UnexpectedVersion()),
+                }
+            }
+            Err(pest_error) => panic!("{}", pest_error), //Err(V10DocumentParsingError::PestError()),
         }
     }
 }
@@ -276,8 +296,8 @@ impl StandardTextDocumentParser for CertificationDocumentParser {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use blockchain::VerificationResult;
     use duniter_crypto::keys::{PrivateKey, PublicKey, Signature};
+    use VerificationResult;
 
     #[test]
     fn generate_real_document() {
@@ -334,19 +354,6 @@ mod tests {
         );
     }
 
-    #[test]
-    fn certification_standard_regex() {
-        assert!(CERTIFICATION_REGEX.is_match(
-            "Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV
-IdtyIssuer: 7jzkd8GiFnpys4X7mP78w2Y3y3kwdK6fVSLEaojd3aH9
-IdtyUniqueID: fbarbut
-IdtyTimestamp: 98221-000000575AC04F5164F7A307CDB766139EA47DD249E4A2444F292BC8AAB408B3
-IdtySignature: DjeipIeb/RF0tpVCnVnuw6mH1iLJHIsDfPGLR90Twy3PeoaDz6Yzhc/UjLWqHCi5Y6wYajV0dNg4jQRUneVBCQ==
-CertTimestamp: 99956-00000472758331FDA8388E30E50CA04736CBFD3B7C21F34E74707107794B56DD
-"
-        ));
-    }
-
     #[test]
     fn certification_document() {
         let doc = "Version: 10
@@ -358,24 +365,11 @@ IdtyUniqueID: mmpio
 IdtyTimestamp: 7543-000044410C5370DE8DBA911A358F318096B7A269CFC2BB93272E397CC513EA0A
 IdtySignature: SmSweUD4lEMwiZfY8ux9maBjrQQDkC85oMNsin6oSQCPdXG8sFCZ4FisUaWqKsfOlZVb/HNa+TKzD2t0Yte+DA==
 CertTimestamp: 167884-0001DFCA28002A8C96575E53B8CEF8317453A7B0BA255542CCF0EC8AB5E99038
-";
-
-        let body = "Issuer: 5B8iMAzq1dNmFe3ZxFTBQkqhq4fsztg1gZvxHXCk1XYH
-IdtyIssuer: mMPioknj2MQCX9KyKykdw8qMRxYR2w1u3UpdiEJHgXg
-IdtyUniqueID: mmpio
-IdtyTimestamp: 7543-000044410C5370DE8DBA911A358F318096B7A269CFC2BB93272E397CC513EA0A
-IdtySignature: SmSweUD4lEMwiZfY8ux9maBjrQQDkC85oMNsin6oSQCPdXG8sFCZ4FisUaWqKsfOlZVb/HNa+TKzD2t0Yte+DA==
-CertTimestamp: 167884-0001DFCA28002A8C96575E53B8CEF8317453A7B0BA255542CCF0EC8AB5E99038
-";
+wqZxPEGxLrHGv8VdEIfUGvUcf+tDdNTMXjLzVRCQ4UhlhDRahOMjfcbP7byNYr5OfIl83S1MBxF7VJgu8YasCA==";
 
         let currency = "g1-test";
 
-        let signatures = vec![Sig::Ed25519(ed25519::Signature::from_base64(
-"wqZxPEGxLrHGv8VdEIfUGvUcf+tDdNTMXjLzVRCQ4UhlhDRahOMjfcbP7byNYr5OfIl83S1MBxF7VJgu8YasCA=="
-        ).unwrap())];
-
-        let doc =
-            CertificationDocumentParser::parse_standard(doc, body, currency, signatures).unwrap();
+        let doc = CertificationDocumentParser::parse(doc, currency).unwrap();
         if let V10Document::Certification(doc) = doc {
             println!("Doc : {:?}", doc);
             assert_eq!(doc.verify_signatures(), VerificationResult::Valid());
diff --git a/documents/blockchain/v10/documents/identity.rs b/documents/src/v10/identity.rs
similarity index 67%
rename from documents/blockchain/v10/documents/identity.rs
rename to documents/src/v10/identity.rs
index 4eacf71e517e38cf909d46a1c5ccc4ef4a621dfc..fb228f5f65974f34712cab73a9482b6b50313495 100644
--- a/documents/blockchain/v10/documents/identity.rs
+++ b/documents/src/v10/identity.rs
@@ -15,16 +15,11 @@
 
 //! Wrappers around Identity documents.
 
-use blockchain::v10::documents::*;
-use blockchain::{BlockchainProtocol, Document, DocumentBuilder, IntoSpecializedDocument};
-use regex::Regex;
-use Blockstamp;
+use pest::Parser;
 
-lazy_static! {
-    static ref IDENTITY_REGEX: Regex = Regex::new(
-        "^Issuer: (?P<issuer>[1-9A-Za-z][^OIl]{43,44})\nUniqueID: (?P<uid>[[:alnum:]_-]+)\nTimestamp: (?P<blockstamp>[0-9]+-[0-9A-F]{64})\n$"
-    ).unwrap();
-}
+use v10::*;
+use Blockstamp;
+use *;
 
 /// Wrap an Identity document.
 ///
@@ -86,7 +81,7 @@ impl Document for IdentityDocument {
     }
 
     fn as_bytes(&self) -> &[u8] {
-        self.as_text().as_bytes()
+        self.as_text_without_signature().as_bytes()
     }
 }
 
@@ -204,35 +199,60 @@ Timestamp: {blockstamp}
 #[derive(Debug, Clone, Copy)]
 pub struct IdentityDocumentParser;
 
-impl StandardTextDocumentParser for IdentityDocumentParser {
-    fn parse_standard(
-        doc: &str,
-        body: &str,
-        currency: &str,
-        signatures: Vec<Sig>,
-    ) -> Result<V10Document, V10DocumentParsingError> {
-        if let Some(caps) = IDENTITY_REGEX.captures(body) {
-            let issuer = &caps["issuer"];
-            let uid = &caps["uid"];
-            let blockstamp = &caps["blockstamp"];
-
-            // Regex match so should not fail.
-            // TODO : Test it anyway
-            let issuer = PubKey::Ed25519(ed25519::PublicKey::from_base58(issuer).unwrap());
-            let blockstamp = Blockstamp::from_string(blockstamp).unwrap();
-
-            Ok(V10Document::Identity(IdentityDocument {
-                text: Some(doc.to_owned()),
-                currency: currency.to_owned(),
-                username: uid.to_owned(),
-                blockstamp,
-                issuers: vec![issuer],
-                signatures,
-            }))
-        } else {
-            Err(V10DocumentParsingError::InvalidInnerFormat(
-                "Identity".to_string(),
-            ))
+impl TextDocumentParser for IdentityDocumentParser {
+    fn parse(doc: &str, currency: &str) -> Result<V10Document, V10DocumentParsingError> {
+        match DocumentsParser::parse(Rule::idty, doc) {
+            Ok(mut doc_ast) => {
+                let idty_ast = doc_ast.next().unwrap(); // get and unwrap the `idty` rule; never fails
+                let idty_vx_ast = idty_ast.into_inner().next().unwrap(); // get and unwrap the `idty_vX` rule; never fails
+
+                match idty_vx_ast.as_rule() {
+                    Rule::idty_v10 => {
+                        let mut pubkey_str = "";
+                        let mut uid = "";
+                        let mut blockstamp = Blockstamp::default();
+                        let mut sig_str = "";
+                        for field in idty_vx_ast.into_inner() {
+                            match field.as_rule() {
+                                Rule::currency => {
+                                    if currency != field.as_str() {
+                                        return Err(V10DocumentParsingError::InvalidCurrency());
+                                    }
+                                }
+                                Rule::pubkey => pubkey_str = field.as_str(),
+                                Rule::uid => uid = field.as_str(),
+                                Rule::blockstamp => {
+                                    let mut inner_rules = field.into_inner(); // { integer ~ "-" ~ hash }
+
+                                    let block_id: &str = inner_rules.next().unwrap().as_str();
+                                    let block_hash: &str = inner_rules.next().unwrap().as_str();
+                                    blockstamp = Blockstamp {
+                                        id: BlockId(block_id.parse().unwrap()), // Grammar ensures that we have a digits string.
+                                        hash: BlockHash(Hash::from_hex(block_hash).unwrap()), // Grammar ensures that we have an hexadecimal string.
+                                    };
+                                }
+                                Rule::ed25519_sig => sig_str = field.as_str(),
+                                Rule::EOI => (),
+                                _ => panic!("unexpected rule"), // Grammar ensures that we never reach this line
+                            }
+                        }
+                        Ok(V10Document::Identity(IdentityDocument {
+                            text: Some(doc.to_owned()),
+                            currency: currency.to_owned(),
+                            username: uid.to_owned(),
+                            blockstamp,
+                            issuers: vec![PubKey::Ed25519(
+                                ed25519::PublicKey::from_base58(pubkey_str).unwrap(),
+                            )], // Grammar ensures that we have a base58 string.
+                            signatures: vec![Sig::Ed25519(
+                                ed25519::Signature::from_base64(sig_str).unwrap(),
+                            )], // Grammar ensures that we have a base64 string.
+                        }))
+                    }
+                    _ => Err(V10DocumentParsingError::UnexpectedVersion()),
+                }
+            }
+            Err(pest_error) => panic!("{}", pest_error), //Err(V10DocumentParsingError::PestError()),
         }
     }
 }
@@ -240,8 +260,8 @@ impl StandardTextDocumentParser for IdentityDocumentParser {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use blockchain::{Document, VerificationResult};
     use duniter_crypto::keys::{PrivateKey, PublicKey, Signature};
+    use {Document, VerificationResult};
 
     #[test]
     fn generate_real_document() {
@@ -288,16 +308,6 @@ mod tests {
         );
     }
 
-    #[test]
-    fn identity_standard_regex() {
-        assert!(IDENTITY_REGEX.is_match(
-            "Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV
-UniqueID: tic
-Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
-"
-        ));
-    }
-
     #[test]
     fn parse_identity_document() {
         let doc = "Version: 10
@@ -306,20 +316,11 @@ Currency: duniter_unit_test_currency
 Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV
 UniqueID: tic
 Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
-";
-
-        let body = "Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV
-UniqueID: tic
-Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
-";
+1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGMMmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==";
 
         let currency = "duniter_unit_test_currency";
 
-        let signatures = vec![Sig::Ed25519(ed25519::Signature::from_base64(
-"1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGMMmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg=="
-        ).unwrap())];
-
-        let doc = IdentityDocumentParser::parse_standard(doc, body, currency, signatures).unwrap();
+        let doc = IdentityDocumentParser::parse(doc, currency).expect("Fail to parse idty doc !");
         if let V10Document::Identity(doc) = doc {
             println!("Doc : {:?}", doc);
             assert_eq!(doc.verify_signatures(), VerificationResult::Valid())
diff --git a/documents/blockchain/v10/documents/membership.rs b/documents/src/v10/membership.rs
similarity index 69%
rename from documents/blockchain/v10/documents/membership.rs
rename to documents/src/v10/membership.rs
index 3e3fb554a114a3b3bca72af5167c073e4795680a..55eb6e4606ff7a37fa41fcad35ca087a3e45e1ab 100644
--- a/documents/blockchain/v10/documents/membership.rs
+++ b/documents/src/v10/membership.rs
@@ -16,22 +16,11 @@
 //! Wrappers around Membership documents.
 
 use duniter_crypto::keys::*;
-use regex::Regex;
-
-use blockchain::v10::documents::*;
-use blockchain::{BlockchainProtocol, Document, DocumentBuilder, IntoSpecializedDocument};
-use Blockstamp;
-
-lazy_static! {
-    static ref MEMBERSHIP_REGEX: Regex = Regex::new(
-        "^Issuer: (?P<issuer>[1-9A-Za-z][^OIl]{43,44})\n\
-         Block: (?P<blockstamp>[0-9]+-[0-9A-F]{64})\n\
-         Membership: (?P<membership>(IN|OUT))\n\
-         UserID: (?P<ity_user>[[:alnum:]_-]+)\n\
-         CertTS: (?P<ity_block>[0-9]+-[0-9A-F]{64})\n$"
-    )
-    .unwrap();
-}
+use pest::Parser;
+
+use blockstamp::Blockstamp;
+use v10::*;
+use *;
 
 /// Type of a Membership.
 #[derive(Debug, Deserialize, Clone, Copy, Hash, Serialize, PartialEq, Eq)]
@@ -136,7 +125,7 @@ impl Document for MembershipDocument {
     }
 
     fn as_bytes(&self) -> &[u8] {
-        self.as_text().as_bytes()
+        self.as_text_without_signature().as_bytes()
     }
 }
 
@@ -259,47 +248,68 @@ CertTS: {ity_blockstamp}
 #[derive(Debug, Clone, Copy)]
 pub struct MembershipDocumentParser;
 
-impl StandardTextDocumentParser for MembershipDocumentParser {
-    fn parse_standard(
-        doc: &str,
-        body: &str,
-        currency: &str,
-        signatures: Vec<Sig>,
-    ) -> Result<V10Document, V10DocumentParsingError> {
-        if let Some(caps) = MEMBERSHIP_REGEX.captures(body) {
-            let issuer = &caps["issuer"];
-
-            let blockstamp = &caps["blockstamp"];
-            let membership = &caps["membership"];
-            let username = &caps["ity_user"];
-            let ity_block = &caps["ity_block"];
-
-            // Regex match so should not fail.
-            // TODO : Test it anyway
-            let issuer = PubKey::Ed25519(ed25519::PublicKey::from_base58(issuer).unwrap());
-            let blockstamp = Blockstamp::from_string(blockstamp).unwrap();
-            let membership = match membership {
-                "IN" => MembershipType::In(),
-                "OUT" => MembershipType::Out(),
-                _ => panic!("Invalid membership type {}", membership),
-            };
-
-            let ity_block = Blockstamp::from_string(ity_block).unwrap();
-
-            Ok(V10Document::Membership(MembershipDocument {
-                text: Some(doc.to_owned()),
-                issuers: vec![issuer],
-                currency: currency.to_owned(),
-                blockstamp,
-                membership,
-                identity_username: username.to_owned(),
-                identity_blockstamp: ity_block,
-                signatures,
-            }))
-        } else {
-            Err(V10DocumentParsingError::InvalidInnerFormat(
-                "Membership".to_string(),
-            ))
+impl TextDocumentParser for MembershipDocumentParser {
+    fn parse(doc: &str, currency: &str) -> Result<V10Document, V10DocumentParsingError> {
+        match DocumentsParser::parse(Rule::membership, doc) {
+            Ok(mut doc_ast) => {
+                let membership_ast = doc_ast.next().unwrap(); // get and unwrap the `membership` rule; never fails
+                let membership_vx_ast = membership_ast.into_inner().next().unwrap(); // get and unwrap the `membership_vX` rule; never fails
+
+                match membership_vx_ast.as_rule() {
+                    Rule::membership_v10 => {
+                        let mut pubkey_str = "";
+                        let mut uid = "";
+                        let mut blockstamps = Vec::with_capacity(2);
+                        let mut membership = MembershipType::In();
+                        let mut sig_str = "";
+                        for field in membership_vx_ast.into_inner() {
+                            match field.as_rule() {
+                                Rule::currency => {
+                                    if currency != field.as_str() {
+                                        return Err(V10DocumentParsingError::InvalidCurrency());
+                                    }
+                                }
+                                Rule::pubkey => pubkey_str = field.as_str(),
+                                Rule::uid => uid = field.as_str(),
+                                Rule::membership_in => membership = MembershipType::In(),
+                                Rule::membership_out => membership = MembershipType::Out(),
+                                Rule::blockstamp => {
+                                    if blockstamps.len() > 1 {
+                                        return Err(V10DocumentParsingError::InvalidInnerFormat("Membership document must have exactly two blockstamps !"));
+                                    }
+                                    let mut inner_rules = field.into_inner(); // { integer ~ "-" ~ hash }
+
+                                    let block_id: &str = inner_rules.next().unwrap().as_str();
+                                    let block_hash: &str = inner_rules.next().unwrap().as_str();
+                                    blockstamps.push(Blockstamp {
+                                        id: BlockId(block_id.parse().unwrap()), // Grammar ensures that we have a digits string.
+                                        hash: BlockHash(Hash::from_hex(block_hash).unwrap()), // Grammar ensures that we have an hexadecimal string.
+                                    });
+                                }
+                                Rule::ed25519_sig => sig_str = field.as_str(),
+                                Rule::EOI => (),
+                                _ => panic!("unexpected rule"), // Grammar ensures that we never reach this line
+                            }
+                        }
+                        Ok(V10Document::Membership(MembershipDocument {
+                            text: Some(doc.to_owned()),
+                            issuers: vec![PubKey::Ed25519(
+                                ed25519::PublicKey::from_base58(pubkey_str).unwrap(),
+                            )], // Grammar ensures that we have a base58 string.
+                            currency: currency.to_owned(),
+                            blockstamp: blockstamps[0],
+                            membership,
+                            identity_username: uid.to_owned(),
+                            identity_blockstamp: blockstamps[1],
+                            signatures: vec![Sig::Ed25519(
+                                ed25519::Signature::from_base64(sig_str).unwrap(),
+                            )], // Grammar ensures that we have a base64 string.
+                        }))
+                    }
+                    _ => Err(V10DocumentParsingError::UnexpectedVersion()),
+                }
+            }
+            Err(pest_error) => panic!("{}", pest_error), //Err(V10DocumentParsingError::PestError()),
         }
     }
 }
@@ -307,8 +317,8 @@ impl StandardTextDocumentParser for MembershipDocumentParser {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use blockchain::VerificationResult;
     use duniter_crypto::keys::{PrivateKey, PublicKey, Signature};
+    use VerificationResult;
 
     #[test]
     fn generate_real_document() {
@@ -357,18 +367,6 @@ mod tests {
         );
     }
 
-    #[test]
-    fn membership_standard_regex() {
-        assert!(MEMBERSHIP_REGEX.is_match(
-            "Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV
-Block: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
-Membership: IN
-UserID: tic
-CertTS: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
-"
-        ));
-    }
-
     #[test]
     fn membership_identity_document() {
         let doc = "Version: 10
@@ -379,23 +377,11 @@ Block: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
 Membership: IN
 UserID: tic
 CertTS: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
-";
-
-        let body = "Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV
-Block: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
-Membership: IN
-UserID: tic
-CertTS: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
-";
+s2hUbokkibTAWGEwErw6hyXSWlWFQ2UWs2PWx8d/kkElAyuuWaQq4Tsonuweh1xn4AC1TVWt4yMR3WrDdkhnAw==";
 
         let currency = "duniter_unit_test_currency";
 
-        let signatures = vec![Sig::Ed25519(ed25519::Signature::from_base64(
-"s2hUbokkibTAWGEwErw6hyXSWlWFQ2UWs2PWx8d/kkElAyuuWaQq4Tsonuweh1xn4AC1TVWt4yMR3WrDdkhnAw=="
-        ).unwrap())];
-
-        let doc =
-            MembershipDocumentParser::parse_standard(doc, body, currency, signatures).unwrap();
+        let doc = MembershipDocumentParser::parse(doc, currency).unwrap();
         if let V10Document::Membership(doc) = doc {
             println!("Doc : {:?}", doc);
             assert_eq!(doc.verify_signatures(), VerificationResult::Valid());
diff --git a/documents/blockchain/v10/documents/mod.rs b/documents/src/v10/mod.rs
similarity index 59%
rename from documents/blockchain/v10/documents/mod.rs
rename to documents/src/v10/mod.rs
index 3e3d2137834cf3b39e400e49c0858e4b84306538..0cefad227a7d6a59f717ae1cecbac6b9721997dc 100644
--- a/documents/blockchain/v10/documents/mod.rs
+++ b/documents/src/v10/mod.rs
@@ -15,12 +15,6 @@
 
 //! Provide wrappers around Duniter blockchain documents for protocol version 10.
 
-use blockchain::v10::documents::identity::IdentityDocumentParser;
-use blockchain::{Document, DocumentBuilder, DocumentParser};
-use crypto::digest::Digest;
-use duniter_crypto::keys::*;
-use regex::Regex;
-
 pub mod block;
 pub mod certification;
 pub mod identity;
@@ -28,31 +22,16 @@ pub mod membership;
 pub mod revocation;
 pub mod transaction;
 
-pub use blockchain::v10::documents::block::BlockDocument;
-pub use blockchain::v10::documents::certification::{
-    CertificationDocument, CertificationDocumentParser,
-};
-pub use blockchain::v10::documents::identity::{IdentityDocument, IdentityDocumentBuilder};
-pub use blockchain::v10::documents::membership::{MembershipDocument, MembershipDocumentParser};
-pub use blockchain::v10::documents::revocation::{RevocationDocument, RevocationDocumentParser};
-pub use blockchain::v10::documents::transaction::{
-    TransactionDocument, TransactionDocumentBuilder, TransactionDocumentParser,
-};
-
-use std::marker::Sized;
-
-// Use of lazy_static so the regex is only compiled at first use.
-lazy_static! {
-    static ref DOCUMENT_REGEX: Regex = Regex::new(
-        "^(?P<doc>Version: (?P<version>[0-9]+)\n\
-         Type: (?P<type>[[:alpha:]]+)\n\
-         Currency: (?P<currency>[[:alnum:] _-]+)\n\
-         (?P<body>(?:.*\n)+?))\
-         (?P<sigs>([[:alnum:]+/=]+\n)*([[:alnum:]+/=]+))$"
-    )
-    .unwrap();
-    static ref SIGNATURES_REGEX: Regex = Regex::new("[[:alnum:]+/=]+\n?").unwrap();
-}
+use crypto::digest::Digest;
+use duniter_crypto::keys::PrivateKey;
+
+pub use v10::block::BlockDocument;
+use v10::certification::*;
+use v10::identity::*;
+use v10::membership::*;
+use v10::revocation::*;
+use v10::transaction::*;
+use *;
 
 #[derive(Clone, Debug, Deserialize, Serialize)]
 /// Contains a document in full or compact format
@@ -124,22 +103,34 @@ pub trait TextDocument: Document<PublicKey = PubKey, CurrencyType = str> {
     /// Return document as text.
     fn as_text(&self) -> &str;
 
+    /// Return document as text without signature.
+    fn as_text_without_signature(&self) -> &str {
+        let text = self.as_text();
+        let mut lines: Vec<&str> = self.as_text().split('\n').collect();
+        let sigs = self.signatures();
+        let mut sigs_str_len = sigs.len() - 1;
+        for _ in sigs {
+            sigs_str_len += lines.pop().unwrap_or("").len();
+        }
+        &text[0..(text.len() - sigs_str_len)]
+    }
+
     /// Return sha256 hash of text document
     fn hash<H: Digest>(&self, digest: &mut H) -> String {
         digest.input_str(self.as_text());
         digest.result_str()
     }
 
-    /// Return document as text with leading signatures.
+    /*/// Return document as text with leading signatures.
     fn as_text_with_signatures(&self) -> String {
         let mut text = self.as_text().to_string();
-
+    
         for sig in self.signatures() {
             text = format!("{}{}\n", text, sig.to_base64());
         }
-
+    
         text
-    }
+    }*/
 
     /// Generate compact document.
     /// the compact format is the one used in the blocks.
@@ -191,9 +182,15 @@ pub enum V10DocumentParsingError {
     /// The given source don't have a valid document format.
     InvalidWrapperFormat(),
     /// The given source don't have a valid specific document format (document type).
-    InvalidInnerFormat(String),
+    InvalidInnerFormat(&'static str),
     /// Type fields contains an unknown document type.
     UnknownDocumentType(String),
+    /// Error with pest parser
+    PestError(),
+    /// Invalid currency
+    InvalidCurrency(),
+    /// UnexpectedVersion
+    UnexpectedVersion(),
 }
 
 /// V10 Documents in separated parts
@@ -209,134 +206,186 @@ pub struct V10DocumentParts {
     pub signatures: Vec<Sig>,
 }
 
-trait StandardTextDocumentParser {
-    fn parse_standard(
-        doc: &str,
-        body: &str,
-        currency: &str,
-        signatures: Vec<Sig>,
-    ) -> Result<V10Document, V10DocumentParsingError>;
+trait TextDocumentParser {
+    fn parse(doc: &str, currency: &str) -> Result<V10Document, V10DocumentParsingError>;
 }
 
-/// A V10 document parser.
+/*/// A V10 document parser.
 #[derive(Debug, Clone, Copy)]
 pub struct V10DocumentParser;
 
 impl<'a> DocumentParser<&'a str, V10Document, V10DocumentParsingError> for V10DocumentParser {
     fn parse(source: &'a str) -> Result<V10Document, V10DocumentParsingError> {
-        if let Some(caps) = DOCUMENT_REGEX.captures(source) {
-            let doctype = &caps["type"];
-            let doc = &caps["doc"];
-            let currency = &caps["currency"];
-            let body = &caps["body"];
-            let sigs = SIGNATURES_REGEX
-                .captures_iter(&caps["sigs"])
-                .map(|capture| Sig::Ed25519(ed25519::Signature::from_base64(&capture[0]).unwrap()))
-                .collect::<Vec<_>>();
-
-            // TODO : Improve error handling of Signature::from_base64 failure
-
-            match doctype {
-                "Identity" => IdentityDocumentParser::parse_standard(doc, body, currency, sigs),
-                "Membership" => MembershipDocumentParser::parse_standard(doc, body, currency, sigs),
-                "Certification" => {
-                    CertificationDocumentParser::parse_standard(doc, body, currency, sigs)
-                }
-                "Revocation" => RevocationDocumentParser::parse_standard(doc, body, currency, sigs),
-                "Transaction" => {
-                    TransactionDocumentParser::parse_standard(doc, body, currency, sigs)
+        /*match DocumentsParser::parse(Rule::document_v10, source) {
+            Ok(mut source_ast) => {
+                let doc_v10_ast = source_ast.next().unwrap(); // get and unwrap the `document_v10` rule; never fails
+                let doc_type_v10_ast = doc_v10_ast.into_inner().next().unwrap(); // get and unwrap the `{DOC_TYPE}_v10` rule; never fails
+        
+                match doc_type_v10_ast.as_rule() {
+                    Rule::idty_v10 => IdentityDocumentParser::parse_standard(doc_type_v10_ast.as_str(), "", currency, vec![]),
+                    Rule::membership_v10 => MembershipDocumentParser::parse_standard(doc_type_v10_ast.as_str(), "", currency, vec![]),
+                    Rule::cert_v10 => CertificationDocumentParser::parse_standard(doc_type_v10_ast.as_str(), "", currency, vec![]),
+                    Rule::revoc_v10 => RevocationDocumentParser::parse_standard(doc_type_v10_ast.as_str(), "", currency, vec![]),
+                    Rule::tx_v10 => TransactionDocumentParser::parse_standard(doc_type_v10_ast.as_str(), "", currency, vec![]),
                 }
-                _ => Err(V10DocumentParsingError::UnknownDocumentType(
-                    doctype.to_string(),
-                )),
             }
-        } else {
-            Err(V10DocumentParsingError::InvalidWrapperFormat())
-        }
-    }
+            Err(_) => Err(V10DocumentParsingError::InvalidWrapperFormat()),
+        }*/
+if let Some(caps) = DOCUMENT_REGEX.captures(source) {
+let doctype = &caps["type"];
+let currency = &caps["currency"];
+
+// TODO : Improve error handling of Signature::from_base64 failure
+
+match doctype {
+"Identity" => IdentityDocumentParser::parse_standard(source, currency),
+"Membership" => MembershipDocumentParser::parse_standard(source, currency),
+"Certification" => CertificationDocumentParser::parse_standard(source, currency),
+"Revocation" => RevocationDocumentParser::parse_standard(source, currency),
+"Transaction" => TransactionDocumentParser::parse_standard(source, currency),
+_ => Err(V10DocumentParsingError::UnknownDocumentType(
+doctype.to_string(),
+)),
 }
+} else {
+Err(V10DocumentParsingError::InvalidWrapperFormat())
+}
+}
+}*/
 
 #[cfg(test)]
 mod tests {
+    use super::certification::CertificationDocumentParser;
+    use super::identity::IdentityDocumentParser;
+    use super::membership::MembershipDocumentParser;
+    use super::revocation::RevocationDocumentParser;
+    use super::transaction::TransactionDocumentParser;
     use super::*;
-    use blockchain::{Document, VerificationResult};
+    use duniter_crypto::keys::*;
+
+    // simple text document for signature testing
+    #[derive(Debug, Clone)]
+    struct PlainTextDocument {
+        pub text: &'static str,
+        pub issuers: Vec<PubKey>,
+        pub signatures: Vec<Sig>,
+    }
 
-    #[test]
-    fn document_regex() {
-        assert!(DOCUMENT_REGEX.is_match(
-            "Version: 10
-Type: Transaction
-Currency: beta_brousouf
-Blockstamp: 204-00003E2B8A35370BA5A7064598F628A62D4E9EC1936BE8651CE9A85F2E06981B
-Locktime: 0
-Issuers:
-HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY
-CYYjHsNyg3HMRMpTHqCJAN9McjH5BwFLmDKGV3PmCuKp
-9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB
-Inputs:
-40:2:T:6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3:2
-70:2:T:3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435:8
-20:2:D:HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY:46
-70:2:T:A0D9B4CDC113ECE1145C5525873821398890AE842F4B318BD076095A23E70956:3
-20:2:T:67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B:5
-15:2:D:9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB:46
-Unlocks:
-0:SIG(0)
-1:XHX(7665798292)
-2:SIG(0)
-3:SIG(0) SIG(2)
-4:SIG(0) SIG(1) SIG(2)
-5:SIG(2)
-Outputs:
-120:2:SIG(BYfWYFrsyjpvpFysgu19rGK3VHBkz4MqmQbNyEuVU64g)
-146:2:SIG(DSz4rgncXCytsUMW2JU2yhLquZECD2XpEkpP9gG5HyAx)
-49:2:(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i)\
- || XHX(3EB4702F2AC2FD3FA4FDC46A4FC05AE8CDEE1A85))
-Comment: -----@@@----- (why not this comment?)
-42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r
-2D96KZwNUvVtcapQPq2mm7J9isFcDCfykwJpVEZwBc7tCgL4qPyu17BT5ePozAE9HS6Yvj51f62Mp4n9d9dkzJoX
-2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk"
-        ));
-
-        assert!(DOCUMENT_REGEX.is_match(
-            "Version: 10
-Type: Certification
-Currency: beta_brousouf
-Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV
-IdtyIssuer: HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd
-IdtyUniqueID: lolcat
-IdtyTimestamp: 32-DB30D958EE5CB75186972286ED3F4686B8A1C2CD
-IdtySignature: J3G9oM5AKYZNLAB5Wx499w61NuUoS57JVccTShUb\
-GpCMjCqj9yXXqNq7dyZpDWA6BxipsiaMZhujMeBfCznzyci
-CertTimestamp: 36-1076F10A7397715D2BEE82579861999EA1F274AC
-SoKwoa8PFfCDJWZ6dNCv7XstezHcc2BbKiJgVDXv82R5zYR83nis9dShLgWJ5w48noVUHimdngzYQneNYSMV3rk"
-        ));
+    impl Document for PlainTextDocument {
+        type PublicKey = PubKey;
+        type CurrencyType = str;
+
+        fn version(&self) -> u16 {
+            unimplemented!()
+        }
+
+        fn currency(&self) -> &str {
+            unimplemented!()
+        }
+
+        fn blockstamp(&self) -> Blockstamp {
+            unimplemented!()
+        }
+
+        fn issuers(&self) -> &Vec<PubKey> {
+            &self.issuers
+        }
+
+        fn signatures(&self) -> &Vec<Sig> {
+            &self.signatures
+        }
+
+        fn as_bytes(&self) -> &[u8] {
+            self.text.as_bytes()
+        }
     }
 
     #[test]
-    fn signatures_regex() {
-        assert_eq!(
-            SIGNATURES_REGEX
-                .captures_iter(
-                    "
-42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r
-2D96KZwNUvVtcapQPq2mm7J9isFcDCfykwJpVEZwBc7tCgL4qPyu17BT5ePozAE9HS6Yvj51f62Mp4n9d9dkzJoX
-2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk"
-                )
-                .count(),
-            3
+    fn verify_signatures() {
+        let text = "Version: 10
+Type: Identity
+Currency: duniter_unit_test_currency
+Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV
+UniqueID: tic
+Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
+";
+
+        // good pair
+        let issuer1 = PubKey::Ed25519(
+            ed25519::PublicKey::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV")
+                .unwrap(),
+        );
+
+        let sig1 = Sig::Ed25519(
+            ed25519::Signature::from_base64(
+                "1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGMM\
+                 mQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==",
+            )
+            .unwrap(),
         );
 
-        assert_eq!(
-            SIGNATURES_REGEX
-                .captures_iter(
-                    "
-42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r
-2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk"
-                )
-                .count(),
-            2
+        // incorrect pair
+        let issuer2 = PubKey::Ed25519(
+            ed25519::PublicKey::from_base58("DNann1Lh55eZMEDXeYt32bzHbA3NJR46DeQYCS2qQdLV")
+                .unwrap(),
         );
+
+        let sig2 = Sig::Ed25519(
+            ed25519::Signature::from_base64(
+                "1eubHHbuNfilHHH0G2bI30iZzebQ2cQ1PC7uPAw08FGMM\
+                 mQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==",
+            )
+            .unwrap(),
+        );
+
+        {
+            let doc = PlainTextDocument {
+                text,
+                issuers: vec![issuer1],
+                signatures: vec![sig1],
+            };
+
+            assert_eq!(doc.verify_signatures(), VerificationResult::Valid());
+        }
+
+        {
+            let doc = PlainTextDocument {
+                text,
+                issuers: vec![issuer1],
+                signatures: vec![sig2],
+            };
+
+            assert_eq!(
+                doc.verify_signatures(),
+                VerificationResult::Invalid(vec![0])
+            );
+        }
+
+        {
+            let doc = PlainTextDocument {
+                text,
+                issuers: vec![issuer1, issuer2],
+                signatures: vec![sig1],
+            };
+
+            assert_eq!(
+                doc.verify_signatures(),
+                VerificationResult::IncompletePairs(2, 1)
+            );
+        }
+
+        {
+            let doc = PlainTextDocument {
+                text,
+                issuers: vec![issuer1],
+                signatures: vec![sig1, sig2],
+            };
+
+            assert_eq!(
+                doc.verify_signatures(),
+                VerificationResult::IncompletePairs(1, 2)
+            );
+        }
     }
 
     #[test]
@@ -349,7 +398,7 @@ UniqueID: elois
 Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
 Ydnclvw76/JHcKSmU9kl9Ie0ne5/X8NYOqPqbGnufIK3eEPRYYdEYaQh+zffuFhbtIRjv6m/DkVLH5cLy/IyAg==";
 
-        let doc = V10DocumentParser::parse(text).unwrap();
+        let doc = IdentityDocumentParser::parse(text, "g1").unwrap();
         if let V10Document::Identity(doc) = doc {
             println!("Doc : {:?}", doc);
             assert_eq!(doc.verify_signatures(), VerificationResult::Valid())
@@ -370,7 +419,7 @@ UserID: elois
 CertTS: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
 FFeyrvYio9uYwY5aMcDGswZPNjGLrl8THn9l3EPKSNySD3SDSHjCljSfFEwb87sroyzJQoVzPwER0sW/cbZMDg==";
 
-        let doc = V10DocumentParser::parse(text).unwrap();
+        let doc = MembershipDocumentParser::parse(text, "g1").unwrap();
         if let V10Document::Membership(doc) = doc {
             println!("Doc : {:?}", doc);
             assert_eq!(doc.verify_signatures(), VerificationResult::Valid())
@@ -392,7 +441,7 @@ IdtySignature: DjeipIeb/RF0tpVCnVnuw6mH1iLJHIsDfPGLR90Twy3PeoaDz6Yzhc/UjLWqHCi5Y
 CertTimestamp: 99956-00000472758331FDA8388E30E50CA04736CBFD3B7C21F34E74707107794B56DD
 Hkps1QU4HxIcNXKT8YmprYTVByBhPP1U2tIM7Z8wENzLKIWAvQClkAvBE7pW9dnVa18sJIJhVZUcRrPAZfmjBA==";
 
-        let doc = V10DocumentParser::parse(text).unwrap();
+        let doc = CertificationDocumentParser::parse(text, "g1").unwrap();
         if let V10Document::Certification(doc) = doc {
             println!("Doc : {:?}", doc);
             assert_eq!(doc.verify_signatures(), VerificationResult::Valid())
@@ -412,7 +461,7 @@ IdtyTimestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B85
 IdtySignature: 1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGMMmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==
 XXOgI++6qpY9O31ml/FcfbXCE6aixIrgkT5jL7kBle3YOMr+8wrp7Rt+z9hDVjrNfYX2gpeJsuMNfG4T/fzVDQ==";
 
-        let doc = V10DocumentParser::parse(text).unwrap();
+        let doc = RevocationDocumentParser::parse(text, "g1").unwrap();
         if let V10Document::Revocation(doc) = doc {
             println!("Doc : {:?}", doc);
             assert_eq!(doc.verify_signatures(), VerificationResult::Valid())
@@ -441,7 +490,7 @@ Outputs:
 Comment: c est pour 2 mois d adhesion ressourcerie
 lnpuFsIymgz7qhKF/GsZ3n3W8ZauAAfWmT4W0iJQBLKJK2GFkesLWeMj/+GBfjD6kdkjreg9M6VfkwIZH+hCCQ==";
 
-        let doc = V10DocumentParser::parse(text).unwrap();
+        let doc = TransactionDocumentParser::parse(text, "g1").unwrap();
         if let V10Document::Transaction(doc) = doc {
             println!("Doc : {:?}", doc);
             assert_eq!(doc.verify_signatures(), VerificationResult::Valid())
diff --git a/documents/blockchain/v10/documents/revocation.rs b/documents/src/v10/revocation.rs
similarity index 63%
rename from documents/blockchain/v10/documents/revocation.rs
rename to documents/src/v10/revocation.rs
index 2b059615dd288fe146d215be1dfb0bbe1382554c..d4ca1983cd9918576f982d9f82201ac168d52dcd 100644
--- a/documents/blockchain/v10/documents/revocation.rs
+++ b/documents/src/v10/revocation.rs
@@ -16,20 +16,11 @@
 //! Wrappers around Revocation documents.
 
 use duniter_crypto::keys::*;
-use regex::Regex;
-
-use blockchain::v10::documents::*;
-use blockchain::{BlockchainProtocol, Document, DocumentBuilder, IntoSpecializedDocument};
-use Blockstamp;
-
-lazy_static! {
-    static ref REVOCATION_REGEX: Regex = Regex::new(
-        "^Issuer: (?P<issuer>[1-9A-Za-z][^OIl]{43,44})\n\
-         IdtyUniqueID: (?P<idty_uid>[[:alnum:]_-]+)\n\
-         IdtyTimestamp: (?P<idty_blockstamp>[0-9]+-[0-9A-F]{64})\n\
-         IdtySignature: (?P<idty_sig>(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?)\n$"
-    ).unwrap();
-}
+use pest::Parser;
+
+use blockstamp::Blockstamp;
+use v10::*;
+use *;
 
 #[derive(Debug, Copy, Clone, Deserialize, Serialize, PartialEq, Eq)]
 /// Wrap an Compact Revocation document (in block content)
@@ -106,7 +97,7 @@ impl Document for RevocationDocument {
     }
 
     fn as_bytes(&self) -> &[u8] {
-        self.as_text().as_bytes()
+        self.as_text_without_signature().as_bytes()
     }
 }
 
@@ -198,26 +189,92 @@ IdtySignature: {idty_sig}
 #[derive(Debug, Clone, Copy)]
 pub struct RevocationDocumentParser;
 
-impl StandardTextDocumentParser for RevocationDocumentParser {
-    fn parse_standard(
-        doc: &str,
-        body: &str,
-        currency: &str,
-        signatures: Vec<Sig>,
-    ) -> Result<V10Document, V10DocumentParsingError> {
-        if let Some(caps) = REVOCATION_REGEX.captures(body) {
+impl TextDocumentParser for RevocationDocumentParser {
+    fn parse(doc: &str, currency: &str) -> Result<V10Document, V10DocumentParsingError> {
+        match DocumentsParser::parse(Rule::revoc, doc) {
+            Ok(mut doc_ast) => {
+                let revoc_ast = doc_ast.next().unwrap(); // get and unwrap the `revoc` rule; never fails
+                let revoc_vx_ast = revoc_ast.into_inner().next().unwrap(); // get and unwrap the `revoc_vX` rule; never fails
+
+                match revoc_vx_ast.as_rule() {
+                    Rule::revoc_v10 => {
+                        let mut pubkeys = Vec::with_capacity(1);
+                        let mut uid = "";
+                        let mut sigs = Vec::with_capacity(2);
+                        let mut blockstamps = Vec::with_capacity(1);
+                        for field in revoc_vx_ast.into_inner() {
+                            match field.as_rule() {
+                                Rule::currency => {
+                                    if currency != field.as_str() {
+                                        return Err(V10DocumentParsingError::InvalidCurrency());
+                                    }
+                                }
+                                Rule::pubkey => {
+                                    if !pubkeys.is_empty() {
+                                        return Err(V10DocumentParsingError::InvalidInnerFormat(
+                                            "Revocation document must contain exactly one pubkey !",
+                                        ));
+                                    }
+                                    pubkeys.push(PubKey::Ed25519(
+                                        ed25519::PublicKey::from_base58(field.as_str()).unwrap(), // Grammar ensures that we have a base58 string.
+                                    ));
+                                }
+                                Rule::uid => {
+                                    uid = field.as_str();
+                                }
+                                Rule::blockstamp => {
+                                    if blockstamps.len() > 1 {
+                                        return Err(V10DocumentParsingError::InvalidInnerFormat(
+                                            "Revocation document must contain exactly one blockstamp !",
+                                        ));
+                                    }
+                                    let mut inner_rules = field.into_inner(); // { integer ~ "-" ~ hash }
+
+                                    let block_id: &str = inner_rules.next().unwrap().as_str();
+                                    let block_hash: &str = inner_rules.next().unwrap().as_str();
+                                    blockstamps.push(Blockstamp {
+                                        id: BlockId(block_id.parse().unwrap()), // Grammar ensures that we have a digits string.
+                                        hash: BlockHash(Hash::from_hex(block_hash).unwrap()), // Grammar ensures that we have an hexadecimal string.
+                                    });
+                                }
+                                Rule::ed25519_sig => {
+                                    sigs.push(Sig::Ed25519(
+                                        ed25519::Signature::from_base64(field.as_str()).unwrap(), // Grammar ensures that we have a base64 string.
+                                    ));
+                                }
+                                Rule::EOI => (),
+                                _ => panic!("unexpected rule"), // Grammar ensures that we never reach this line
+                            }
+                        }
+                        Ok(V10Document::Revocation(Box::new(RevocationDocument {
+                            text: doc.to_owned(),
+                            issuers: vec![pubkeys[0]],
+                            currency: currency.to_owned(),
+                            identity_username: uid.to_owned(),
+                            identity_blockstamp: blockstamps[0],
+                            identity_sig: sigs[0],
+                            signatures: vec![sigs[1]],
+                        })))
+                    }
+                    _ => Err(V10DocumentParsingError::UnexpectedVersion()),
+                }
+            }
+            Err(pest_error) => panic!("{}", pest_error), //Err(V10DocumentParsingError::PestError()),
+        }
+
+        /*if let Some(caps) = REVOCATION_REGEX.captures(body) {
             let issuer = &caps["issuer"];
             let identity_username = &caps["idty_uid"];
             let identity_blockstamp = &caps["idty_blockstamp"];
             let identity_sig = &caps["idty_sig"];
-
+        
             // Regex match so should not fail.
             // TODO : Test it anyway
             let issuer = PubKey::Ed25519(ed25519::PublicKey::from_base58(issuer).unwrap());
             let identity_username = String::from(identity_username);
             let identity_blockstamp = Blockstamp::from_string(identity_blockstamp).unwrap();
             let identity_sig = Sig::Ed25519(Signature::from_base64(identity_sig).unwrap());
-
+        
             Ok(V10Document::Revocation(Box::new(RevocationDocument {
                 text: doc.to_owned(),
                 issuers: vec![issuer],
@@ -228,18 +285,16 @@ impl StandardTextDocumentParser for RevocationDocumentParser {
                 signatures,
             })))
         } else {
-            Err(V10DocumentParsingError::InvalidInnerFormat(
-                "Revocation".to_string(),
-            ))
-        }
+            Err(V10DocumentParsingError::InvalidInnerFormat("Revocation"))
+        }*/
     }
 }
 
 #[cfg(test)]
 mod tests {
     use super::*;
-    use blockchain::VerificationResult;
     use duniter_crypto::keys::{PrivateKey, PublicKey, Signature};
+    use VerificationResult;
 
     #[test]
     fn generate_real_document() {
@@ -288,17 +343,6 @@ mod tests {
         );
     }
 
-    #[test]
-    fn revocation_standard_regex() {
-        assert!(REVOCATION_REGEX.is_match(
-            "Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV
-IdtyUniqueID: tic
-IdtyTimestamp: 98221-000000575AC04F5164F7A307CDB766139EA47DD249E4A2444F292BC8AAB408B3
-IdtySignature: DjeipIeb/RF0tpVCnVnuw6mH1iLJHIsDfPGLR90Twy3PeoaDz6Yzhc/UjLWqHCi5Y6wYajV0dNg4jQRUneVBCQ==
-"
-        ));
-    }
-
     #[test]
     fn revocation_document() {
         let doc = "Version: 10
@@ -308,22 +352,11 @@ Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV
 IdtyUniqueID: tic
 IdtyTimestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
 IdtySignature: 1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGMMmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==
-";
-
-        let body = "Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV
-IdtyUniqueID: tic
-IdtyTimestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
-IdtySignature: 1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGMMmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==
-";
+XXOgI++6qpY9O31ml/FcfbXCE6aixIrgkT5jL7kBle3YOMr+8wrp7Rt+z9hDVjrNfYX2gpeJsuMNfG4T/fzVDQ==";
 
         let currency = "g1";
 
-        let signatures = vec![Sig::Ed25519(ed25519::Signature::from_base64(
-"XXOgI++6qpY9O31ml/FcfbXCE6aixIrgkT5jL7kBle3YOMr+8wrp7Rt+z9hDVjrNfYX2gpeJsuMNfG4T/fzVDQ=="
-        ).unwrap())];
-
-        let doc =
-            RevocationDocumentParser::parse_standard(doc, body, currency, signatures).unwrap();
+        let doc = RevocationDocumentParser::parse(doc, currency).unwrap();
         if let V10Document::Revocation(doc) = doc {
             println!("Doc : {:?}", doc);
             assert_eq!(doc.verify_signatures(), VerificationResult::Valid())
diff --git a/documents/blockchain/v10/documents/transaction.rs b/documents/src/v10/transaction.rs
similarity index 62%
rename from documents/blockchain/v10/documents/transaction.rs
rename to documents/src/v10/transaction.rs
index 077e335036cb48cf1f98198d922692760799e67b..8969526018579cf0970d60c5adf6bd35da745e9a 100644
--- a/documents/blockchain/v10/documents/transaction.rs
+++ b/documents/src/v10/transaction.rs
@@ -15,44 +15,17 @@
 
 //! Wrappers around Transaction documents.
 
-use blockchain::v10::documents::*;
-use blockchain::{BlockchainProtocol, Document, DocumentBuilder, IntoSpecializedDocument};
 use crypto::digest::Digest;
 use crypto::sha2::Sha256;
-use regex::Regex;
-use regex::RegexBuilder;
+use pest::iterators::Pair;
+use pest::iterators::Pairs;
+use pest::Parser;
 use std::ops::{Add, Deref, Sub};
 use std::str::FromStr;
-use {BlockId, Blockstamp, Hash};
-
-lazy_static! {
-    static ref TRANSACTION_REGEX_SIZE: &'static usize = &40_000_000;
-    static ref TRANSACTION_REGEX_BUILDER: &'static str =
-        r"^Blockstamp: (?P<blockstamp>[0-9]+-[0-9A-F]{64})\nLocktime: (?P<locktime>[0-9]+)\nIssuers:(?P<issuers>(?:\n[1-9A-Za-z][^OIl]{43,44})+)Inputs:\n(?P<inputs>([0-9A-Za-z:]+\n)+)Unlocks:\n(?P<unlocks>([0-9]+:(SIG\([0-9]+\) ?|XHX\(\w+\) ?)+\n)+)Outputs:\n(?P<outputs>([0-9A-Za-z()&|: ]+\n)+)Comment: (?P<comment>[\\\w:/;*\[\]()?!^+=@&~#{}|<>%. -]{0,255})\n";
-    static ref ISSUER_REGEX: Regex = Regex::new("(?P<issuer>[1-9A-Za-z]{43,44})\n").unwrap();
-    static ref D_INPUT_REGEX: Regex = Regex::new(
-        "^(?P<amount>[1-9][0-9]*):(?P<base>[0-9]+):D:(?P<pubkey>[1-9A-Za-z]{43,44}):(?P<block_number>[0-9]+)$"
-    ).unwrap();
-    static ref T_INPUT_REGEX: Regex = Regex::new(
-        "^(?P<amount>[1-9][0-9]*):(?P<base>[0-9]+):T:(?P<tx_hash>[0-9A-F]{64}):(?P<tx_index>[0-9]+)$"
-    ).unwrap();
-    static ref UNLOCKS_REGEX: Regex = Regex::new(
-        r"^(?P<index>[0-9]+):(?P<unlocks>(SIG\([0-9]+\) ?|XHX\(\w+\) ?)+)$"
-    ).unwrap();
-    static ref UNLOCK_SIG_REGEX: Regex =
-        Regex::new(r"^SIG\((?P<index>[0-9]+)\)$").unwrap();
-    static ref UNLOCK_XHX_REGEX: Regex = Regex::new(r"^XHX\((?P<code>\w+)\)$").unwrap();
-    static ref OUTPUT_COND_SIG_REGEX: Regex = Regex::new(r"^SIG\((?P<pubkey>[1-9A-Za-z]{43,44})\)*$").unwrap();
-    static ref OUTPUT_COND_XHX_REGEX: Regex = Regex::new(r"^XHX\((?P<hash>[0-9A-F]{64})\)*$").unwrap();
-    static ref OUTPUT_COND_CLTV_REGEX: Regex = Regex::new(r"^CLTV\((?P<timestamp>[0-9]+)\)*$").unwrap();
-    static ref OUTPUT_COND_CSV_REGEX: Regex = Regex::new(r"^CSV\((?P<duration>[0-9]+)\)*$").unwrap();
-    static ref OUPUT_CONDS_BRAKETS: Regex = Regex::new(r"^\((?P<conditions>[0-9A-Za-z()&| ]+)\)$").unwrap();
-    static ref OUPUT_CONDS_AND: Regex = Regex::new(r"^(?P<conditions_group_1>[0-9A-Za-z()&| ]+) && (?P<conditions_group_2>[0-9A-Za-z()&| ]+)$").unwrap();
-    static ref OUPUT_CONDS_OR: Regex = Regex::new(r"^(?P<conditions_group_1>[0-9A-Za-z()&| ]+) \|\| (?P<conditions_group_2>[0-9A-Za-z()&| ]+)$").unwrap();
-    static ref OUTPUT_REGEX: Regex = Regex::new(
-        "^(?P<amount>[1-9][0-9]*):(?P<base>[0-9]+):(?P<conditions>[0-9A-Za-z()&| ]+)$"
-    ).unwrap();
-}
+
+use blockstamp::Blockstamp;
+use v10::*;
+use *;
 
 /// Wrap a transaction amount
 #[derive(Debug, Copy, Clone, Eq, Ord, PartialEq, PartialOrd, Deserialize, Hash, Serialize)]
@@ -103,8 +76,55 @@ impl ToString for TransactionInput {
 }
 
 impl TransactionInput {
+    fn from_pest_pairs(mut pairs: Pairs<Rule>) -> TransactionInput {
+        let tx_input_type_pair = pairs.next().unwrap();
+        match tx_input_type_pair.as_rule() {
+            Rule::tx_input_du => {
+                let mut inner_rules = tx_input_type_pair.into_inner(); // ${ tx_amount ~ ":" ~ tx_amount_base ~ ":D:" ~ pubkey ~ ":" ~ du_block_id }
+
+                TransactionInput::D(
+                    TxAmount(inner_rules.next().unwrap().as_str().parse().unwrap()),
+                    TxBase(inner_rules.next().unwrap().as_str().parse().unwrap()),
+                    PubKey::Ed25519(
+                        ed25519::PublicKey::from_base58(inner_rules.next().unwrap().as_str())
+                            .unwrap(),
+                    ),
+                    BlockId(inner_rules.next().unwrap().as_str().parse().unwrap()),
+                )
+            }
+            Rule::tx_input_tx => {
+                let mut inner_rules = tx_input_type_pair.into_inner(); // ${ tx_amount ~ ":" ~ tx_amount_base ~ ":D:" ~ pubkey ~ ":" ~ du_block_id }
+
+                TransactionInput::T(
+                    TxAmount(inner_rules.next().unwrap().as_str().parse().unwrap()),
+                    TxBase(inner_rules.next().unwrap().as_str().parse().unwrap()),
+                    Hash::from_hex(inner_rules.next().unwrap().as_str()).unwrap(),
+                    TxIndex(inner_rules.next().unwrap().as_str().parse().unwrap()),
+                )
+            }
+            _ => panic!("unexpected rule: {:?}", tx_input_type_pair.as_rule()), // Grammar ensures that we never reach this line
+        }
+    }
+}
+
+impl FromStr for TransactionInput {
+    type Err = V10DocumentParsingError;
+
+    fn from_str(source: &str) -> Result<Self, Self::Err> {
+        match DocumentsParser::parse(Rule::tx_input, source) {
+            Ok(mut pairs) => Ok(TransactionInput::from_pest_pairs(
+                pairs.next().unwrap().into_inner(),
+            )),
+            Err(_) => Err(V10DocumentParsingError::InvalidInnerFormat(
+                "Invalid unlocks !",
+            )),
+        }
+    }
+}
+
+/*impl TransactionInput {
     /// Parse Transaction Input from string.
-    pub fn parse_from_str(source: &str) -> Result<TransactionInput, V10DocumentParsingError> {
+    pub fn from_str(source: &str) -> Result<TransactionInput, V10DocumentParsingError> {
         if let Some(caps) = D_INPUT_REGEX.captures(source) {
             let amount = &caps["amount"];
             let base = &caps["base"];
@@ -136,12 +156,10 @@ impl TransactionInput {
             ))
         } else {
             println!("Fail to parse this input = {:?}", source);
-            Err(V10DocumentParsingError::InvalidInnerFormat(String::from(
-                "Transaction2",
-            )))
+            Err(V10DocumentParsingError::InvalidInnerFormat("Transaction2"))
         }
     }
-}
+}*/
 
 /// Wrap a transaction unlock proof
 #[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
@@ -161,24 +179,6 @@ impl ToString for TransactionUnlockProof {
     }
 }
 
-impl TransactionUnlockProof {
-    fn parse_from_str(source: &str) -> Result<TransactionUnlockProof, V10DocumentParsingError> {
-        if let Some(caps) = UNLOCK_SIG_REGEX.captures(source) {
-            let index = &caps["index"];
-            Ok(TransactionUnlockProof::Sig(
-                index.parse().expect("fail to parse SIG unlock"),
-            ))
-        } else if let Some(caps) = UNLOCK_XHX_REGEX.captures(source) {
-            let code = &caps["code"];
-            Ok(TransactionUnlockProof::Xhx(String::from(code)))
-        } else {
-            Err(V10DocumentParsingError::InvalidInnerFormat(String::from(
-                "Transaction3",
-            )))
-        }
-    }
-}
-
 /// Wrap a transaction unlocks input
 #[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
 pub struct TransactionInputUnlocks {
@@ -201,28 +201,46 @@ impl ToString for TransactionInputUnlocks {
 }
 
 impl TransactionInputUnlocks {
-    /// Parse Transaction Unlock from string.
-    pub fn parse_from_str(
-        source: &str,
-    ) -> Result<TransactionInputUnlocks, V10DocumentParsingError> {
-        if let Some(caps) = UNLOCKS_REGEX.captures(source) {
-            let index = &caps["index"].parse().expect("fail to parse unlock index");
-            let unlocks = &caps["unlocks"];
-
-            let unlocks_array: Vec<&str> = unlocks.split(' ').collect();
-            let mut unlocks = Vec::new();
-            for unlock in unlocks_array {
-                unlocks.push(TransactionUnlockProof::parse_from_str(unlock)?);
+    fn from_pest_pairs(pairs: Pairs<Rule>) -> TransactionInputUnlocks {
+        let mut input_index = 0;
+        let mut unlock_conds = Vec::new();
+        for unlock_field in pairs {
+            // ${ input_index ~ ":" ~ unlock_cond ~ (" " ~ unlock_cond)* }
+            match unlock_field.as_rule() {
+                Rule::input_index => input_index = unlock_field.as_str().parse().unwrap(),
+                Rule::unlock_sig => unlock_conds.push(TransactionUnlockProof::Sig(
+                    unlock_field
+                        .into_inner()
+                        .next()
+                        .unwrap()
+                        .as_str()
+                        .parse()
+                        .unwrap(),
+                )),
+                Rule::unlock_xhx => unlock_conds.push(TransactionUnlockProof::Xhx(String::from(
+                    unlock_field.into_inner().next().unwrap().as_str(),
+                ))),
+                _ => panic!("unexpected rule: {:?}", unlock_field.as_rule()), // Grammar ensures that we never reach this line
             }
-            Ok(TransactionInputUnlocks {
-                index: *index,
-                unlocks,
-            })
-        } else {
-            println!("Fail to parse this unlock = {:?}", source);
-            Err(V10DocumentParsingError::InvalidInnerFormat(String::from(
-                "Transaction4",
-            )))
+        }
+        TransactionInputUnlocks {
+            index: input_index,
+            unlocks: unlock_conds,
+        }
+    }
+}
+
+impl FromStr for TransactionInputUnlocks {
+    type Err = V10DocumentParsingError;
+
+    fn from_str(source: &str) -> Result<Self, Self::Err> {
+        match DocumentsParser::parse(Rule::tx_unlock, source) {
+            Ok(mut pairs) => Ok(TransactionInputUnlocks::from_pest_pairs(
+                pairs.next().unwrap().into_inner(),
+            )),
+            Err(_) => Err(V10DocumentParsingError::InvalidInnerFormat(
+                "Invalid unlocks !",
+            )),
         }
     }
 }
@@ -251,48 +269,6 @@ impl ToString for TransactionOutputCondition {
     }
 }
 
-impl TransactionOutputCondition {
-    fn parse_from_str(source: &str) -> Result<TransactionOutputCondition, V10DocumentParsingError> {
-        if let Some(caps) = OUTPUT_COND_SIG_REGEX.captures(source) {
-            if let Ok(pubkey) = ed25519::PublicKey::from_base58(&caps["pubkey"]) {
-                Ok(TransactionOutputCondition::Sig(PubKey::Ed25519(pubkey)))
-            } else {
-                Err(V10DocumentParsingError::InvalidInnerFormat(String::from(
-                    "OutputCondition : Fail to parse SIG pubkey.",
-                )))
-            }
-        } else if let Some(caps) = OUTPUT_COND_XHX_REGEX.captures(source) {
-            if let Ok(hash) = Hash::from_hex(&caps["hash"]) {
-                Ok(TransactionOutputCondition::Xhx(hash))
-            } else {
-                Err(V10DocumentParsingError::InvalidInnerFormat(String::from(
-                    "OutputCondition : Fail to parse XHX Hash.",
-                )))
-            }
-        } else if let Some(caps) = OUTPUT_COND_CLTV_REGEX.captures(source) {
-            if let Ok(timestamp) = caps["timestamp"].parse() {
-                Ok(TransactionOutputCondition::Cltv(timestamp))
-            } else {
-                Err(V10DocumentParsingError::InvalidInnerFormat(String::from(
-                    "OutputCondition : Fail to parse CLTV timestamp.",
-                )))
-            }
-        } else if let Some(caps) = OUTPUT_COND_CSV_REGEX.captures(source) {
-            if let Ok(duration) = caps["duration"].parse() {
-                Ok(TransactionOutputCondition::Csv(duration))
-            } else {
-                Err(V10DocumentParsingError::InvalidInnerFormat(String::from(
-                    "OutputCondition : Fail to parse CSV duraion.",
-                )))
-            }
-        } else {
-            Err(V10DocumentParsingError::InvalidInnerFormat(
-                "Transaction5".to_string(),
-            ))
-        }
-    }
-}
-
 /// Wrap an utxo conditions
 #[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
 pub struct UTXOConditions {
@@ -329,17 +305,6 @@ impl ToString for UTXOConditions {
     }
 }
 
-impl ::std::str::FromStr for UTXOConditions {
-    type Err = V10DocumentParsingError;
-
-    fn from_str(source: &str) -> Result<Self, Self::Err> {
-        Ok(UTXOConditions {
-            origin_str: Some(String::from(source)),
-            conditions: UTXOConditionsGroup::from_str(source)?,
-        })
-    }
-}
-
 /// Wrap a transaction ouput condition group
 #[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
 pub enum UTXOConditionsGroup {
@@ -353,6 +318,79 @@ pub enum UTXOConditionsGroup {
     Or(Box<UTXOConditionsGroup>, Box<UTXOConditionsGroup>),
 }
 
+macro_rules! utxo_conds_wrap_op_chain {
+    ($op:expr, $fn_name:ident) => {
+        fn $fn_name(conds_subgroups: &mut Vec<UTXOConditionsGroup>) -> UTXOConditionsGroup {
+            if conds_subgroups.len() == 2 {
+                $op(
+                    Box::new(conds_subgroups[0].clone()),
+                    Box::new(conds_subgroups[1].clone()),
+                )
+            } else if conds_subgroups.len() > 2 {
+                let last_subgroup = conds_subgroups.pop().unwrap();
+                let previous_last_subgroup = conds_subgroups.pop().unwrap();
+                conds_subgroups.push($op(
+                    Box::new(previous_last_subgroup),
+                    Box::new(last_subgroup),
+                ));
+                UTXOConditionsGroup::$fn_name(conds_subgroups)
+            } else {
+                panic!(
+                    "Grammar should ensure that and chain contains at least two conditions subgroups !"
+                )
+            }
+        }
+    }
+}
+
+impl UTXOConditionsGroup {
+    /// Wrap UTXO and chain
+    utxo_conds_wrap_op_chain!(UTXOConditionsGroup::And, new_and_chain);
+    /// Wrap UTXO or chain
+    utxo_conds_wrap_op_chain!(UTXOConditionsGroup::Or, new_or_chain);
+
+    /// Wrap UTXO conditions
+    pub fn wrap_utxo_conds(pair: Pair<Rule>) -> UTXOConditionsGroup {
+        match pair.as_rule() {
+            Rule::output_and_group => {
+                let mut and_pairs = pair.into_inner();
+                let mut conds_subgroups: Vec<UTXOConditionsGroup> = and_pairs
+                    .map(UTXOConditionsGroup::wrap_utxo_conds)
+                    .collect();
+                UTXOConditionsGroup::Brackets(Box::new(UTXOConditionsGroup::new_and_chain(
+                    &mut conds_subgroups,
+                )))
+            }
+            Rule::output_or_group => {
+                let mut or_pairs = pair.into_inner();
+                let mut conds_subgroups: Vec<UTXOConditionsGroup> =
+                    or_pairs.map(UTXOConditionsGroup::wrap_utxo_conds).collect();
+                UTXOConditionsGroup::Brackets(Box::new(UTXOConditionsGroup::new_or_chain(
+                    &mut conds_subgroups,
+                )))
+            }
+            Rule::output_cond_sig => {
+                UTXOConditionsGroup::Single(TransactionOutputCondition::Sig(PubKey::Ed25519(
+                    ed25519::PublicKey::from_base58(pair.into_inner().next().unwrap().as_str())
+                        .unwrap(),
+                )))
+            }
+            Rule::output_cond_xhx => UTXOConditionsGroup::Single(TransactionOutputCondition::Xhx(
+                Hash::from_hex(pair.into_inner().next().unwrap().as_str()).unwrap(),
+            )),
+            Rule::output_cond_csv => UTXOConditionsGroup::Single(TransactionOutputCondition::Csv(
+                pair.into_inner().next().unwrap().as_str().parse().unwrap(),
+            )),
+            Rule::output_cond_cltv => {
+                UTXOConditionsGroup::Single(TransactionOutputCondition::Cltv(
+                    pair.into_inner().next().unwrap().as_str().parse().unwrap(),
+                ))
+            }
+            _ => panic!("unexpected rule: {:?}", pair.as_rule()), // Grammar ensures that we never reach this line
+        }
+    }
+}
+
 impl ToString for UTXOConditionsGroup {
     fn to_string(&self) -> String {
         match *self {
@@ -374,38 +412,6 @@ impl ToString for UTXOConditionsGroup {
     }
 }
 
-impl ::std::str::FromStr for UTXOConditionsGroup {
-    type Err = V10DocumentParsingError;
-
-    fn from_str(conditions: &str) -> Result<Self, Self::Err> {
-        if let Ok(single_condition) = TransactionOutputCondition::parse_from_str(conditions) {
-            Ok(UTXOConditionsGroup::Single(single_condition))
-        } else if let Some(caps) = OUPUT_CONDS_BRAKETS.captures(conditions) {
-            let inner_conditions = UTXOConditionsGroup::from_str(&caps["conditions"])?;
-            Ok(UTXOConditionsGroup::Brackets(Box::new(inner_conditions)))
-        } else if let Some(caps) = OUPUT_CONDS_AND.captures(conditions) {
-            let conditions_group_1 = UTXOConditionsGroup::from_str(&caps["conditions_group_1"])?;
-            let conditions_group_2 = UTXOConditionsGroup::from_str(&caps["conditions_group_2"])?;
-            Ok(UTXOConditionsGroup::And(
-                Box::new(conditions_group_1),
-                Box::new(conditions_group_2),
-            ))
-        } else if let Some(caps) = OUPUT_CONDS_OR.captures(conditions) {
-            let conditions_group_1 = UTXOConditionsGroup::from_str(&caps["conditions_group_1"])?;
-            let conditions_group_2 = UTXOConditionsGroup::from_str(&caps["conditions_group_2"])?;
-            Ok(UTXOConditionsGroup::Or(
-                Box::new(conditions_group_1),
-                Box::new(conditions_group_2),
-            ))
-        } else {
-            println!("fail to parse this output condition = {:?}", conditions);
-            Err(V10DocumentParsingError::InvalidInnerFormat(String::from(
-                "Transaction6",
-            )))
-        }
-    }
-}
-
 /// Wrap a transaction ouput
 #[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
 pub struct TransactionOutput {
@@ -440,21 +446,33 @@ impl ToString for TransactionOutput {
 }
 
 impl TransactionOutput {
-    /// Parse Transaction Output from string.
-    pub fn parse_from_str(source: &str) -> Result<TransactionOutput, V10DocumentParsingError> {
-        if let Some(caps) = OUTPUT_REGEX.captures(source) {
-            let amount = TxAmount(caps["amount"].parse().expect("fail to parse output amount"));
-            let base = TxBase(caps["base"].parse().expect("fail to parse base amount"));
-            let conditions = UTXOConditions::from_str(&caps["conditions"])?;
-            Ok(TransactionOutput {
-                conditions,
-                amount,
-                base,
-            })
-        } else {
-            Err(V10DocumentParsingError::InvalidInnerFormat(
-                "Transaction7".to_string(),
-            ))
+    fn from_pest_pairs(mut utxo_pairs: Pairs<Rule>) -> TransactionOutput {
+        let amount = TxAmount(utxo_pairs.next().unwrap().as_str().parse().unwrap());
+        let base = TxBase(utxo_pairs.next().unwrap().as_str().parse().unwrap());
+        let conditions_pairs = utxo_pairs.next().unwrap();
+        let conditions_origin_str = conditions_pairs.as_str();
+        TransactionOutput {
+            amount,
+            base,
+            conditions: UTXOConditions {
+                origin_str: Some(String::from(conditions_origin_str)),
+                conditions: UTXOConditionsGroup::wrap_utxo_conds(conditions_pairs),
+            },
+        }
+    }
+}
+
+impl FromStr for TransactionOutput {
+    type Err = V10DocumentParsingError;
+
+    fn from_str(source: &str) -> Result<Self, Self::Err> {
+        match DocumentsParser::parse(Rule::tx_output, source) {
+            Ok(mut utxo_pairs) => Ok(TransactionOutput::from_pest_pairs(
+                utxo_pairs.next().unwrap().into_inner(),
+            )),
+            Err(_) => Err(V10DocumentParsingError::InvalidInnerFormat(
+                "Invalid output !",
+            )),
         }
     }
 }
@@ -563,7 +581,7 @@ impl Document for TransactionDocument {
     }
 
     fn as_bytes(&self) -> &[u8] {
-        self.as_text().as_bytes()
+        self.as_text_without_signature().as_bytes()
     }
 }
 
@@ -743,72 +761,80 @@ Issuers:
 #[derive(Debug, Clone, Copy)]
 pub struct TransactionDocumentParser;
 
-impl StandardTextDocumentParser for TransactionDocumentParser {
-    fn parse_standard(
-        doc: &str,
-        body: &str,
-        currency: &str,
-        signatures: Vec<Sig>,
-    ) -> Result<V10Document, V10DocumentParsingError> {
-        let tx_regex: Regex = RegexBuilder::new(&TRANSACTION_REGEX_BUILDER)
-            .size_limit(**TRANSACTION_REGEX_SIZE)
-            .build()
-            .expect("fail to build TRANSACTION_REGEX !");
-        if let Some(caps) = tx_regex.captures(body) {
-            let blockstamp =
-                Blockstamp::from_string(&caps["blockstamp"]).expect("fail to parse blockstamp");
-            let locktime = caps["locktime"].parse().expect("fail to parse locktime");
-            let issuers_str = &caps["issuers"];
-            let inputs = &caps["inputs"];
-            let unlocks = &caps["unlocks"];
-            let outputs = &caps["outputs"];
-            let comment = String::from(&caps["comment"]);
-
-            let mut issuers = Vec::new();
-            for caps in ISSUER_REGEX.captures_iter(issuers_str) {
-                issuers.push(PubKey::Ed25519(
-                    ed25519::PublicKey::from_base58(&caps["issuer"]).expect("fail to parse issuer"),
-                ));
-            }
-            let inputs_array: Vec<&str> = inputs.split('\n').collect();
-            let mut inputs = Vec::new();
-            for input in inputs_array {
-                if !input.is_empty() {
-                    inputs.push(TransactionInput::parse_from_str(input)?);
-                }
-            }
-            let unlocks_array: Vec<&str> = unlocks.split('\n').collect();
-            let mut unlocks = Vec::new();
-            for unlock in unlocks_array {
-                if !unlock.is_empty() {
-                    unlocks.push(TransactionInputUnlocks::parse_from_str(unlock)?);
+impl TextDocumentParser for TransactionDocumentParser {
+    fn parse(doc: &str, currency: &str) -> Result<V10Document, V10DocumentParsingError> {
+        match DocumentsParser::parse(Rule::tx, doc) {
+            Ok(mut doc_ast) => {
+                let tx_ast = doc_ast.next().unwrap(); // get and unwrap the `tx` rule; never fails
+                let tx_vx_ast = tx_ast.into_inner().next().unwrap(); // get and unwrap the `tx_vX` rule; never fails
+
+                match tx_vx_ast.as_rule() {
+                    Rule::tx_v10 => {
+                        let mut blockstamp = Blockstamp::default();
+                        let mut locktime = 0;
+                        let mut issuers = Vec::new();
+                        let mut inputs = Vec::new();
+                        let mut unlocks = Vec::new();
+                        let mut outputs = Vec::new();
+                        let mut comment = "";
+                        let mut sigs = Vec::new();
+
+                        for field in tx_vx_ast.into_inner() {
+                            match field.as_rule() {
+                                Rule::currency => {
+                                    if currency != field.as_str() {
+                                        return Err(V10DocumentParsingError::InvalidCurrency());
+                                    }
+                                }
+                                Rule::blockstamp => {
+                                    let mut inner_rules = field.into_inner(); // ${ block_id ~ "-" ~ hash }
+
+                                    let block_id: &str = inner_rules.next().unwrap().as_str();
+                                    let block_hash: &str = inner_rules.next().unwrap().as_str();
+                                    blockstamp = Blockstamp {
+                                        id: BlockId(block_id.parse().unwrap()), // Grammar ensures that we have a digits string.
+                                        hash: BlockHash(Hash::from_hex(block_hash).unwrap()), // Grammar ensures that we have an hexadecimal string.
+                                    };
+                                }
+                                Rule::tx_locktime => locktime = field.as_str().parse().unwrap(), // Grammar ensures that we have digits characters.
+                                Rule::pubkey => issuers.push(PubKey::Ed25519(
+                                    ed25519::PublicKey::from_base58(field.as_str()).unwrap(), // Grammar ensures that we have a base58 string.
+                                )),
+                                Rule::tx_input => inputs
+                                    .push(TransactionInput::from_pest_pairs(field.into_inner())),
+                                Rule::tx_unlock => unlocks.push(
+                                    TransactionInputUnlocks::from_pest_pairs(field.into_inner()),
+                                ),
+                                Rule::tx_output => outputs
+                                    .push(TransactionOutput::from_pest_pairs(field.into_inner())),
+                                Rule::tx_comment => comment = field.as_str(),
+                                Rule::ed25519_sig => {
+                                    sigs.push(Sig::Ed25519(
+                                        ed25519::Signature::from_base64(field.as_str()).unwrap(), // Grammar ensures that we have a base64 string.
+                                    ));
+                                }
+                                Rule::EOI => (),
+                                _ => panic!("unexpected rule: {:?}", field.as_rule()), // Grammar ensures that we never reach this line
+                            }
+                        }
+                        Ok(V10Document::Transaction(Box::new(TransactionDocument {
+                            text: Some(doc.to_owned()),
+                            currency: currency.to_owned(),
+                            blockstamp,
+                            locktime,
+                            issuers,
+                            inputs,
+                            unlocks,
+                            outputs,
+                            comment: comment.to_owned(),
+                            signatures: sigs,
+                            hash: None,
+                        })))
+                    }
+                    _ => Err(V10DocumentParsingError::UnexpectedVersion()),
                 }
             }
-            let outputs_array: Vec<&str> = outputs.split('\n').collect();
-            let mut outputs = Vec::new();
-            for output in outputs_array {
-                if !output.is_empty() {
-                    outputs.push(TransactionOutput::parse_from_str(output)?);
-                }
-            }
-
-            Ok(V10Document::Transaction(Box::new(TransactionDocument {
-                text: Some(doc.to_owned()),
-                currency: currency.to_owned(),
-                blockstamp,
-                locktime,
-                issuers,
-                inputs,
-                unlocks,
-                outputs,
-                comment,
-                signatures,
-                hash: None,
-            })))
-        } else {
-            Err(V10DocumentParsingError::InvalidInnerFormat(
-                "Transaction1".to_string(),
-            ))
+            Err(pest_error) => panic!("{}", pest_error), //Err(V10DocumentParsingError::PestError()),
         }
     }
 }
@@ -816,7 +842,7 @@ impl StandardTextDocumentParser for TransactionDocumentParser {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use blockchain::{Document, VerificationResult};
+    use {Document, VerificationResult};
 
     #[test]
     fn generate_real_document() {
@@ -847,13 +873,20 @@ mod tests {
             blockstamp: &block,
             locktime: &0,
             issuers: &vec![pubkey],
-            inputs: &vec![TransactionInput::parse_from_str(
-                "10:0:D:DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV:0",
-            )
-            .expect("fail to parse input !")],
-            unlocks: &vec![TransactionInputUnlocks::parse_from_str("0:SIG(0)")
-                .expect("fail to parse unlock !")],
-            outputs: &vec![TransactionOutput::parse_from_str(
+            inputs: &vec![TransactionInput::D(
+                TxAmount(10),
+                TxBase(0),
+                PubKey::Ed25519(
+                    ed25519::PublicKey::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV")
+                        .unwrap(),
+                ),
+                BlockId(0),
+            )],
+            unlocks: &vec![TransactionInputUnlocks {
+                index: 0,
+                unlocks: vec![TransactionUnlockProof::Sig(0)],
+            }],
+            outputs: &vec![TransactionOutput::from_str(
                 "10:0:SIG(FD9wujR7KABw88RyKEGBYRLz8PA6jzVCbcBAsrBXBqSa)",
             )
             .expect("fail to parse output !")],
@@ -895,18 +928,22 @@ mod tests {
             blockstamp: &block,
             locktime: &0,
             issuers: &vec![pubkey],
-            inputs: &vec![TransactionInput::parse_from_str(
-                "950:0:T:2CF1ACD8FE8DC93EE39A1D55881C50D87C55892AE8E4DB71D4EBAB3D412AA8FD:1",
-            )
-            .expect("fail to parse input !")],
-            unlocks: &vec![TransactionInputUnlocks::parse_from_str("0:SIG(0)")
-                .expect("fail to parse unlock !")],
+            inputs: &vec![TransactionInput::T(
+                TxAmount(950),
+                TxBase(0),
+                Hash::from_hex("2CF1ACD8FE8DC93EE39A1D55881C50D87C55892AE8E4DB71D4EBAB3D412AA8FD")
+                    .unwrap(),
+                TxIndex(1),
+            )],
+            unlocks: &vec![
+                TransactionInputUnlocks::from_str("0:SIG(0)").expect("fail to parse unlock !")
+            ],
             outputs: &vec![
-                TransactionOutput::parse_from_str(
+                TransactionOutput::from_str(
                     "30:0:SIG(38MEAZN68Pz1DTvT3tqgxx4yQP6snJCQhPqEFxbDk4aE)",
                 )
                 .expect("fail to parse output !"),
-                TransactionOutput::parse_from_str(
+                TransactionOutput::from_str(
                     "920:0:SIG(FEkbc4BfJukSWnCU6Hed6dgwwTuPFTVdgz5LpL4iHr9J)",
                 )
                 .expect("fail to parse output !"),
@@ -924,42 +961,6 @@ mod tests {
         );
     }
 
-    #[test]
-    fn transaction_standard_regex() {
-        let tx_regex: Regex = RegexBuilder::new(&TRANSACTION_REGEX_BUILDER)
-            .size_limit(**TRANSACTION_REGEX_SIZE)
-            .build()
-            .expect("fail to build TRANSACTION_REGEX !");
-        assert!(tx_regex.is_match(
-            "Blockstamp: 204-00003E2B8A35370BA5A7064598F628A62D4E9EC1936BE8651CE9A85F2E06981B
-Locktime: 0
-Issuers:
-HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY
-CYYjHsNyg3HMRMpTHqCJAN9McjH5BwFLmDKGV3PmCuKp
-FD9wujR7KABw88RyKEGBYRLz8PA6jzVCbcBAsrBXBqSa
-Inputs:
-40:2:T:6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3:2
-70:2:T:3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435:8
-20:2:D:HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY:46
-70:2:T:A0D9B4CDC113ECE1145C5525873821398890AE842F4B318BD076095A23E70956:3
-20:2:T:67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B:5
-15:2:D:FD9wujR7KABw88RyKEGBYRLz8PA6jzVCbcBAsrBXBqSa:46
-Unlocks:
-0:SIG(0)
-1:XHX(7665798292)
-2:SIG(0)
-3:SIG(0) SIG(2)
-4:SIG(0) SIG(1) SIG(2)
-5:SIG(2)
-Outputs:
-120:2:SIG(BYfWYFrsyjpvpFysgu19rGK3VHBkz4MqmQbNyEuVU64g)
-146:2:SIG(DSz4rgncXCytsUMW2JU2yhLquZECD2XpEkpP9gG5HyAx)
-49:2:(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) || XHX(3EB4702F2AC2FD3FA4FDC46A4FC05AE8CDEE1A85))
-Comment: -----@@@----- (why not this comment?)
-"
-        ));
-    }
-
     #[test]
     fn parse_transaction_document() {
         let doc = "Version: 10
@@ -990,51 +991,13 @@ Outputs:
 146:2:SIG(DSz4rgncXCytsUMW2JU2yhLquZECD2XpEkpP9gG5HyAx)
 49:2:(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) || XHX(3EB4702F2AC2FD3FA4FDC46A4FC05AE8CDEE1A85F2AC2FD3FA4FDC46A4FC01CA))
 Comment: -----@@@----- (why not this comment?)
-";
-
-        let body =
-            "Blockstamp: 204-00003E2B8A35370BA5A7064598F628A62D4E9EC1936BE8651CE9A85F2E06981B
-Locktime: 0
-Issuers:
-DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV
-4tNQ7d9pj2Da5wUVoW9mFn7JjuPoowF977au8DdhEjVR
-FD9wujR7KABw88RyKEGBYRLz8PA6jzVCbcBAsrBXBqSa
-Inputs:
-40:2:T:6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3:2
-70:2:T:3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435:8
-20:2:D:DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV:46
-70:2:T:A0D9B4CDC113ECE1145C5525873821398890AE842F4B318BD076095A23E70956:3
-20:2:T:67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B:5
-15:2:D:FD9wujR7KABw88RyKEGBYRLz8PA6jzVCbcBAsrBXBqSa:46
-Unlocks:
-0:SIG(0)
-1:XHX(7665798292)
-2:SIG(0)
-3:SIG(0) SIG(2)
-4:SIG(0) SIG(1) SIG(2)
-5:SIG(2)
-Outputs:
-120:2:SIG(BYfWYFrsyjpvpFysgu19rGK3VHBkz4MqmQbNyEuVU64g)
-146:2:SIG(DSz4rgncXCytsUMW2JU2yhLquZECD2XpEkpP9gG5HyAx)
-49:2:(SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) || XHX(3EB4702F2AC2FD3FA4FDC46A4FC05AE8CDEE1A85F2AC2FD3FA4FDC46A4FC01CA))
-Comment: -----@@@----- (why not this comment?)
-";
+kL59C1izKjcRN429AlKdshwhWbasvyL7sthI757zm1DfZTdTIctDWlKbYeG/tS7QyAgI3gcfrTHPhu1E1lKCBw==
+e3LpgB2RZ/E/BCxPJsn+TDDyxGYzrIsMyDt//KhJCjIQD6pNUxr5M5jrq2OwQZgwmz91YcmoQ2XRQAUDpe4BAw==
+w69bYgiQxDmCReB0Dugt9BstXlAKnwJkKCdWvCeZ9KnUCv0FJys6klzYk/O/b9t74tYhWZSX0bhETWHiwfpWBw==";
 
         let currency = "duniter_unit_test_currency";
 
-        let signatures = vec![
-            Sig::Ed25519(ed25519::Signature::from_base64(
-"kL59C1izKjcRN429AlKdshwhWbasvyL7sthI757zm1DfZTdTIctDWlKbYeG/tS7QyAgI3gcfrTHPhu1E1lKCBw=="
-        ).expect("fail to parse test signature")),
-            Sig::Ed25519(ed25519::Signature::from_base64(
-"e3LpgB2RZ/E/BCxPJsn+TDDyxGYzrIsMyDt//KhJCjIQD6pNUxr5M5jrq2OwQZgwmz91YcmoQ2XRQAUDpe4BAw=="
-            ).expect("fail to parse test signature")),
-            Sig::Ed25519(ed25519::Signature::from_base64(
-"w69bYgiQxDmCReB0Dugt9BstXlAKnwJkKCdWvCeZ9KnUCv0FJys6klzYk/O/b9t74tYhWZSX0bhETWHiwfpWBw=="
-            ).expect("fail to parse test signature")),
-        ];
-
-        let doc = TransactionDocumentParser::parse_standard(doc, body, currency, signatures)
+        let doc = TransactionDocumentParser::parse(doc, currency)
             .expect("fail to parse test transaction document !");
         if let V10Document::Transaction(doc) = doc {
             //println!("Doc : {:?}", doc);
diff --git a/message/lib.rs b/message/lib.rs
index d8bf3a8b710de4537c30fb65b710abd285184220..b6d75d48790c2a630ee1f9ba69dc04fb0798be8b 100644
--- a/message/lib.rs
+++ b/message/lib.rs
@@ -41,8 +41,8 @@ use duniter_crypto::hashs::Hash;
 use duniter_crypto::keys::Sig;
 use duniter_dal::dal_event::DALEvent;
 use duniter_dal::dal_requests::{DALRequest, DALResponse};
-use duniter_documents::blockchain::BlockchainProtocol;
 use duniter_documents::BlockId;
+use duniter_documents::BlockchainProtocol;
 use duniter_module::*;
 use duniter_network::{NetworkEvent, NetworkResponse, OldNetworkRequest};
 
diff --git a/network/lib.rs b/network/lib.rs
index 4a0ed49cb6d8d5f695c5857712e7a8bb7efc7098..b8de326f9daf90f67ae44a41fcafeca65b330bc4 100644
--- a/network/lib.rs
+++ b/network/lib.rs
@@ -55,12 +55,14 @@ use crypto::digest::Digest;
 use crypto::sha2::Sha256;
 use duniter_crypto::hashs::*;
 use duniter_crypto::keys::*;
-use duniter_documents::blockchain::v10::documents::{
-    BlockDocument, CertificationDocument, IdentityDocument, MembershipDocument, RevocationDocument,
-    TransactionDocument,
-};
-use duniter_documents::blockchain::Document;
-use duniter_documents::{BlockHash, BlockId, Blockstamp};
+use duniter_documents::v10::block::BlockDocument;
+use duniter_documents::v10::certification::CertificationDocument;
+use duniter_documents::v10::identity::IdentityDocument;
+use duniter_documents::v10::membership::MembershipDocument;
+use duniter_documents::v10::revocation::RevocationDocument;
+use duniter_documents::v10::transaction::TransactionDocument;
+use duniter_documents::Document;
+use duniter_documents::{blockstamp::Blockstamp, BlockHash, BlockId};
 use duniter_module::*;
 use network_endpoint::ApiFeatures;
 use network_head::NetworkHead;
diff --git a/network/network_head.rs b/network/network_head.rs
index 922989510a9dc149d306a6f0b8070853b8aa7b80..9c5d1c023e11170eebcfc2619e7e77719e044d82 100644
--- a/network/network_head.rs
+++ b/network/network_head.rs
@@ -16,8 +16,7 @@
 //! Module defining the format of network heads and how to handle them.
 
 use duniter_crypto::keys::*;
-use duniter_documents::BlockUIdParseError;
-use duniter_documents::Blockstamp;
+use duniter_documents::blockstamp::*;
 use network_head_v2::*;
 use network_head_v3::*;
 use serde_json;
@@ -52,8 +51,8 @@ pub enum NetworkHeadParseErr {
     BaseConvertionError(BaseConvertionError),
     /// ParseIntError
     ParseIntError(ParseIntError),
-    /// BlockUIdParseError
-    BlockUIdParseError(BlockUIdParseError),
+    /// BlockstampParseError
+    BlockstampParseError(BlockstampParseError),
     /// NetworkHeadMessageParseErr
     NetworkHeadMessageParseErr(NetworkHeadMessageParseErr),
     /// InvalidMessageVersion
@@ -78,9 +77,9 @@ impl From<BaseConvertionError> for NetworkHeadParseErr {
     }
 }
 
-impl From<BlockUIdParseError> for NetworkHeadParseErr {
-    fn from(e: BlockUIdParseError) -> Self {
-        NetworkHeadParseErr::BlockUIdParseError(e)
+impl From<BlockstampParseError> for NetworkHeadParseErr {
+    fn from(e: BlockstampParseError) -> Self {
+        NetworkHeadParseErr::BlockstampParseError(e)
     }
 }
 
diff --git a/network/network_head_v2.rs b/network/network_head_v2.rs
index 25fa81c11786db8b4c0bd9e7e6abd9c89d3589c4..bae01eac58023fb905afe5727e23b0e09d1178df 100644
--- a/network/network_head_v2.rs
+++ b/network/network_head_v2.rs
@@ -16,8 +16,7 @@
 //! Module defining the format of network heads v2 and how to handle them.
 
 use duniter_crypto::keys::*;
-use duniter_documents::BlockUIdParseError;
-use duniter_documents::Blockstamp;
+use duniter_documents::blockstamp::*;
 use std::cmp::Ordering;
 use std::num::ParseIntError;
 use std::ops::Deref;
@@ -145,8 +144,8 @@ pub enum NetworkHeadMessageParseErr {
     BaseConvertionError(BaseConvertionError),
     /// ParseIntError
     ParseIntError(ParseIntError),
-    /// BlockUIdParseError
-    BlockUIdParseError(BlockUIdParseError),
+    /// BlockstampParseError
+    BlockstampParseError(BlockstampParseError),
 }
 
 impl From<BaseConvertionError> for NetworkHeadMessageParseErr {
@@ -155,9 +154,9 @@ impl From<BaseConvertionError> for NetworkHeadMessageParseErr {
     }
 }
 
-impl From<BlockUIdParseError> for NetworkHeadMessageParseErr {
-    fn from(e: BlockUIdParseError) -> Self {
-        NetworkHeadMessageParseErr::BlockUIdParseError(e)
+impl From<BlockstampParseError> for NetworkHeadMessageParseErr {
+    fn from(e: BlockstampParseError) -> Self {
+        NetworkHeadMessageParseErr::BlockstampParseError(e)
     }
 }
 
diff --git a/network/network_head_v3.rs b/network/network_head_v3.rs
index b227b94b1d4ce0f0195a2e32fee488f5e0af62dd..611c9807c808a1253c4bb9428595b97c4d61f2ec 100644
--- a/network/network_head_v3.rs
+++ b/network/network_head_v3.rs
@@ -18,7 +18,7 @@
 use base58::ToBase58;
 use duniter_crypto::keys::bin_signable::BinSignable;
 use duniter_crypto::keys::*;
-use duniter_documents::Blockstamp;
+use duniter_documents::blockstamp::Blockstamp;
 use serde_json;
 use std::cmp::Ordering;
 use NodeId;
diff --git a/network/network_peer.rs b/network/network_peer.rs
index d0b7bf9f30acc55155456c3811f43129bd857364..caacd3390e0074170d42127c39a2117757deaf94 100644
--- a/network/network_peer.rs
+++ b/network/network_peer.rs
@@ -24,7 +24,7 @@ extern crate serde;
 use base58::ToBase58;
 use duniter_crypto::keys::bin_signable::BinSignable;
 use duniter_crypto::keys::*;
-use duniter_documents::{Blockstamp, CurrencyName};
+use duniter_documents::{blockstamp::Blockstamp, CurrencyName};
 use network_endpoint::*;
 use *;
 
diff --git a/ws2p-messages/lib.rs b/ws2p-messages/lib.rs
index 1588f275e38dd34b9485c3882b096dee74deb6c8..f3f2e9b7ecd7d9e11fa2a17abf6fd0bf70c820bd 100644
--- a/ws2p-messages/lib.rs
+++ b/ws2p-messages/lib.rs
@@ -58,7 +58,7 @@ mod tests {
     use bincode::{deserialize, serialize};
     use duniter_crypto::keys::bin_signable::BinSignable;
     use duniter_crypto::keys::*;
-    use duniter_documents::blockchain::v10::documents::certification::*;
+    use duniter_documents::v10::certification::*;
     use duniter_documents::{Blockstamp, CurrencyName};
     use duniter_network::network_endpoint::*;
     use duniter_network::network_peer::*;
diff --git a/ws2p-messages/v2/payload_container.rs b/ws2p-messages/v2/payload_container.rs
index 9ff1dec581943c9149415c5dcbe801b067b84cde..473502878493826dbc59b6c4b61a26378b9014f2 100644
--- a/ws2p-messages/v2/payload_container.rs
+++ b/ws2p-messages/v2/payload_container.rs
@@ -19,10 +19,12 @@ use super::req_responses::WS2Pv2ReqRes;
 use super::requests::WS2Pv2Request;
 use super::secret_flags::WS2Pv2SecretFlagsMsg;
 use duniter_crypto::hashs::Hash;
-use duniter_documents::blockchain::v10::documents::{
-    BlockDocument, CertificationDocument, IdentityDocument, MembershipDocument, RevocationDocument,
-    TransactionDocument,
-};
+use duniter_documents::v10::block::BlockDocument;
+use duniter_documents::v10::certification::CertificationDocument;
+use duniter_documents::v10::identity::IdentityDocument;
+use duniter_documents::v10::membership::MembershipDocument;
+use duniter_documents::v10::revocation::RevocationDocument;
+use duniter_documents::v10::transaction::TransactionDocument;
 use duniter_network::network_head_v2::NetworkHeadV2;
 use duniter_network::network_head_v3::NetworkHeadV3Container;
 use duniter_network::network_peer::PeerCardV11;
diff --git a/ws2p-messages/v2/req_responses.rs b/ws2p-messages/v2/req_responses.rs
index ed81adbc5cfc62e6d4d2dd133284877f4e025aff..c4010b2f80a3a66aa61ff2c7dab9095e8f0a1279 100644
--- a/ws2p-messages/v2/req_responses.rs
+++ b/ws2p-messages/v2/req_responses.rs
@@ -14,10 +14,10 @@
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 use duniter_crypto::hashs::Hash;
-use duniter_documents::blockchain::v10::documents::certification::CompactCertificationDocument;
-use duniter_documents::blockchain::v10::documents::identity::CompactIdentityDocument;
-use duniter_documents::blockchain::v10::documents::membership::CompactPoolMembershipDoc;
-use duniter_documents::blockchain::v10::documents::BlockDocument;
+use duniter_documents::v10::block::BlockDocument;
+use duniter_documents::v10::certification::CompactCertificationDocument;
+use duniter_documents::v10::identity::CompactIdentityDocument;
+use duniter_documents::v10::membership::CompactPoolMembershipDoc;
 use duniter_documents::Blockstamp;
 use std::str;
 
diff --git a/ws2p-v1-legacy/lib.rs b/ws2p-v1-legacy/lib.rs
index 3e7e662f35b8f887f26bf62d70f125c1b098b06f..1406c811f9433ad90eb490fd6b3a2312e5b96657 100644
--- a/ws2p-v1-legacy/lib.rs
+++ b/ws2p-v1-legacy/lib.rs
@@ -929,7 +929,7 @@ mod tests {
     use super::parsers::blocks::parse_json_block;
     use super::*;
     use duniter_crypto::keys::PublicKey;
-    use duniter_documents::blockchain::v10::documents::BlockDocument;
+    use duniter_documents::v10::BlockDocument;
     use duniter_module::DuniterModule;
     use duniter_network::network_endpoint::{EndpointEnum, NetworkEndpointApi};
     use duniter_network::NetworkBlock;
diff --git a/ws2p-v1-legacy/parsers/blocks.rs b/ws2p-v1-legacy/parsers/blocks.rs
index ae3aa8dd3ea4b0475bc84275974742830f653e52..867e97070e8c0e28493d3154cb75af74596abc7b 100644
--- a/ws2p-v1-legacy/parsers/blocks.rs
+++ b/ws2p-v1-legacy/parsers/blocks.rs
@@ -5,9 +5,9 @@ use super::identities::parse_compact_identity;
 use super::transactions::parse_transaction;
 use duniter_crypto::hashs::Hash;
 use duniter_crypto::keys::*;
-use duniter_documents::blockchain::v10::documents::block::{BlockV10Parameters, TxDocOrTxHash};
-use duniter_documents::blockchain::v10::documents::membership::*;
-use duniter_documents::blockchain::v10::documents::BlockDocument;
+use duniter_documents::v10::block::{BlockV10Parameters, TxDocOrTxHash};
+use duniter_documents::v10::membership::*;
+use duniter_documents::v10::BlockDocument;
 use duniter_documents::CurrencyName;
 use duniter_documents::{BlockHash, BlockId};
 use duniter_network::{NetworkBlock, NetworkBlockV10};
diff --git a/ws2p-v1-legacy/parsers/identities.rs b/ws2p-v1-legacy/parsers/identities.rs
index ef62335415055c325cef050850d8957efc949fb9..1d288f6db6b03f9c4dd983ff74d2a4320ed6a7b7 100644
--- a/ws2p-v1-legacy/parsers/identities.rs
+++ b/ws2p-v1-legacy/parsers/identities.rs
@@ -1,10 +1,9 @@
 extern crate serde_json;
 
 use duniter_crypto::keys::*;
-use duniter_documents::blockchain::v10::documents::identity::IdentityDocumentBuilder;
-use duniter_documents::blockchain::v10::documents::IdentityDocument;
-use duniter_documents::blockchain::DocumentBuilder;
+use duniter_documents::v10::identity::*;
 use duniter_documents::Blockstamp;
+use duniter_documents::DocumentBuilder;
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
 pub enum IdentityParseError {
diff --git a/ws2p-v1-legacy/parsers/memberships.rs b/ws2p-v1-legacy/parsers/memberships.rs
index a193d5e64ea9ed393bd606eb63b85fd4a29d77a2..496a1c4b84ba4cb11960c7d34c9c7f1ee055dd2c 100644
--- a/ws2p-v1-legacy/parsers/memberships.rs
+++ b/ws2p-v1-legacy/parsers/memberships.rs
@@ -1,12 +1,9 @@
 extern crate serde_json;
 
 use duniter_crypto::keys::*;
-use duniter_documents::blockchain::v10::documents::membership::{
-    MembershipDocumentBuilder, MembershipType,
-};
-use duniter_documents::blockchain::v10::documents::MembershipDocument;
-use duniter_documents::blockchain::DocumentBuilder;
+use duniter_documents::v10::membership::*;
 use duniter_documents::Blockstamp;
+use duniter_documents::DocumentBuilder;
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
 pub enum MembershipParseError {
diff --git a/ws2p-v1-legacy/parsers/mod.rs b/ws2p-v1-legacy/parsers/mod.rs
index decd00fa29656b549f201a620fdfb6ae7c269682..fec21d7a728fb1c7714ee5e0c477603fbf996c8d 100644
--- a/ws2p-v1-legacy/parsers/mod.rs
+++ b/ws2p-v1-legacy/parsers/mod.rs
@@ -23,9 +23,10 @@ pub mod transactions;
 mod tests {
     use super::transactions::*;
     use duniter_crypto::keys::*;
-    use duniter_documents::blockchain::v10::documents::transaction::*;
-    use duniter_documents::blockchain::DocumentBuilder;
+    use duniter_documents::v10::transaction::*;
     use duniter_documents::Blockstamp;
+    use duniter_documents::DocumentBuilder;
+    use std::str::FromStr;
 
     #[test]
     fn parse_json_tx() {
@@ -65,15 +66,15 @@ mod tests {
                 ed25519::PublicKey::from_base58("51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2")
                     .unwrap(),
             )],
-            inputs: &vec![TransactionInput::parse_from_str(
+            inputs: &vec![TransactionInput::from_str(
                 "1000:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:46496",
             )
             .unwrap()],
-            outputs: &vec![TransactionOutput::parse_from_str(
+            outputs: &vec![TransactionOutput::from_str(
                 "1000:0:SIG(2yN8BRSkARcqE8NCxKMBiHfTpx1EvwULFn56Myf6qRmy)",
             )
             .unwrap()],
-            unlocks: &vec![TransactionInputUnlocks::parse_from_str("0:SIG(0)").unwrap()],
+            unlocks: &vec![TransactionInputUnlocks::from_str("0:SIG(0)").unwrap()],
             comment: "Merci pour la calligraphie ;) de Liam",
             hash: None,
         };
@@ -124,21 +125,19 @@ mod tests {
                 ed25519::PublicKey::from_base58("FVUFRrk1K5TQGsY7PRLwqHgdHRoHrwb1hcucp4C2N5tD")
                     .unwrap(),
             )],
-            inputs: &vec![TransactionInput::parse_from_str(
+            inputs: &vec![TransactionInput::from_str(
                 "1000:0:D:FVUFRrk1K5TQGsY7PRLwqHgdHRoHrwb1hcucp4C2N5tD:1",
             )
             .unwrap()],
             outputs: &vec![
-                TransactionOutput::parse_from_str(
-                    "3:0:SIG(7vU9BMDhN6fBuRa2iK3JRbC6pqQKb4qDMGsFcQuT5cz)",
-                )
-                .unwrap(),
-                TransactionOutput::parse_from_str(
+                TransactionOutput::from_str("3:0:SIG(7vU9BMDhN6fBuRa2iK3JRbC6pqQKb4qDMGsFcQuT5cz)")
+                    .unwrap(),
+                TransactionOutput::from_str(
                     "997:0:SIG(FVUFRrk1K5TQGsY7PRLwqHgdHRoHrwb1hcucp4C2N5tD)",
                 )
                 .unwrap(),
             ],
-            unlocks: &vec![TransactionInputUnlocks::parse_from_str("0:SIG(0)").unwrap()],
+            unlocks: &vec![TransactionInputUnlocks::from_str("0:SIG(0)").unwrap()],
             comment: "Un petit cafe ;-)",
             hash: None,
         };
diff --git a/ws2p-v1-legacy/parsers/transactions.rs b/ws2p-v1-legacy/parsers/transactions.rs
index ff24ff9e7c3a5836f485b8752ae606046c4a1349..5f4b700520caf045f784ebd3e8a49a1e64a1b685 100644
--- a/ws2p-v1-legacy/parsers/transactions.rs
+++ b/ws2p-v1-legacy/parsers/transactions.rs
@@ -3,12 +3,13 @@ extern crate serde_json;
 
 use duniter_crypto::hashs::Hash;
 use duniter_crypto::keys::*;
-use duniter_documents::blockchain::v10::documents::transaction::{
+use duniter_documents::v10::transaction::{
     TransactionDocument, TransactionDocumentBuilder, TransactionInput, TransactionInputUnlocks,
     TransactionOutput,
 };
-use duniter_documents::blockchain::DocumentBuilder;
 use duniter_documents::Blockstamp;
+use duniter_documents::DocumentBuilder;
+use std::str::FromStr;
 
 pub fn parse_transaction(
     currency: &str,
@@ -36,7 +37,7 @@ pub fn parse_transaction(
     let mut inputs = Vec::with_capacity(inputs_array.len());
     for input in inputs_array {
         let input_str = input.as_str()?;
-        match TransactionInput::parse_from_str(input_str) {
+        match TransactionInput::from_str(input_str) {
             Ok(input) => inputs.push(input),
             Err(_) => {
                 return None;
@@ -46,7 +47,7 @@ pub fn parse_transaction(
     let unlocks_array = source.get("unlocks")?.as_array()?;
     let mut unlocks = Vec::with_capacity(unlocks_array.len());
     for unlock in unlocks_array {
-        match TransactionInputUnlocks::parse_from_str(unlock.as_str()?) {
+        match TransactionInputUnlocks::from_str(unlock.as_str()?) {
             Ok(unlock) => unlocks.push(unlock),
             Err(_) => {
                 return None;
@@ -56,7 +57,7 @@ pub fn parse_transaction(
     let outputs_array = source.get("outputs")?.as_array()?;
     let mut outputs = Vec::with_capacity(outputs_array.len());
     for output in outputs_array {
-        match TransactionOutput::parse_from_str(output.as_str()?) {
+        match TransactionOutput::from_str(output.as_str()?) {
             Ok(output) => outputs.push(output),
             Err(_) => {
                 return None;
@@ -121,15 +122,15 @@ Merci pour la calligraphie ;) de Liam$\
                 ed25519::PublicKey::from_base58("51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2")
                     .unwrap(),
             )],
-            inputs: &vec![TransactionInput::parse_from_str(
+            inputs: &vec![TransactionInput::from_str(
                 "1000:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:46496",
             )
             .unwrap()],
-            outputs: &vec![TransactionOutput::parse_from_str(
+            outputs: &vec![TransactionOutput::from_str(
                 "1000:0:SIG(2yN8BRSkARcqE8NCxKMBiHfTpx1EvwULFn56Myf6qRmy)",
             )
             .unwrap()],
-            unlocks: &vec![TransactionInputUnlocks::parse_from_str("0:SIG(0)").unwrap()],
+            unlocks: &vec![TransactionInputUnlocks::from_str("0:SIG(0)").unwrap()],
             comment: "Merci pour la calligraphie ;) de Liam",
             hash: None,
         };