diff --git a/node/src/chain_spec/gen_genesis_data.rs b/node/src/chain_spec/gen_genesis_data.rs
index 2fdd6cef08caa4a40d06c1c9b40e6ec197f44a14..3d4dd4d713a9c507f305f6949859cdd9d04cc8eb 100644
--- a/node/src/chain_spec/gen_genesis_data.rs
+++ b/node/src/chain_spec/gen_genesis_data.rs
@@ -15,9 +15,12 @@
 // along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>.
 
 use common_runtime::*;
+use maplit::btreemap;
 use serde::{de::DeserializeOwned, Deserialize, Serialize};
+use sp_core::crypto::AccountId32;
 use sp_core::{blake2_256, Decode, Encode, H256};
 use std::collections::BTreeMap;
+use std::fmt::format;
 
 type MembershipData = sp_membership::MembershipData<u32>;
 
@@ -55,7 +58,6 @@ struct GenesisConfig<Parameters> {
     first_ud: Option<u64>,
     first_ud_reeval: Option<u64>,
     genesis_parameters: ParamsAppliedAtGenesis,
-    identities: BTreeMap<String, Idty>,
     #[serde(default)]
     parameters: Parameters,
     #[serde(rename = "smiths")]
@@ -63,6 +65,11 @@ struct GenesisConfig<Parameters> {
     sudo_key: Option<AccountId>,
     technical_committee: Vec<String>,
     ud: u64,
+}
+
+#[derive(Deserialize, Serialize)]
+struct GenesisMigrationData {
+    identities: BTreeMap<String, Idty>,
     #[serde(default)]
     wallets: BTreeMap<AccountId, u64>,
 }
@@ -112,36 +119,8 @@ where
     SK: Decode,
     F: Fn(GenesisData<P, SK>) -> CS,
 {
-    let genesis_timestamp: u64 =
-        if let Ok(genesis_timestamp) = std::env::var("DUNITER_GENESIS_TIMESTAMP") {
-            genesis_timestamp
-                .parse()
-                .map_err(|_| "DUNITER_GENESIS_TIMESTAMP must be a number".to_owned())?
-        } else {
-            use std::time::SystemTime;
-            SystemTime::now()
-                .duration_since(SystemTime::UNIX_EPOCH)
-                .expect("SystemTime before UNIX EPOCH!")
-                .as_secs()
-        };
-
-    let json_file_path = std::env::var("DUNITER_GENESIS_CONFIG")
-        .unwrap_or_else(|_| "duniter-gen-conf.json".to_owned());
-
-    // We mmap the file into memory first, as this is *a lot* faster than using
-    // `serde_json::from_reader`. See https://github.com/serde-rs/json/issues/160
-    let file = std::fs::File::open(&json_file_path)
-        .map_err(|e| format!("Error opening gen conf file `{}`: {}", json_file_path, e))?;
+    let genesis_timestamp: u64 = get_genesis_timestamp()?;
 
-    // SAFETY: `mmap` is fundamentally unsafe since technically the file can change
-    //         underneath us while it is mapped; in practice it's unlikely to be a problem
-    let bytes = unsafe {
-        memmap2::Mmap::map(&file)
-            .map_err(|e| format!("Error mmaping gen conf file `{}`: {}", json_file_path, e))?
-    };
-
-    let genesis_config = serde_json::from_slice(&bytes)
-        .map_err(|e| format!("Error parsing gen conf file: {}", e))?;
     let GenesisConfig {
         sudo_key,
         first_ud,
@@ -154,12 +133,19 @@ where
                 genesis_smith_memberships_expire_on,
             },
         parameters,
-        identities,
+        // identities,
         smith_identities,
         technical_committee,
         ud,
+        // wallets,
+    } = get_genesis_config::<P>()?;
+
+    let GenesisMigrationData {
+        identities,
         wallets,
-    } = genesis_config;
+    } = get_genesis_migration_data()?;
+
+    check_parameters_consistency(&wallets, &first_ud, &first_ud_reeval, &ud)?;
 
     // MONEY AND WOT //
 
@@ -396,6 +382,89 @@ where
     Ok(f(genesis_data))
 }
 
