From 3f3990d9fb699834ed5c0a3edd088cb0394574f8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pascal=20Eng=C3=A9libert?= <tuxmain@zettascript.org>
Date: Fri, 10 Jan 2025 14:43:10 +0100
Subject: [PATCH 1/3] end2end: non-member idty has UD at genesis

---
 .../universal_dividend.feature                | 15 +++++++++++
 end2end-tests/cucumber-genesis/wot.json       | 27 ++++++++++++++++++-
 end2end-tests/tests/cucumber_tests.rs         | 20 ++++++++++++++
 3 files changed, 61 insertions(+), 1 deletion(-)
 create mode 100644 end2end-tests/cucumber-features/universal_dividend.feature

diff --git a/end2end-tests/cucumber-features/universal_dividend.feature b/end2end-tests/cucumber-features/universal_dividend.feature
new file mode 100644
index 000000000..c858c5e19
--- /dev/null
+++ b/end2end-tests/cucumber-features/universal_dividend.feature
@@ -0,0 +1,15 @@
+@genesis.wot
+
+Feature: Universal Dividend
+
+    Scenario: Eligibility at genesis
+        When 2 blocks later
+
+        # Members
+        Then alice should be eligible to UD
+        Then bob should be eligible to UD
+        Then charlie should be eligible to UD
+
+        # Not members
+        Then eve should not be eligible to UD
+        Then ferdie should not be eligible to UD
diff --git a/end2end-tests/cucumber-genesis/wot.json b/end2end-tests/cucumber-genesis/wot.json
index 26042cf39..0bc2d5457 100644
--- a/end2end-tests/cucumber-genesis/wot.json
+++ b/end2end-tests/cucumber-genesis/wot.json
@@ -59,6 +59,31 @@
       "membership_revokes_on": 2700000001,
       "revoked": false,
       "next_cert_issuable_on": 0
+    },
+    "Eve": {
+      "index": 5,
+      "balance": 1000,
+      "certs_received": {
+        "Alice": 2700000000,
+        "Bob": 2700000000
+      },
+      "owner_address": "5HGjWAeFDfFCWPsjFQdVV2Msvz2XtMktvgocEZcCj68kUMaw",
+      "membership_expire_on": 2700000000,
+      "membership_revokes_on": 2700000001,
+      "revoked": true,
+      "next_cert_issuable_on": 0
+    },
+    "Ferdie": {
+      "index": 6,
+      "balance": 1000,
+      "certs_received": {
+        "Alice": 2700000000
+      },
+      "owner_address": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL",
+      "membership_expire_on": 2700000000,
+      "membership_revokes_on": 2700000001,
+      "revoked": false,
+      "next_cert_issuable_on": 0
     }
   },
   "parameters": {
@@ -99,7 +124,7 @@
   ],
   "treasury_funder_pubkey": "FHNpKmJrUtusuvKPGomAygQqeiks98bdV6yD61Stb6vg",
   "ud": 1000,
-  "initial_monetary_mass": 4000,
+  "initial_monetary_mass": 6000,
   "current_block": {
     "number": 0,
     "medianTime": 1700000000
diff --git a/end2end-tests/tests/cucumber_tests.rs b/end2end-tests/tests/cucumber_tests.rs
index 642779ec8..58a532b2d 100644
--- a/end2end-tests/tests/cucumber_tests.rs
+++ b/end2end-tests/tests/cucumber_tests.rs
@@ -526,6 +526,26 @@ async fn should_be_certified_by(
     }
 }
 
+#[then(regex = r"([a-zA-Z]+) should (not )?be eligible to UD")]
+async fn should_be_eligible_to_ud(
+    world: &mut DuniterWorld,
+    identity: String,
+    not: String,
+) -> Result<()> {
+    let eligible = not.is_empty();
+
+    assert_eq!(
+        identity::get_identity_value(world, identity)
+            .await
+            .expect("Identity not found")
+            .data
+            .first_eligible_ud
+            != 0,
+        eligible
+    );
+    Ok(())
+}
+
 use gdev::runtime_types::pallet_identity::types::IdtyStatus;
 
 // status from string
-- 
GitLab


From 1f18c5bc9b3bb634847b4ee2a695e5cc37dc9b97 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pascal=20Eng=C3=A9libert?= <tuxmain@zettascript.org>
Date: Fri, 10 Jan 2025 15:38:15 +0100
Subject: [PATCH 2/3] Fix UD eligibility at genesis

---
 node/src/chain_spec/g1.rs               |  7 ++++++-
 node/src/chain_spec/gdev.rs             |  7 ++++++-
 node/src/chain_spec/gtest.rs            |  7 ++++++-
 pallets/universal-dividend/src/types.rs | 10 +++++++++-
 runtime/common/src/entities.rs          |  9 ---------
 runtime/gdev/tests/common/mod.rs        |  4 +++-
 6 files changed, 30 insertions(+), 14 deletions(-)