+fn check_parameters_consistency(
+    wallets: &BTreeMap<AccountId32, u64>,
+    first_ud: &Option<u64>,
+    first_reeval: &Option<u64>,
+    ud: &u64,
+) -> Result<(), String> {
+    // No empty wallet
+    if let Some((account, _)) = wallets.iter().find(|(_, amount)| **amount == 0) {
+        return Err(format!("Wallet {} is empty", account));
+    }
+
+    // TODO: check ud_reeval_period / ud_creation_period (can round to zero)
+
+    if first_reeval.is_none() {
+        return Err("Please provied a value for `first_ud_reeval`".to_owned());
+    }
+    if first_ud.is_none() {
+        return Err("Please provied a value for `first_ud`".to_owned());
+    }
+    if first_ud.unwrap() > first_reeval.unwrap() {
+        return Err(format!(
+            "`first_ud` ({}) should be lower than `first_ud_reeval` ({})",
+            first_ud.unwrap(),
+            first_reeval.unwrap()
+        )
+        .to_owned());
+    }
+    if *ud == 0 {
+        return Err("`ud` is expected to be > 0".to_owned());
+    }
+    Ok(())
+}
+
+fn get_genesis_config<P: Default + DeserializeOwned>() -> Result<GenesisConfig<P>, String> {
+    let json_file_path = std::env::var("DUNITER_GENESIS_CONFIG")
+        .unwrap_or_else(|_| "duniter-gen-conf.json".to_owned());
+    // We mmap the file into memory first, as this is *a lot* faster than using
+    // `serde_json::from_reader`. See https://github.com/serde-rs/json/issues/160
+    let file = std::fs::File::open(&json_file_path)
+        .map_err(|e| format!("Error opening gen conf file `{}`: {}", json_file_path, e))?;
+    // SAFETY: `mmap` is fundamentally unsafe since technically the file can change
+    //         underneath us while it is mapped; in practice it's unlikely to be a problem
+    let bytes = unsafe {
+        memmap2::Mmap::map(&file)
+            .map_err(|e| format!("Error mmaping gen conf file `{}`: {}", json_file_path, e))?
+    };
+    serde_json::from_slice::<GenesisConfig<P>>(&bytes)
+        .map_err(|e| format!("Error parsing gen conf file: {}", e))
+}
+
+fn get_genesis_migration_data() -> Result<GenesisMigrationData, String> {
+    if let Ok(json_file_path) = std::env::var("DUNITER_GENESIS_MIGRATION") {
+        let file = std::fs::File::open(&json_file_path)
+            .map_err(|e| format!("Error opening gen conf file `{}`: {}", json_file_path, e))?;
+        let bytes = unsafe {
+            memmap2::Mmap::map(&file)
+                .map_err(|e| format!("Error mmaping gen conf file `{}`: {}", json_file_path, e))?
+        };
+        serde_json::from_slice::<GenesisMigrationData>(&bytes)
+            .map_err(|e| format!("Error parsing gen conf file: {}", e))
+    } else {
+        // No data
+        Ok(GenesisMigrationData {
+            wallets: btreemap! {},
+            identities: btreemap! {},
+        })
+    }
+}
+
+fn get_genesis_timestamp() -> Result<u64, String> {
+    if let Ok(genesis_timestamp) = std::env::var("DUNITER_GENESIS_TIMESTAMP") {
+        genesis_timestamp
+            .parse()
+            .map_err(|_| "DUNITER_GENESIS_TIMESTAMP must be a number".to_owned())
+    } else {
+        use std::time::SystemTime;
+        Ok(SystemTime::now()
+            .duration_since(SystemTime::UNIX_EPOCH)
+            .expect("SystemTime before UNIX EPOCH!")
+            .as_secs())
+    }
+}
+
 // Timestamp to block number
 fn to_bn(genesis_timestamp: u64, timestamp: u64) -> u32 {
     let duration_in_secs = timestamp.saturating_sub(genesis_timestamp);
diff --git a/resources/gdev.json b/resources/gdev.json
index b2ec211ee6f63eb90f5c80b900f87ec914e41c2d..6a128da4e678e15b39b93c5f149fa829ea3b0b35 100644
--- a/resources/gdev.json
+++ b/resources/gdev.json
@@ -1,6 +1,7 @@
 {
   "first_ud": 10000,
   "first_ud_reeval": 100800,
+  "ud": 1068,
   "genesis_parameters": {
     "genesis_certs_expire_on": 2102400,
     "genesis_certs_min_received": 3,
@@ -9,142 +10,6 @@
     "genesis_smith_certs_min_received": 3,
     "genesis_smith_memberships_expire_on": 1051200
   },
-  "identities": {
-    "Elois": {
-      "balance": 10000,
-      "certs": [
-        "poka",
-        "cgeek",
-        "vit",
-        "tuxmain",
-        "HugoTrentesaux",
-        "ManUtopiK",
-        "moul",
-        "1000i100",
-        "kapis",
-        "David B",
-        "Gamaliel",
-        "wellno1"
-      ],
-      "pubkey": "5H95G8bwuf4yyNNNa83hDhj7wpYaSRhZiGezZ9TDbyqNdAhY"
-    },
-    "Elois2": {
-      "balance": 10000,
-      "certs": ["tuxmain", "Elois", "HugoTrentesaux"],
-      "pubkey": "5GFEEx7kqvP4QEPCAXkALeYCG7m8DiA5LQ4YzW62j7FytQyg"
-    },
-    "poka": {
-      "balance": 10000,
-      "certs": ["cgeek", "vit", "tuxmain", "Elois", "HugoTrentesaux"],
-      "pubkey": "5CQ8T4qpbYJq7uVsxGPQ5q2df7x3Wa4aRY6HUWMBYjfLZhnn"
-    },
-    "tuxmain": {
-      "balance": 10000,
-      "certs": [
-        "cgeek",
-        "Elois",
-        "HugoTrentesaux",
-        "ManUtopiK",
-        "poka",
-        "moul",
-        "1000i100"
-      ],
-      "pubkey": "5D2DnScFpxoEUXDwZbJH18tRsQMygBSh1F6YCcWvTYzKY2W7"
-    },
-    "vit": {
-      "balance": 10000,
-      "certs": [
-        "cgeek",
-        "Elois",
-        "HugoTrentesaux",
-        "ManUtopiK",
-        "poka",
-        "tuxmain",
-        "moul"
-      ],
-      "pubkey": "5DqkYGjiT5TFm2pGMUBMuZW4sw13vDEZmxqkxmky5AoQvUwd"
-    },
-    "cgeek": {
-      "balance": 10000,
-      "certs": ["poka", "vit", "tuxmain", "Elois", "HugoTrentesaux", "moul"],
-      "pubkey": "5DP7ze5cJwtHbqXaP2aNtJ5jkULzcTCqXuMzDvk9JjneFjfq"
-    },
-    "HugoTrentesaux": {
-      "balance": 10000,
-      "certs": [
-        "poka",
-        "vit",
-        "tuxmain",
-        "Elois",
-        "moul",
-        "1000i100",
-        "ManUtopiK",
-        "kapis",
-        "David B",
-        "Gamaliel",
-        "wellno1"
-      ],
-      "pubkey": "5Dq8xjvkmbz7q4g2LbZgyExD26VSCutfEc6n4W4AfQeVHZqz"
-    },
-    "ManUtopiK": {
-      "balance": 10000,
-      "certs": [
-        "poka",
-        "vit",
-        "tuxmain",
-        "Elois",
-        "HugoTrentesaux",
-        "1000i100"
-      ],
-      "pubkey": "5DUjwHRqPayt3tAZk1fqEgU99xZB9jzBHKy2sMSTNcc7m9D1"
-    },
-    "1000i100": {
-      "balance": 10000,
-      "certs": [
-        "Elois",
-        "poka",
-        "cgeek",
-        "vit",
-        "tuxmain",
-        "HugoTrentesaux",
-        "ManUtopiK",
-        "moul"
-      ],
-      "pubkey": "5CCrBS67BrpBx3ihGHc72HZp3eHHbETxWFuNfwbbdoGSJFN8"
-    },
-    "moul": {
-      "balance": 10000,
-      "certs": [
-        "ManUtopiK",
-        "vit",
-        "tuxmain",
-        "Elois",
-        "HugoTrentesaux",
-        "1000i100"
-      ],
-      "pubkey": "5EPGRtBYLwfDinnaAXsscM3FkffRADpJRrkZETqW8N6uhp22"
-    },
-    "Gamaliel": {
-      "balance": 10000,
-      "certs": ["David B", "wellno1", "kapis"],
-      "pubkey": "5DS9iWBXW56N7XbeVyyp6CB7m4LeE5fGJYrUR9HDSStT5JN9"
-    },
-    "kapis": {
-      "balance": 10000,
-      "certs": ["David B", "wellno1", "Gamaliel"],
-      "pubkey": "5HJyyim1W8Y1UD8LAbBL7cQQLjGofMoD45RtRSAmhkFQxrvs"
-    },
-    "David B": {
-      "balance": 10000,
-      "certs": ["kapis", "wellno1", "Gamaliel"],
-      "pubkey": "5HKTDdXHj3MojiPRcEsVU9JaHyif5gg2br1sy3JZbsjuQebP"
-    },
-    "wellno1": {
-      "balance": 10000,
-      "certs": ["David B", "kapis", "Gamaliel"],
-      "pubkey": "5DyEZNkSuK5i8wZiXtvL63zqpye9zPBsPRauCjQkMuVzZYX7"
-    }
-  },
   "parameters": {
     "babe_epoch_duration": 600,
     "cert_period": 14400,
@@ -200,5 +65,5 @@
     }
   },
   "sudo_key": "5Hm8sBbwuLAU99dBezvgtnRmZCrUy9mhqmbQMFyGTaeATYg7",
-  "technical_committee": ["Elois", "cgeek", "tuxmain", "HugoTrentesaux"]
+  "technical_committee": ["1000i100", "vit", "poka", "tuxmain", "cgeek", "HugoTrentesaux", "Maaltir", "Pini"]
 }