diff --git a/node/src/chain_spec/g1.rs b/node/src/chain_spec/g1.rs
index 8ad20d230..5cfc42125 100644
--- a/node/src/chain_spec/g1.rs
+++ b/node/src/chain_spec/g1.rs
@@ -198,7 +198,12 @@ fn genesis_data_to_g1_genesis_conf(
                         index: idty_index,
                         name: common_runtime::IdtyName::from(name.as_str()),
                         value: common_runtime::IdtyValue {
-                            data: IdtyData::new(),
+                            data: IdtyData {
+                                first_eligible_ud: match status {
+                                    common_runtime::IdtyStatus::Member => 1_u16.into(),
+                                    _ => g1_runtime::pallet_universal_dividend::FirstEligibleUd(None),
+                                }
+                            },
                             next_creatable_identity_on: 0,
                             old_owner_key: None,
                             owner_key,
diff --git a/node/src/chain_spec/gdev.rs b/node/src/chain_spec/gdev.rs
index c78154891..36c906c11 100644
--- a/node/src/chain_spec/gdev.rs
+++ b/node/src/chain_spec/gdev.rs
@@ -286,7 +286,12 @@ fn genesis_data_to_gdev_genesis_conf(
                         index: idty_index,
                         name: common_runtime::IdtyName::from(name.as_str()),
                         value: common_runtime::IdtyValue {
-                            data: IdtyData::new(),
+                            data: IdtyData {
+                                first_eligible_ud: match status {
+                                    common_runtime::IdtyStatus::Member => 1_u16.into(),
+                                    _ => gdev_runtime::pallet_universal_dividend::FirstEligibleUd(None),
+                                }
+                            },
                             next_creatable_identity_on: 0,
                             old_owner_key: None,
                             owner_key,
diff --git a/node/src/chain_spec/gtest.rs b/node/src/chain_spec/gtest.rs
index 2b4020664..80a5705fb 100644
--- a/node/src/chain_spec/gtest.rs
+++ b/node/src/chain_spec/gtest.rs
@@ -291,7 +291,12 @@ fn genesis_data_to_gtest_genesis_conf(
                         index: idty_index,
                         name: common_runtime::IdtyName::from(name.as_str()),
                         value: common_runtime::IdtyValue {
-                            data: IdtyData::new(),
+                            data: IdtyData {
+                                first_eligible_ud: match status {
+                                    common_runtime::IdtyStatus::Member => 1_u16.into(),
+                                    _ => gtest_runtime::pallet_universal_dividend::FirstEligibleUd(None),
+                                }
+                            },
                             next_creatable_identity_on: 0,
                             old_owner_key: None,
                             owner_key,
diff --git a/pallets/universal-dividend/src/types.rs b/pallets/universal-dividend/src/types.rs
index 12fb017cf..b5b5907e6 100644
--- a/pallets/universal-dividend/src/types.rs
+++ b/pallets/universal-dividend/src/types.rs
@@ -22,10 +22,18 @@ use sp_runtime::RuntimeDebug;
 pub type UdIndex = u16;
 
 /// Represents the first eligible Universal Dividend.
-#[derive(Clone, Default, Eq, PartialEq, RuntimeDebug, serde::Deserialize, serde::Serialize)]
+#[derive(Clone, Eq, PartialEq, RuntimeDebug, serde::Deserialize, serde::Serialize)]
 pub struct FirstEligibleUd(pub Option<NonZeroU16>);
 
+/// Default is not eligible
+impl Default for FirstEligibleUd {
+    fn default() -> Self {
+        FirstEligibleUd(None)
+    }
+}
+
 impl FirstEligibleUd {
+    /// Eligible at the first UD index
     pub fn min() -> Self {
         Self(Some(NonZeroU16::new(1).expect("unreachable")))
     }
diff --git a/runtime/common/src/entities.rs b/runtime/common/src/entities.rs
index 4f21fa71b..8884f399f 100644
--- a/runtime/common/src/entities.rs
+++ b/runtime/common/src/entities.rs
@@ -53,15 +53,6 @@ pub struct IdtyData {
     pub first_eligible_ud: pallet_universal_dividend::FirstEligibleUd,
 }
 
-#[cfg(feature = "std")]
-impl IdtyData {
-    pub fn new() -> Self {
-        Self {
-            first_eligible_ud: pallet_universal_dividend::FirstEligibleUd::min(),
-        }
-    }
-}
-
 impl From<IdtyData> for pallet_universal_dividend::FirstEligibleUd {
     fn from(idty_data: IdtyData) -> Self {
         idty_data.first_eligible_ud
diff --git a/runtime/gdev/tests/common/mod.rs b/runtime/gdev/tests/common/mod.rs
index ae5c557d7..192857d11 100644
--- a/runtime/gdev/tests/common/mod.rs
+++ b/runtime/gdev/tests/common/mod.rs
@@ -223,7 +223,9 @@ impl ExtBuilder {
                     index: i as u32 + 1,
                     name: name.clone(),
                     value: IdtyValue {
-                        data: IdtyData::new(),
+                        data: IdtyData {
+                            first_eligible_ud: 1_u16.into(),
+                        },
                         next_creatable_identity_on: Default::default(),
                         owner_key: owner_key.clone(),
                         old_owner_key: None,
-- 
GitLab


From 681c10cc7cd1dae7e9105ccfa7265ed99a3d5cef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pascal=20Eng=C3=A9libert?= <tuxmain@zettascript.org>
Date: Tue, 14 Jan 2025 15:17:12 +0100
Subject: [PATCH 3/3] use FirstEligibleUd::min

---
 node/src/chain_spec/g1.rs        | 4 +++-
 node/src/chain_spec/gdev.rs      | 4 +++-
 node/src/chain_spec/gtest.rs     | 4 +++-
 runtime/gdev/tests/common/mod.rs | 2 +-
 4 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/node/src/chain_spec/g1.rs b/node/src/chain_spec/g1.rs
index 5cfc42125..78f879a8c 100644
--- a/node/src/chain_spec/g1.rs
+++ b/node/src/chain_spec/g1.rs
@@ -200,7 +200,9 @@ fn genesis_data_to_g1_genesis_conf(
                         value: common_runtime::IdtyValue {
                             data: IdtyData {
                                 first_eligible_ud: match status {
-                                    common_runtime::IdtyStatus::Member => 1_u16.into(),
+                                    // Only members are eligible to UD.
+                                    // The first claimable UD has the minimum index (1).
+                                    common_runtime::IdtyStatus::Member => g1_runtime::pallet_universal_dividend::FirstEligibleUd::min(),
                                     _ => g1_runtime::pallet_universal_dividend::FirstEligibleUd(None),
                                 }
                             },
diff --git a/node/src/chain_spec/gdev.rs b/node/src/chain_spec/gdev.rs
index 36c906c11..d6ff6806f 100644
--- a/node/src/chain_spec/gdev.rs
+++ b/node/src/chain_spec/gdev.rs
@@ -288,7 +288,9 @@ fn genesis_data_to_gdev_genesis_conf(
                         value: common_runtime::IdtyValue {
                             data: IdtyData {
                                 first_eligible_ud: match status {
-                                    common_runtime::IdtyStatus::Member => 1_u16.into(),
+                                    // Only members are eligible to UD.
+                                    // The first claimable UD has the minimum index (1).
+                                    common_runtime::IdtyStatus::Member => gdev_runtime::pallet_universal_dividend::FirstEligibleUd::min(),
                                     _ => gdev_runtime::pallet_universal_dividend::FirstEligibleUd(None),
                                 }
                             },
diff --git a/node/src/chain_spec/gtest.rs b/node/src/chain_spec/gtest.rs
index 80a5705fb..b80ad714f 100644
--- a/node/src/chain_spec/gtest.rs
+++ b/node/src/chain_spec/gtest.rs
@@ -293,7 +293,9 @@ fn genesis_data_to_gtest_genesis_conf(
                         value: common_runtime::IdtyValue {
                             data: IdtyData {
                                 first_eligible_ud: match status {
-                                    common_runtime::IdtyStatus::Member => 1_u16.into(),
+                                    // Only members are eligible to UD.
+                                    // The first claimable UD has the minimum index (1).
+                                    common_runtime::IdtyStatus::Member => gtest_runtime::pallet_universal_dividend::FirstEligibleUd::min(),
                                     _ => gtest_runtime::pallet_universal_dividend::FirstEligibleUd(None),
                                 }
                             },
diff --git a/runtime/gdev/tests/common/mod.rs b/runtime/gdev/tests/common/mod.rs
index 192857d11..82b5ade8d 100644
--- a/runtime/gdev/tests/common/mod.rs
+++ b/runtime/gdev/tests/common/mod.rs
@@ -224,7 +224,7 @@ impl ExtBuilder {
                     name: name.clone(),
                     value: IdtyValue {
                         data: IdtyData {
-                            first_eligible_ud: 1_u16.into(),
+                            first_eligible_ud: pallet_universal_dividend::FirstEligibleUd::min(),
                         },
                         next_creatable_identity_on: Default::default(),
                         owner_key: owner_key.clone(),
-- 
GitLab