From 382970ab33e9e75425efe517e5eafbcd30df1144 Mon Sep 17 00:00:00 2001 From: Arshavir Ter-Gabrielyan Date: Wed, 26 Feb 2025 17:18:47 +0000 Subject: [PATCH 1/7] first --- Cargo.lock | 1 + .../tests/constraints_dependencies.rs | 12 +- rs/sns/init/BUILD.bazel | 1 + rs/sns/init/Cargo.toml | 1 + rs/sns/init/src/distributions.rs | 394 ++---------------- rs/sns/init/src/lib.rs | 63 +-- 6 files changed, 36 insertions(+), 436 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7a114cb3568..a748680cf17 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12319,6 +12319,7 @@ dependencies = [ "lazy_static", "maplit", "num-traits", + "pretty_assertions", "prost 0.13.4", "serde", "serde_yaml", diff --git a/rs/nervous_system/integration_tests/tests/constraints_dependencies.rs b/rs/nervous_system/integration_tests/tests/constraints_dependencies.rs index e937858a991..fce178b276c 100644 --- a/rs/nervous_system/integration_tests/tests/constraints_dependencies.rs +++ b/rs/nervous_system/integration_tests/tests/constraints_dependencies.rs @@ -1,10 +1,7 @@ use ic_nervous_system_common::MAX_NEURONS_FOR_DIRECT_PARTICIPANTS; use ic_nns_governance::governance::MAX_NEURONS_FUND_PARTICIPANTS; use ic_sns_governance::pb::v1::NervousSystemParameters; -use ic_sns_init::{ - distributions::{MAX_AIRDROP_DISTRIBUTION_COUNT, MAX_DEVELOPER_DISTRIBUTION_COUNT}, - MAX_SNS_NEURONS_PER_BASKET, -}; +use ic_sns_init::{distributions::MAX_DEVELOPER_DISTRIBUTION_COUNT, MAX_SNS_NEURONS_PER_BASKET}; // Test that the total number of SNS neurons created by an SNS swap is within the ceiling expected // by SNS Governance (`MAX_NUMBER_OF_NEURONS_CEILING`). Concretely, the test compares this constant @@ -46,19 +43,16 @@ fn test_max_number_of_sns_neurons_adds_up() { NervousSystemParameters::MAX_NUMBER_OF_NEURONS_CEILING >= MAX_SNS_NEURONS_PER_BASKET * MAX_NEURONS_FUND_PARTICIPANTS + MAX_NEURONS_FOR_DIRECT_PARTICIPANTS - + MAX_DEVELOPER_DISTRIBUTION_COUNT as u64 - + MAX_AIRDROP_DISTRIBUTION_COUNT as u64, + + MAX_DEVELOPER_DISTRIBUTION_COUNT as u64, "MAX_NUMBER_OF_NEURONS_CEILING ({}) must be >= \ MAX_SNS_NEURONS_PER_BASKET ({}) * MAX_NEURONS_FUND_PARTICIPANTS ({}) \ + MAX_NEURONS_FOR_DIRECT_PARTICIPANTS ({}) \ - + MAX_DEVELOPER_DISTRIBUTION_COUNT ({}) \ - + MAX_AIRDROP_DISTRIBUTION_COUNT ({}).\n{}", + + MAX_DEVELOPER_DISTRIBUTION_COUNT ({})", NervousSystemParameters::MAX_NUMBER_OF_NEURONS_CEILING, MAX_SNS_NEURONS_PER_BASKET, MAX_NEURONS_FUND_PARTICIPANTS, MAX_NEURONS_FOR_DIRECT_PARTICIPANTS, MAX_DEVELOPER_DISTRIBUTION_COUNT, - MAX_AIRDROP_DISTRIBUTION_COUNT, RECOMMENDATION ); } diff --git a/rs/sns/init/BUILD.bazel b/rs/sns/init/BUILD.bazel index 1f086b6e48e..2d3f2c0c779 100644 --- a/rs/sns/init/BUILD.bazel +++ b/rs/sns/init/BUILD.bazel @@ -44,6 +44,7 @@ DEV_DEPENDENCIES = [ "//rs/sns/init/protobuf_generator:lib", "//rs/test_utilities/compare_dirs", "@crate_index//:num-traits", + "@crate_index//:pretty_assertions", "@crate_index//:tempfile", ] diff --git a/rs/sns/init/Cargo.toml b/rs/sns/init/Cargo.toml index f4d2d9e290b..3226f385fed 100644 --- a/rs/sns/init/Cargo.toml +++ b/rs/sns/init/Cargo.toml @@ -37,6 +37,7 @@ ic-nervous-system-common-test-keys = { path = "../../nervous_system/common/test_ ic-sns-init-protobuf-generator = { path = "protobuf_generator" } ic-test-utilities-compare-dirs = { path = "../../test_utilities/compare_dirs" } num-traits = { workspace = true } +pretty_assertions = { workspace = true } tempfile = { workspace = true } [features] diff --git a/rs/sns/init/src/distributions.rs b/rs/sns/init/src/distributions.rs index a0c6dc0bb65..a96a6713e80 100644 --- a/rs/sns/init/src/distributions.rs +++ b/rs/sns/init/src/distributions.rs @@ -1,7 +1,7 @@ use crate::{ pb::v1::{ - AirdropDistribution, DeveloperDistribution, FractionalDeveloperVotingPower, - NeuronDistribution, SwapDistribution, TreasuryDistribution, + DeveloperDistribution, FractionalDeveloperVotingPower, NeuronDistribution, + SwapDistribution, TreasuryDistribution, }, SnsCanisterIds, }; @@ -16,7 +16,6 @@ use ic_nervous_system_common::{ }; use ic_sns_governance::{ governance::TREASURY_SUBACCOUNT_NONCE, - neuron::DEFAULT_VOTING_POWER_PERCENTAGE_MULTIPLIER, pb::v1::{neuron::DissolveState, NervousSystemParameters, Neuron, NeuronId, NeuronPermission}, }; use ic_sns_swap::swap::{NEURON_BASKET_MEMO_RANGE_START, SALE_NEURON_MEMO_RANGE_END}; @@ -30,9 +29,6 @@ pub const SWAP_SUBACCOUNT_NONCE: u64 = 1; /// The max number of DeveloperDistributions that can be specified in the SnsInitPayload. pub const MAX_DEVELOPER_DISTRIBUTION_COUNT: usize = 100; -/// The max number of AirdropDistributions that can be specified in the SnsInitPayload. -pub const MAX_AIRDROP_DISTRIBUTION_COUNT: usize = 1000; - impl FractionalDeveloperVotingPower { /// Given the configuration of the different buckets, when provided the SnsCanisterIds calculate /// all the `AccountId`s of SNS Ledger accounts that will have tokens distributed at genesis. @@ -45,7 +41,6 @@ impl FractionalDeveloperVotingPower { self.insert_developer_accounts(sns_canister_ids, &mut accounts)?; self.insert_treasury_accounts(sns_canister_ids, &mut accounts)?; self.insert_swap_accounts(sns_canister_ids, &mut accounts)?; - self.insert_airdrop_accounts(sns_canister_ids, &mut accounts)?; Ok(accounts) } @@ -58,7 +53,6 @@ impl FractionalDeveloperVotingPower { parameters: &NervousSystemParameters, ) -> Result, String> { let developer_neurons = &self.developer_distribution()?.developer_neurons; - let airdrop_neurons = &self.airdrop_distribution()?.airdrop_neurons; let swap = self.swap_distribution()?; @@ -83,16 +77,6 @@ impl FractionalDeveloperVotingPower { initial_neurons.insert(neuron.id.as_ref().unwrap().to_string(), neuron); } - for airdrop_neuron_distribution in airdrop_neurons { - let neuron = self.create_neuron( - airdrop_neuron_distribution, - DEFAULT_VOTING_POWER_PERCENTAGE_MULTIPLIER, - parameters, - )?; - - initial_neurons.insert(neuron.id.as_ref().unwrap().to_string(), neuron); - } - Ok(initial_neurons) } @@ -115,21 +99,17 @@ impl FractionalDeveloperVotingPower { .as_ref() .ok_or("Error: swap_distribution must be specified")?; - let airdrop_distribution = self + let airdrop_neurons = self .airdrop_distribution - .as_ref() - .ok_or("Error: airdrop_distribution must be specified")?; + .clone() + .map(|airdrop_distribution| airdrop_distribution.airdrop_neurons) + .unwrap_or_default(); - self.validate_neurons( - developer_distribution, - airdrop_distribution, - nervous_system_parameters, - )?; + if !airdrop_neurons.is_empty() { + return Err("Error: airdrop_distribution is obsolete.".to_string()); + } - match Self::get_total_distributions(&airdrop_distribution.airdrop_neurons) { - Ok(_) => (), - Err(_) => return Err("Error: The sum of all airdrop allocated tokens overflowed and is an invalid distribution".to_string()), - }; + self.validate_neurons(developer_distribution, nervous_system_parameters)?; if swap_distribution.initial_swap_amount_e8s == 0 { return Err( @@ -201,11 +181,10 @@ impl FractionalDeveloperVotingPower { }) } - /// Validate the NeuronDistributions in the Developer and Airdrop bucket + /// Validate the NeuronDistributions in the developer bucket. fn validate_neurons( &self, developer_distribution: &DeveloperDistribution, - airdrop_distribution: &AirdropDistribution, nervous_system_parameters: &NervousSystemParameters, ) -> Result<(), String> { let neuron_minimum_dissolve_delay_to_vote_seconds = nervous_system_parameters @@ -268,76 +247,9 @@ impl FractionalDeveloperVotingPower { } } - let missing_airdrop_principals_count = airdrop_distribution - .airdrop_neurons - .iter() - .filter(|neuron_distribution| neuron_distribution.controller.is_none()) - .count(); - - if missing_airdrop_principals_count != 0 { - return Err(format!( - "Error: {} airdrop_neurons are missing controllers", - missing_airdrop_principals_count - )); - } - - let deduped_airdrop_neurons = airdrop_distribution - .airdrop_neurons - .iter() - .map(|neuron_distribution| { - ( - (neuron_distribution.controller, neuron_distribution.memo), - neuron_distribution.stake_e8s, - ) - }) - .collect::>(); - - if deduped_airdrop_neurons.len() != airdrop_distribution.airdrop_neurons.len() { - return Err( - "Error: Neurons with the same controller and memo detected in airdrop_neurons" - .to_string(), - ); - } - - if deduped_airdrop_neurons.len() > MAX_AIRDROP_DISTRIBUTION_COUNT { - return Err(format!( - "Error: The number of airdrop neurons must be less than {}. Current count is {}", - MAX_AIRDROP_DISTRIBUTION_COUNT, - deduped_airdrop_neurons.len(), - )); - } - - for (controller, memo) in deduped_airdrop_neurons.keys() { - if NEURON_BASKET_MEMO_RANGE_START <= *memo && *memo <= SALE_NEURON_MEMO_RANGE_END { - return Err(format!( - "Error: Airdrop neuron with controller {} cannot have a memo in the range {} to {}", - controller.unwrap(), - NEURON_BASKET_MEMO_RANGE_START, - SALE_NEURON_MEMO_RANGE_END - )); - } - } - - let mut duplicated_neuron_principals = vec![]; - for developer_principal in deduped_dev_neurons.keys() { - if deduped_airdrop_neurons.contains_key(developer_principal) { - // Safe to unwrap due to the checks done above - duplicated_neuron_principals.push(developer_principal.0.unwrap()) - } - } - - if !duplicated_neuron_principals.is_empty() { - return Err(format!( - "Error: The following controllers are present in AirdropDistribution \ - and DeveloperDistribution: {:?}", - duplicated_neuron_principals - )); - } - let configured_at_least_one_voting_neuron = developer_distribution .developer_neurons .iter() - .chain(&airdrop_distribution.airdrop_neurons) .any(|neuron_distribution| { neuron_distribution.dissolve_delay_seconds >= *neuron_minimum_dissolve_delay_to_vote_seconds @@ -354,7 +266,6 @@ impl FractionalDeveloperVotingPower { let misconfigured_dissolve_delay_principals: Vec = developer_distribution .developer_neurons .iter() - .chain(&airdrop_distribution.airdrop_neurons) .filter(|neuron_distribution| { neuron_distribution.dissolve_delay_seconds > *max_dissolve_delay_seconds }) @@ -440,26 +351,6 @@ impl FractionalDeveloperVotingPower { Ok(()) } - /// Calculate and insert the airdrop bucket accounts into the provided map. - fn insert_airdrop_accounts( - &self, - sns_canister_ids: &SnsCanisterIds, - accounts: &mut BTreeMap, - ) -> Result<(), String> { - for neuron_distribution in &self.airdrop_distribution()?.airdrop_neurons { - let principal_id = neuron_distribution.controller()?; - - let (account, tokens) = Self::get_neuron_account_id_and_tokens( - &sns_canister_ids.governance, - &principal_id, - neuron_distribution.stake_e8s, - neuron_distribution.memo, - ); - accounts.insert(account, tokens); - } - Ok(()) - } - /// Given a the PrincipalId of Governance, compute the AccountId and the number of tokens /// of a distribution account. pub fn get_distribution_account_id_and_tokens( @@ -533,12 +424,6 @@ impl FractionalDeveloperVotingPower { .ok_or_else(|| "Expected swap distribution to exist".to_string()) } - fn airdrop_distribution(&self) -> Result<&AirdropDistribution, String> { - self.airdrop_distribution - .as_ref() - .ok_or_else(|| "Expected airdrop distribution to exist".to_string()) - } - /// This gives us some values that work for testing but would not be useful /// in a real world scenario. They are only meant to validate, not be sensible. pub fn with_valid_values_for_testing() -> Self { @@ -553,9 +438,7 @@ impl FractionalDeveloperVotingPower { total_e8s: 10_000_000_000, initial_swap_amount_e8s: 10_000_000_000, }), - airdrop_distribution: Some(AirdropDistribution { - airdrop_neurons: Default::default(), - }), + airdrop_distribution: None, } } } @@ -593,12 +476,10 @@ impl NeuronDistribution { #[cfg(test)] mod test { use crate::{ - distributions::{ - MAX_AIRDROP_DISTRIBUTION_COUNT, MAX_DEVELOPER_DISTRIBUTION_COUNT, SWAP_SUBACCOUNT_NONCE, - }, + distributions::{MAX_DEVELOPER_DISTRIBUTION_COUNT, SWAP_SUBACCOUNT_NONCE}, pb::v1::{ - AirdropDistribution, DeveloperDistribution, FractionalDeveloperVotingPower, - NeuronDistribution, SwapDistribution, TreasuryDistribution, + DeveloperDistribution, FractionalDeveloperVotingPower, NeuronDistribution, + SwapDistribution, TreasuryDistribution, }, SnsCanisterIds, Tokens, }; @@ -609,11 +490,10 @@ mod test { ONE_MONTH_SECONDS, ONE_YEAR_SECONDS, }; use ic_nervous_system_common_test_keys::{ - TEST_NEURON_1_OWNER_PRINCIPAL, TEST_NEURON_2_OWNER_PRINCIPAL, TEST_NEURON_3_OWNER_PRINCIPAL, + TEST_NEURON_1_OWNER_PRINCIPAL, TEST_NEURON_2_OWNER_PRINCIPAL, }; use ic_sns_governance::{ governance::TREASURY_SUBACCOUNT_NONCE, - neuron::DEFAULT_VOTING_POWER_PERCENTAGE_MULTIPLIER, pb::v1::{neuron::DissolveState, NervousSystemParameters, NeuronId, NeuronPermission}, }; use ic_sns_swap::swap::NEURON_BASKET_MEMO_RANGE_START; @@ -697,13 +577,7 @@ mod test { total_e8s: swap_total, initial_swap_amount_e8s: swap_initial_round, }), - airdrop_distribution: Some(AirdropDistribution { - airdrop_neurons: vec![NeuronDistribution { - controller: Some(*TEST_NEURON_3_OWNER_PRINCIPAL), - stake_e8s: neuron_stake, - ..NeuronDistribution::with_valid_values_for_testing() - }], - }), + airdrop_distribution: None, }; let canister_ids = create_canister_ids(); @@ -721,19 +595,12 @@ mod test { Some(*TEST_NEURON_2_OWNER_PRINCIPAL), None, ); - let neuron_3_account = get_neuron_account_identifier( - canister_ids.governance, - Some(*TEST_NEURON_3_OWNER_PRINCIPAL), - None, - ); let neuron_1_account_balance = initial_ledger_accounts.get(&neuron_1_account).unwrap(); let neuron_2_account_balance = initial_ledger_accounts.get(&neuron_2_account).unwrap(); - let neuron_3_account_balance = initial_ledger_accounts.get(&neuron_3_account).unwrap(); assert_eq!(neuron_1_account_balance, &Tokens::from_e8s(neuron_stake)); assert_eq!(neuron_2_account_balance, &Tokens::from_e8s(neuron_stake)); - assert_eq!(neuron_3_account_balance, &Tokens::from_e8s(neuron_stake)); // Verify swap related bucket let locked_swap_account = get_distribution_account_identifier( @@ -782,7 +649,6 @@ mod test { fn test_initial_neurons() { // Different token values let developer_neuron_stake = 100_000_000; - let airdrop_neuron_stake = 50_000; let swap_total = 1_000_000_000; let swap_initial_round = 400_000_000; let treasury_total = 1_000_000_000; @@ -790,7 +656,6 @@ mod test { // Different dissolve delays let neuron_1_dissolve_delay = 6 * ONE_MONTH_SECONDS; let neuron_2_dissolve_delay = ONE_YEAR_SECONDS; - let neuron_3_dissolve_delay = 2 * ONE_YEAR_SECONDS; let neuron_2_vesting_period_seconds = Some(3 * ONE_YEAR_SECONDS); @@ -820,15 +685,7 @@ mod test { total_e8s: swap_total, initial_swap_amount_e8s: swap_initial_round, }), - airdrop_distribution: Some(AirdropDistribution { - airdrop_neurons: vec![NeuronDistribution { - controller: Some(*TEST_NEURON_3_OWNER_PRINCIPAL), - stake_e8s: airdrop_neuron_stake, - memo: 0, - dissolve_delay_seconds: neuron_3_dissolve_delay, - vesting_period_seconds: None, - }], - }), + airdrop_distribution: None, }; let parameters = NervousSystemParameters::with_default_values(); @@ -845,10 +702,6 @@ mod test { *TEST_NEURON_2_OWNER_PRINCIPAL, 0, )); - let neuron_id_3 = NeuronId::from(compute_neuron_staking_subaccount_bytes( - *TEST_NEURON_3_OWNER_PRINCIPAL, - 0, - )); // Validate they exist let neuron_1 = initial_neurons @@ -857,14 +710,10 @@ mod test { let neuron_2 = initial_neurons .get(&neuron_id_2.to_string()) .expect("Expected neuron_id to exist"); - let neuron_3 = initial_neurons - .get(&neuron_id_3.to_string()) - .expect("Expected neuron_id to exist"); // That their stake is as configured assert_eq!(neuron_1.stake_e8s(), developer_neuron_stake); assert_eq!(neuron_2.stake_e8s(), developer_neuron_stake); - assert_eq!(neuron_3.stake_e8s(), airdrop_neuron_stake); // That the neurons have permissions to use them let mut expected_neuron_permission = NeuronPermission { @@ -888,9 +737,6 @@ mod test { vec![expected_neuron_permission.clone()] ); - expected_neuron_permission.principal = Some(*TEST_NEURON_3_OWNER_PRINCIPAL); - assert_eq!(neuron_3.permissions, vec![expected_neuron_permission]); - assert_eq!( neuron_1.dissolve_state, Some(DissolveState::DissolveDelaySeconds(neuron_1_dissolve_delay)) @@ -899,14 +745,9 @@ mod test { neuron_2.dissolve_state, Some(DissolveState::DissolveDelaySeconds(neuron_2_dissolve_delay)) ); - assert_eq!( - neuron_3.dissolve_state, - Some(DissolveState::DissolveDelaySeconds(neuron_3_dissolve_delay)) - ); // That they have the correct voting_power_percentage_multiplier. The developer neurons - // (neuron_1, neuron_2) should have the voting_power_percentage_multiplier, and the airdrop - // neuron (neuron_3) should have the default set. + // (neuron_1, neuron_2) should have the voting_power_percentage_multiplier. let swap_ratio = swap_initial_round as f32 / swap_total as f32; let voting_power_percentage_multiplier = (swap_ratio * 100_f32) as u64; assert_eq!( @@ -917,15 +758,10 @@ mod test { neuron_2.voting_power_percentage_multiplier, voting_power_percentage_multiplier ); - assert_eq!( - neuron_3.voting_power_percentage_multiplier, - DEFAULT_VOTING_POWER_PERCENTAGE_MULTIPLIER - ); // That they have the expected vesting periods assert_eq!(neuron_1.vesting_period_seconds, None); assert_eq!(neuron_2.vesting_period_seconds, Some(3 * ONE_YEAR_SECONDS)); - assert_eq!(neuron_3.vesting_period_seconds, None); } #[test] @@ -940,9 +776,7 @@ mod test { total_e8s: 1_000_000_000, initial_swap_amount_e8s: 100_000_000, }), - airdrop_distribution: Some(AirdropDistribution { - airdrop_neurons: Default::default(), - }), + airdrop_distribution: None, }; // A basic valid NervousSystemParameter @@ -1081,26 +915,6 @@ mod test { .validate(&nervous_system_parameters) .is_ok()); - // Using the same controller + memo in the AirdropDistribution and DeveloperDistribution should fail - // validation - initial_token_distribution.airdrop_distribution = Some(AirdropDistribution { - airdrop_neurons: vec![NeuronDistribution { - controller: Some(*TEST_NEURON_1_OWNER_PRINCIPAL), - stake_e8s: 50, - ..NeuronDistribution::with_valid_values_for_testing() - }], - }); - assert!(initial_token_distribution - .validate(&nervous_system_parameters) - .is_err()); - - initial_token_distribution.airdrop_distribution = Some(AirdropDistribution { - airdrop_neurons: Default::default(), - }); - assert!(initial_token_distribution - .validate(&nervous_system_parameters) - .is_ok()); - // There must be at least one neuron with the dissolve_delay greater than or equal to // neuron_minimum_dissolve_delay_to_vote_seconds. initial_token_distribution.developer_distribution = Some(DeveloperDistribution { @@ -1168,9 +982,7 @@ mod test { total_e8s: 1_000_000_000, initial_swap_amount_e8s: 100_000_000, }), - airdrop_distribution: Some(AirdropDistribution { - airdrop_neurons: Default::default(), - }), + airdrop_distribution: None, }; // A basic valid NervousSystemParameter @@ -1218,9 +1030,7 @@ mod test { total_e8s: 1_000_000_000, initial_swap_amount_e8s: 100_000_000, }), - airdrop_distribution: Some(AirdropDistribution { - airdrop_neurons: Default::default(), - }), + airdrop_distribution: None, }; // A basic valid NervousSystemParameter @@ -1265,142 +1075,7 @@ mod test { .is_err()); } - #[test] - fn test_fractional_developer_voting_power_airdrop_validation() { - // A basic valid FractionalDeveloperVotingPower - let mut initial_token_distribution = FractionalDeveloperVotingPower { - developer_distribution: Some(DeveloperDistribution { - developer_neurons: Default::default(), - }), - treasury_distribution: Some(TreasuryDistribution { total_e8s: 0 }), - swap_distribution: Some(SwapDistribution { - total_e8s: 1_000_000_000, - initial_swap_amount_e8s: 100_000_000, - }), - airdrop_distribution: Some(AirdropDistribution { - airdrop_neurons: vec![NeuronDistribution::with_valid_values_for_testing()], - }), - }; - - // A basic valid NervousSystemParameter - let nervous_system_parameters = NervousSystemParameters::with_default_values(); - - // Validate that the initial version is valid - assert!(initial_token_distribution - .validate(&nervous_system_parameters) - .is_ok()); - - // The airdrop_distribution being absent should fail validation - initial_token_distribution.airdrop_distribution = None; - assert!(initial_token_distribution - .validate(&nervous_system_parameters) - .is_err()); - - // Check that returning to a default is valid - initial_token_distribution.airdrop_distribution = Some(AirdropDistribution { - airdrop_neurons: vec![NeuronDistribution::with_valid_values_for_testing()], - }); - assert!(initial_token_distribution - .validate(&nervous_system_parameters) - .is_ok()); - - // Duplicate principals + memo should fail validation - initial_token_distribution.airdrop_distribution = Some(AirdropDistribution { - airdrop_neurons: vec![ - NeuronDistribution { - controller: Some(*TEST_NEURON_1_OWNER_PRINCIPAL), - memo: 0, - ..NeuronDistribution::with_valid_values_for_testing() - }, - NeuronDistribution { - controller: Some(*TEST_NEURON_1_OWNER_PRINCIPAL), - memo: 0, - ..NeuronDistribution::with_valid_values_for_testing() - }, - ], - }); - assert!(initial_token_distribution - .validate(&nervous_system_parameters) - .is_err()); - - // Unique principals + memo should pass validation - initial_token_distribution.airdrop_distribution = Some(AirdropDistribution { - airdrop_neurons: vec![ - NeuronDistribution { - controller: Some(*TEST_NEURON_1_OWNER_PRINCIPAL), - memo: 0, - ..NeuronDistribution::with_valid_values_for_testing() - }, - NeuronDistribution { - controller: Some(*TEST_NEURON_1_OWNER_PRINCIPAL), - memo: 1, - ..NeuronDistribution::with_valid_values_for_testing() - }, - NeuronDistribution { - controller: Some(*TEST_NEURON_2_OWNER_PRINCIPAL), - memo: 1, - ..NeuronDistribution::with_valid_values_for_testing() - }, - ], - }); - assert!(initial_token_distribution - .validate(&nervous_system_parameters) - .is_ok()); - - // The sum of the distributions MUST fit into a u64 - initial_token_distribution.airdrop_distribution = Some(AirdropDistribution { - airdrop_neurons: vec![ - NeuronDistribution { - controller: Some(*TEST_NEURON_1_OWNER_PRINCIPAL), - stake_e8s: u64::MAX, - ..NeuronDistribution::with_valid_values_for_testing() - }, - NeuronDistribution { - controller: Some(*TEST_NEURON_2_OWNER_PRINCIPAL), - stake_e8s: u64::MAX, - ..NeuronDistribution::with_valid_values_for_testing() - }, - ], - }); - assert!(initial_token_distribution - .validate(&nervous_system_parameters) - .is_err()); - - // Reset to a valid airdrop_distribution - initial_token_distribution.airdrop_distribution = Some(AirdropDistribution { - airdrop_neurons: vec![NeuronDistribution::with_valid_values_for_testing()], - }); - assert!(initial_token_distribution - .validate(&nervous_system_parameters) - .is_ok()); - - // Using the same controller in the AirdropDistribution and DeveloperDistribution should fail - // validation - initial_token_distribution.developer_distribution = Some(DeveloperDistribution { - developer_neurons: vec![NeuronDistribution::with_valid_values_for_testing()], - }); - assert!(initial_token_distribution - .validate(&nervous_system_parameters) - .is_err()); - - // Exceeding the maximum count of developer neurons should fail - let invalid_airdrop_neurons = (0..MAX_AIRDROP_DISTRIBUTION_COUNT + 1) - .map(|i| NeuronDistribution { - controller: Some(*TEST_NEURON_1_OWNER_PRINCIPAL), - memo: i as u64, - ..NeuronDistribution::with_valid_values_for_testing() - }) - .collect(); - initial_token_distribution.airdrop_distribution = Some(AirdropDistribution { - airdrop_neurons: invalid_airdrop_neurons, - }); - assert!(initial_token_distribution - .validate(&nervous_system_parameters) - .is_err()); - } - - /// Test that validation fails if Airdrop or Developer neurons are given memos in the incorrect - /// range. + /// Test that validation fails if developer neurons are given memos in the incorrect range. #[test] fn test_fractional_developer_voting_power_memos() { let mut distribution1 = NeuronDistribution { @@ -1411,14 +1086,6 @@ mod test { vesting_period_seconds: None, }; - let mut distribution2 = NeuronDistribution { - controller: Some(PrincipalId::new_user_test_id(2)), - stake_e8s: 100_000_000, - memo: 0, - dissolve_delay_seconds: ONE_MONTH_SECONDS * 6, - vesting_period_seconds: None, - }; - // A basic valid FractionalDeveloperVotingPower let mut initial_token_distribution = FractionalDeveloperVotingPower { developer_distribution: Some(DeveloperDistribution { @@ -1429,9 +1096,7 @@ mod test { total_e8s: 1_000_000_000, initial_swap_amount_e8s: 100_000_000, }), - airdrop_distribution: Some(AirdropDistribution { - airdrop_neurons: vec![distribution2.clone()], - }), + airdrop_distribution: None, }; // A basic valid NervousSystemParameter @@ -1457,16 +1122,5 @@ mod test { initial_token_distribution.developer_distribution = Some(DeveloperDistribution { developer_neurons: vec![distribution1], }); - - // An airdrop distribution with a memo in the Sale neuron memo range should fail validation - distribution2.memo = NEURON_BASKET_MEMO_RANGE_START + 888; - initial_token_distribution.airdrop_distribution = Some(AirdropDistribution { - airdrop_neurons: vec![distribution2], - }); - - assert_eq!(initial_token_distribution - .validate(&nervous_system_parameters) - .unwrap_err(), - "Error: Airdrop neuron with controller djduj-3qcaa-aaaaa-aaaap-4ai cannot have a memo in the range 1000000 to 10000000".to_string()); } } diff --git a/rs/sns/init/src/lib.rs b/rs/sns/init/src/lib.rs index 77bcde55220..31f9f793002 100644 --- a/rs/sns/init/src/lib.rs +++ b/rs/sns/init/src/lib.rs @@ -1011,11 +1011,6 @@ impl SnsInitPayload { .as_ref() .ok_or_else(|| "Error: developer_distribution must be specified".to_string())?; - let airdrop_distribution = f - .airdrop_distribution - .as_ref() - .ok_or_else(|| "Error: airdrop_distribution must be specified".to_string())?; - let min_stake_infringing_developer_neurons: Vec<(PrincipalId, u64)> = developer_distribution .developer_neurons @@ -1041,32 +1036,6 @@ impl SnsInitPayload { min_stake_infringing_developer_neurons, )); } - - let min_stake_infringing_airdrop_neurons: Vec<(PrincipalId, u64)> = - airdrop_distribution - .airdrop_neurons - .iter() - .filter_map(|neuron_distribution| { - if neuron_distribution.stake_e8s < neuron_minimum_stake_e8s { - // Safe to unwrap due to the checks done above - Some(( - neuron_distribution.controller.unwrap(), - neuron_distribution.stake_e8s, - )) - } else { - None - } - }) - .collect(); - - if !min_stake_infringing_airdrop_neurons.is_empty() { - return Err(format!( - "Error: {} airdrop neurons have a stake below the minimum stake ({} e8s): \n {:?}", - min_stake_infringing_airdrop_neurons.len(), - neuron_minimum_stake_e8s, - min_stake_infringing_airdrop_neurons, - )); - } } } @@ -1994,6 +1963,7 @@ mod test { }; use icrc_ledger_types::{icrc::generic_metadata_value::MetadataValue, icrc1::account::Account}; use isocountry::CountryCode; + use pretty_assertions::assert_eq; use std::{ collections::{BTreeMap, HashSet}, convert::TryInto, @@ -2271,8 +2241,7 @@ initial_token_distribution: !FractionalDeveloperVotingPower swap_distribution: total_e8s: 10000000000 initial_swap_amount_e8s: 10000000000 - airdrop_distribution: - airdrop_neurons: [] + airdrop_distribution: null ".to_string(); assert_eq!(observed, Ok(expected)); @@ -2805,39 +2774,19 @@ initial_token_distribution: !FractionalDeveloperVotingPower fn test_build_canister_payloads_creates_neurons_with_correct_ledger_accounts() { use num_traits::ToPrimitive; - let controller1 = PrincipalId::new_user_test_id(2209); - let airdrop_neuron1 = NeuronDistribution { - controller: Some(controller1), - stake_e8s: 100_000_000, - memo: 5, - dissolve_delay_seconds: 0, - vesting_period_seconds: None, - }; - let controller2 = PrincipalId::new_user_test_id(7184); - let airdrop_neuron2 = NeuronDistribution { - controller: Some(controller2), - stake_e8s: 770_000_000, - memo: 1644, - dissolve_delay_seconds: 9053, - vesting_period_seconds: None, - }; - let airdrop_neurons = AirdropDistribution { - airdrop_neurons: vec![airdrop_neuron1, airdrop_neuron2], - }; - let controller3 = PrincipalId::new_user_test_id(3209); - let developer_neuron1 = NeuronDistribution { - controller: Some(controller3), + let controller = PrincipalId::new_user_test_id(3209); + let developer_neuron = NeuronDistribution { + controller: Some(controller), stake_e8s: 330_000_000, memo: 8721, dissolve_delay_seconds: ONE_MONTH_SECONDS * 6, vesting_period_seconds: None, }; let developer_neurons = DeveloperDistribution { - developer_neurons: vec![developer_neuron1], + developer_neurons: vec![developer_neuron], }; let mut fdvp = FractionalDVP::with_valid_values_for_testing(); - fdvp.airdrop_distribution = Some(airdrop_neurons); fdvp.developer_distribution = Some(developer_neurons); // Build an sns_init_payload with defaults for non-governance related configuration. From bb5c2022a34d924b65508a6e299c925bb503441b Mon Sep 17 00:00:00 2001 From: Arshavir Ter-Gabrielyan Date: Wed, 26 Feb 2025 17:19:39 +0000 Subject: [PATCH 2/7] first --- rs/sns/init/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rs/sns/init/src/lib.rs b/rs/sns/init/src/lib.rs index 31f9f793002..21ee6ffc586 100644 --- a/rs/sns/init/src/lib.rs +++ b/rs/sns/init/src/lib.rs @@ -1932,8 +1932,8 @@ impl SnsInitPayload { mod test { use crate::{ pb::v1::{ - AirdropDistribution, DappCanisters, DeveloperDistribution, - FractionalDeveloperVotingPower as FractionalDVP, NeuronDistribution, SwapDistribution, + DappCanisters, DeveloperDistribution, FractionalDeveloperVotingPower as FractionalDVP, + NeuronDistribution, SwapDistribution, }, FractionalDeveloperVotingPower, MaxNeuronsFundParticipationValidationError, MinDirectParticipationThresholdValidationError, From 73888715852362b33795ca8379329d14ca155f11 Mon Sep 17 00:00:00 2001 From: Arshavir Ter-Gabrielyan Date: Thu, 27 Feb 2025 11:25:15 +0000 Subject: [PATCH 3/7] second --- rs/nns/sns-wasm/canister/sns-wasm.did | 4 +- rs/nns/sns-wasm/tests/upgrade_sns_instance.rs | 116 ++++++++---------- .../proto/ic_sns_init/pb/v1/sns_init.proto | 10 +- .../init/src/create_service_nervous_system.rs | 11 +- rs/sns/init/src/gen/ic_sns_init.pb.v1.rs | 10 +- rs/sns/swap/src/swap.rs | 2 +- .../scenarios/generate_airdrop_entries.sh | 17 --- .../scenarios/sns_lots_of_airdrops.yml | 40 ------ 8 files changed, 66 insertions(+), 144 deletions(-) delete mode 100644 testnet/tools/nns-tools/scenarios/generate_airdrop_entries.sh delete mode 100644 testnet/tools/nns-tools/scenarios/sns_lots_of_airdrops.yml diff --git a/rs/nns/sns-wasm/canister/sns-wasm.did b/rs/nns/sns-wasm/canister/sns-wasm.did index 7baa58ba1af..6ade3970e51 100644 --- a/rs/nns/sns-wasm/canister/sns-wasm.did +++ b/rs/nns/sns-wasm/canister/sns-wasm.did @@ -55,8 +55,10 @@ type DeveloperDistribution = record { type FractionalDeveloperVotingPower = record { treasury_distribution : opt TreasuryDistribution; developer_distribution : opt DeveloperDistribution; - airdrop_distribution : opt AirdropDistribution; swap_distribution : opt SwapDistribution; + + // Obsolete fields. + airdrop_distribution : opt AirdropDistribution; }; type GetAllowedPrincipalsResponse = record { diff --git a/rs/nns/sns-wasm/tests/upgrade_sns_instance.rs b/rs/nns/sns-wasm/tests/upgrade_sns_instance.rs index 9a508fac06f..3380937d7df 100644 --- a/rs/nns/sns-wasm/tests/upgrade_sns_instance.rs +++ b/rs/nns/sns-wasm/tests/upgrade_sns_instance.rs @@ -24,7 +24,7 @@ use ic_sns_governance::{ types::E8S_PER_TOKEN, }; use ic_sns_init::pb::v1::{ - sns_init_payload::InitialTokenDistribution, AirdropDistribution, DeveloperDistribution, + sns_init_payload::InitialTokenDistribution, DeveloperDistribution, FractionalDeveloperVotingPower, NeuronDistribution, SnsInitPayload, SwapDistribution, TreasuryDistribution, }; @@ -102,7 +102,13 @@ fn test_governance_restarts_root_if_root_cannot_stop_during_upgrade() { initial_token_distribution: Some(InitialTokenDistribution::FractionalDeveloperVotingPower( FractionalDeveloperVotingPower { developer_distribution: Some(DeveloperDistribution { - developer_neurons: Default::default(), + developer_neurons: vec![NeuronDistribution { + controller: Some(user), + stake_e8s: 10_000_000_000, + memo: 0, + dissolve_delay_seconds: 15780000, // 6 months + vesting_period_seconds: None, + }], }), treasury_distribution: Some(TreasuryDistribution { total_e8s: 500_000_000, @@ -111,15 +117,7 @@ fn test_governance_restarts_root_if_root_cannot_stop_during_upgrade() { total_e8s: 10_000_000_000, initial_swap_amount_e8s: 10_000_000_000, }), - airdrop_distribution: Some(AirdropDistribution { - airdrop_neurons: vec![NeuronDistribution { - controller: Some(user), - stake_e8s: 2_000_000_000_000, - memo: 0, - dissolve_delay_seconds: 15780000, // 6 months - vesting_period_seconds: None, - }], - }), + airdrop_distribution: None, }, )), ..SnsInitPayload::with_valid_values_for_testing_post_execution() @@ -127,7 +125,7 @@ fn test_governance_restarts_root_if_root_cannot_stop_during_upgrade() { // Will be used to make proposals and such. Fortunately, this guy has lots // of money -> he'll be able to push proposals though. - let airdrop_sns_neuron_id = sns_governance_pb::NeuronId { + let developer_sns_neuron_id = sns_governance_pb::NeuronId { id: compute_neuron_staking_subaccount(user, /* memo */ 0) .0 .to_vec(), @@ -167,7 +165,7 @@ fn test_governance_restarts_root_if_root_cannot_stop_during_upgrade() { &machine, governance, user, - airdrop_sns_neuron_id, + developer_sns_neuron_id, Proposal { title: "Upgrade Canister.".into(), action: Some(Action::UpgradeSnsToNextVersion(UpgradeSnsToNextVersion {})), @@ -242,24 +240,22 @@ fn run_upgrade_test(canister_type: SnsCanisterType) { initial_token_distribution: Some(InitialTokenDistribution::FractionalDeveloperVotingPower( FractionalDeveloperVotingPower { developer_distribution: Some(DeveloperDistribution { - developer_neurons: Default::default(), + developer_neurons: vec![NeuronDistribution { + controller: Some(user), + stake_e8s: 100_000_000_000, + memo: 0, + dissolve_delay_seconds: 15780000, // 6 months + vesting_period_seconds: None, + }], }), treasury_distribution: Some(TreasuryDistribution { total_e8s: 500_000_000, }), swap_distribution: Some(SwapDistribution { - total_e8s: 10_000_000_000, + total_e8s: 100_000_000_000, initial_swap_amount_e8s: 10_000_000_000, }), - airdrop_distribution: Some(AirdropDistribution { - airdrop_neurons: vec![NeuronDistribution { - controller: Some(user), - stake_e8s: 2_000_000_000_000, - memo: 0, - dissolve_delay_seconds: 15780000, // 6 months - vesting_period_seconds: None, - }], - }), + airdrop_distribution: None, }, )), ..SnsInitPayload::with_valid_values_for_testing_post_execution() @@ -485,18 +481,26 @@ fn upgrade_archive_sns_canister_via_sns_wasms() { let wasm_map = sns_wasm::add_real_wasms_to_sns_wasms(&machine); - // To get an SNS neuron, we airdrop our new tokens to this user. + // This user will act as the fallback controller and the big developer neuron controller. let user = PrincipalId::new_user_test_id(0); - let airdrop_neuron = |number| NeuronDistribution { + let mut developer_neurons = vec![NeuronDistribution { + controller: Some(user), + stake_e8s: 80_000_000_000, + memo: 0, + dissolve_delay_seconds: 15780000, // 6 months + vesting_period_seconds: None, + }]; + + // We make these to create some extra transactions so an archive will spawn. + let make_neuron_distribution = |number| NeuronDistribution { controller: Some(PrincipalId::new_user_test_id(number)), stake_e8s: 100_000_000, memo: 0, dissolve_delay_seconds: 15780000, // 6 months vesting_period_seconds: None, }; - // We make these to create some extra transactions so an archive will spawn. - let airdrop_neurons: Vec = (1..20_u64).map(airdrop_neuron).collect(); + developer_neurons.extend((1..20_u64).map(make_neuron_distribution)); let payload = SnsInitPayload { transaction_fee_e8s: Some(DEFAULT_TRANSFER_FEE.get_e8s()), @@ -507,28 +511,15 @@ fn upgrade_archive_sns_canister_via_sns_wasms() { fallback_controller_principal_ids: vec![user.to_string()], initial_token_distribution: Some(InitialTokenDistribution::FractionalDeveloperVotingPower( FractionalDeveloperVotingPower { - developer_distribution: Some(DeveloperDistribution { - developer_neurons: Default::default(), - }), + developer_distribution: Some(DeveloperDistribution { developer_neurons }), treasury_distribution: Some(TreasuryDistribution { total_e8s: 500_000_000, }), swap_distribution: Some(SwapDistribution { - total_e8s: 10_000_000_000, + total_e8s: 100_000_000_000, initial_swap_amount_e8s: 10_000_000_000, }), - airdrop_distribution: Some(AirdropDistribution { - airdrop_neurons: vec![NeuronDistribution { - controller: Some(user), - stake_e8s: 2_000_000_000_000, - memo: 0, - dissolve_delay_seconds: 15780000, // 6 months - vesting_period_seconds: None, - }] - .into_iter() - .chain(airdrop_neurons) - .collect(), - }), + airdrop_distribution: None, }, )), ..SnsInitPayload::with_valid_values_for_testing_post_execution() @@ -739,18 +730,26 @@ fn test_out_of_sync_version_still_allows_upgrade_to_succeed() { } let wasm_map = sns_wasm::add_freshly_built_sns_wasms(&machine, filter_wasm); - // To get an SNS neuron, we airdrop our new tokens to this user. + // This user will act as the fallback controller and the big developer neuron controller. let user = PrincipalId::new_user_test_id(0); - let airdrop_neuron = |number| NeuronDistribution { + let mut developer_neurons = vec![NeuronDistribution { + controller: Some(user), + stake_e8s: 80_000_000_000, + memo: 0, + dissolve_delay_seconds: 15780000, // 6 months + vesting_period_seconds: None, + }]; + + // We make these to create some extra transactions so an archive will spawn. + let make_neuron_distribution = |number| NeuronDistribution { controller: Some(PrincipalId::new_user_test_id(number)), stake_e8s: 100_000_000, memo: 0, dissolve_delay_seconds: 15780000, // 6 months vesting_period_seconds: None, }; - // We make these to create some extra transactions so an archive will spawn. - let airdrop_neurons: Vec = (1..20_u64).map(airdrop_neuron).collect(); + developer_neurons.extend((1..20_u64).map(make_neuron_distribution)); let payload = SnsInitPayload { transaction_fee_e8s: Some(DEFAULT_TRANSFER_FEE.get_e8s()), @@ -761,28 +760,15 @@ fn test_out_of_sync_version_still_allows_upgrade_to_succeed() { fallback_controller_principal_ids: vec![user.to_string()], initial_token_distribution: Some(InitialTokenDistribution::FractionalDeveloperVotingPower( FractionalDeveloperVotingPower { - developer_distribution: Some(DeveloperDistribution { - developer_neurons: Default::default(), - }), + developer_distribution: Some(DeveloperDistribution { developer_neurons }), treasury_distribution: Some(TreasuryDistribution { total_e8s: 500_000_000, }), swap_distribution: Some(SwapDistribution { - total_e8s: 10_000_000_000, - initial_swap_amount_e8s: 10_000_000_000, - }), - airdrop_distribution: Some(AirdropDistribution { - airdrop_neurons: vec![NeuronDistribution { - controller: Some(user), - stake_e8s: 2_000_000_000_000, - memo: 0, - dissolve_delay_seconds: 15780000, // 6 months - vesting_period_seconds: None, - }] - .into_iter() - .chain(airdrop_neurons) - .collect(), + total_e8s: 100_000_000_000, + initial_swap_amount_e8s: 100_000_000_000, }), + airdrop_distribution: None, }, )), ..SnsInitPayload::with_valid_values_for_testing_post_execution() diff --git a/rs/sns/init/proto/ic_sns_init/pb/v1/sns_init.proto b/rs/sns/init/proto/ic_sns_init/pb/v1/sns_init.proto index be9444002de..9ec5a9250f3 100644 --- a/rs/sns/init/proto/ic_sns_init/pb/v1/sns_init.proto +++ b/rs/sns/init/proto/ic_sns_init/pb/v1/sns_init.proto @@ -230,7 +230,7 @@ message SnsInitPayload { // The FractionalDeveloperVotingPower token distribution strategy configures // how tokens and neurons are distributed via four "buckets": developers, -// treasury, swap, and airdrops. This strategy will distribute all developer tokens +// treasury, and swap. This strategy will distribute all developer tokens // at genesis in restricted neurons with an additional voting power // multiplier applied. This voting power multiplier is calculated as // `swap_distribution.initial_swap_amount_e8s / swap_distribution.total_e8s`. @@ -239,7 +239,6 @@ message SnsInitPayload { // it to be a valid distribution: // - developer_distribution.developer_neurons.stake_e8s.sum <= u64:MAX // - developer_neurons.developer_neurons.stake_e8s.sum <= swap_distribution.total_e8s -// - airdrop_distribution.airdrop_neurons.stake_e8s.sum <= u64:MAX // - swap_distribution.initial_swap_amount_e8s > 0 // - swap_distribution.initial_swap_amount_e8s <= swap_distribution.total_e8s // - swap_distribution.total_e8s >= developer_distribution.developer_neurons.stake_e8s.sum @@ -253,7 +252,7 @@ message FractionalDeveloperVotingPower { // The swap bucket. SwapDistribution swap_distribution = 3; - // The airdrop bucket. + // OBSOLETE. AirdropDistribution airdrop_distribution = 4; } @@ -287,11 +286,8 @@ message SwapDistribution { uint64 initial_swap_amount_e8s = 2; } -// The distributions airdropped at SNS genesis. +// OBSOLETE. message AirdropDistribution { - // List of `NeuronDistribution` that specify a Neuron controller and Neuron stake in e8s - // (10E-8 of a token). For each entry in the airdrop_neurons list, a neuron will be - // created with NO voting multiplier applied and will start in PreInitializationSwap mode. repeated NeuronDistribution airdrop_neurons = 1; } diff --git a/rs/sns/init/src/create_service_nervous_system.rs b/rs/sns/init/src/create_service_nervous_system.rs index 441d2527c51..139e58a05a4 100644 --- a/rs/sns/init/src/create_service_nervous_system.rs +++ b/rs/sns/init/src/create_service_nervous_system.rs @@ -1,7 +1,6 @@ use crate::pb::v1::{ - sns_init_payload, AirdropDistribution, DappCanisters, DeveloperDistribution, - FractionalDeveloperVotingPower, NeuronDistribution, SnsInitPayload, SwapDistribution, - TreasuryDistribution, + sns_init_payload, DappCanisters, DeveloperDistribution, FractionalDeveloperVotingPower, + NeuronDistribution, SnsInitPayload, SwapDistribution, TreasuryDistribution, }; use ic_nns_governance_api::pb::v1::{create_service_nervous_system, CreateServiceNervousSystem}; @@ -321,8 +320,6 @@ impl TryFrom } }; - let airdrop_distribution = Some(AirdropDistribution::default()); - if !defects.is_empty() { return Err(format!( "Failed to convert to InitialTokenDistribution for the following reasons:\n{}", @@ -335,7 +332,9 @@ impl TryFrom developer_distribution, treasury_distribution, swap_distribution, - airdrop_distribution, + + // Obsolete fields. + airdrop_distribution: None, }, )) } diff --git a/rs/sns/init/src/gen/ic_sns_init.pb.v1.rs b/rs/sns/init/src/gen/ic_sns_init.pb.v1.rs index ce302ac5a8c..2b20e1f4780 100644 --- a/rs/sns/init/src/gen/ic_sns_init.pb.v1.rs +++ b/rs/sns/init/src/gen/ic_sns_init.pb.v1.rs @@ -243,7 +243,7 @@ pub mod sns_init_payload { } /// The FractionalDeveloperVotingPower token distribution strategy configures /// how tokens and neurons are distributed via four "buckets": developers, -/// treasury, swap, and airdrops. This strategy will distribute all developer tokens +/// treasury, and swap. This strategy will distribute all developer tokens /// at genesis in restricted neurons with an additional voting power /// multiplier applied. This voting power multiplier is calculated as /// `swap_distribution.initial_swap_amount_e8s / swap_distribution.total_e8s`. @@ -252,7 +252,6 @@ pub mod sns_init_payload { /// it to be a valid distribution: /// - developer_distribution.developer_neurons.stake_e8s.sum <= u64:MAX /// - developer_neurons.developer_neurons.stake_e8s.sum <= swap_distribution.total_e8s -/// - airdrop_distribution.airdrop_neurons.stake_e8s.sum <= u64:MAX /// - swap_distribution.initial_swap_amount_e8s > 0 /// - swap_distribution.initial_swap_amount_e8s <= swap_distribution.total_e8s /// - swap_distribution.total_e8s >= developer_distribution.developer_neurons.stake_e8s.sum @@ -275,7 +274,7 @@ pub struct FractionalDeveloperVotingPower { /// The swap bucket. #[prost(message, optional, tag = "3")] pub swap_distribution: ::core::option::Option, - /// The airdrop bucket. + /// OBSOLETE. #[prost(message, optional, tag = "4")] pub airdrop_distribution: ::core::option::Option, } @@ -339,7 +338,7 @@ pub struct SwapDistribution { #[prost(uint64, tag = "2")] pub initial_swap_amount_e8s: u64, } -/// The distributions airdropped at SNS genesis. +/// OBSOLETE. #[derive( candid::CandidType, candid::Deserialize, @@ -350,9 +349,6 @@ pub struct SwapDistribution { ::prost::Message, )] pub struct AirdropDistribution { - /// List of `NeuronDistribution` that specify a Neuron controller and Neuron stake in e8s - /// (10E-8 of a token). For each entry in the airdrop_neurons list, a neuron will be - /// created with NO voting multiplier applied and will start in PreInitializationSwap mode. #[prost(message, repeated, tag = "1")] pub airdrop_neurons: ::prost::alloc::vec::Vec, } diff --git a/rs/sns/swap/src/swap.rs b/rs/sns/swap/src/swap.rs index 324424faa2e..33be66aace7 100644 --- a/rs/sns/swap/src/swap.rs +++ b/rs/sns/swap/src/swap.rs @@ -83,7 +83,7 @@ const LIST_COMMUNITY_FUND_PARTICIPANTS_LIMIT_CAP: u32 = 10_000; const DEFAULT_LIST_SNS_NEURON_RECIPES_LIMIT: u32 = 10_000; /// Range of allowed memos for neurons distributed via an SNS swap. This range is used to choose -/// the memos of neurons in the neuron basket, and to enforce that other memos (e.g. for Airdrop +/// the memos of neurons in the neuron basket, and to enforce that other memos (e.g. for developer /// neurons) do not conflict with the neuron basket memos. pub const NEURON_BASKET_MEMO_RANGE_START: u64 = 1_000_000; pub const SALE_NEURON_MEMO_RANGE_END: u64 = 10_000_000; diff --git a/testnet/tools/nns-tools/scenarios/generate_airdrop_entries.sh b/testnet/tools/nns-tools/scenarios/generate_airdrop_entries.sh deleted file mode 100644 index bba88eab21c..00000000000 --- a/testnet/tools/nns-tools/scenarios/generate_airdrop_entries.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -set -Eeuo pipefail - -NNS_TOOLS_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) -source "$NNS_TOOLS_DIR/lib/include.sh" - -ensure_variable_set SNS_QUILL - -for i in {1..2000}; do - PRINCIPAL=$($SNS_QUILL generate --overwrite-pem-file --overwrite-seed-file | grep "Principal id:" | cut -d" " -f3) - echo " - controller: $PRINCIPAL" - echo " stake_e8s: 20000" - echo " memo: 0" - echo " dissolve_delay_seconds: 15780000 # 6 months" - -done diff --git a/testnet/tools/nns-tools/scenarios/sns_lots_of_airdrops.yml b/testnet/tools/nns-tools/scenarios/sns_lots_of_airdrops.yml deleted file mode 100644 index b9d77c1ef97..00000000000 --- a/testnet/tools/nns-tools/scenarios/sns_lots_of_airdrops.yml +++ /dev/null @@ -1,40 +0,0 @@ ---- -transaction_fee_e8s: 10000 -token_name: MyTestnetToken -token_symbol: MTT -proposal_reject_cost_e8s: 10000 -neuron_minimum_stake_e8s: 20000 -neuron_minimum_dissolve_delay_to_vote_seconds: 15778800 -logo: ~ -url: https://example.com -name: "My Testnet Tokens" -description: "What is the description supposed to be?" -reward_rate_transition_duration_seconds: 1 -initial_reward_rate_percentage: 0.0 -final_reward_rate_percentage: 0.0 -max_dissolve_delay_seconds: 252460800 -max_neuron_age_seconds_for_age_bonus: 126230400 -max_dissolve_delay_bonus_multiplier: 2.0 -max_age_bonus_multiplier: 1.25 - -fallback_controller_principal_ids: ["ye54c-us65k-r4log-cyhy6-vt33j-z7mwx-ymwzl-yjtti-24xs4-qemd2-rqe"] - -initial_voting_period_seconds: 345600 - -wait_for_quiet_deadline_increase_seconds: 86400 -initial_token_distribution: - FractionalDeveloperVotingPower: - developer_distribution: - developer_neurons: - - controller: ye54c-us65k-r4log-cyhy6-vt33j-z7mwx-ymwzl-yjtti-24xs4-qemd2-rqe - stake_e8s: 3000000000000 - memo: 0 - dissolve_delay_seconds: 15780000 # 6 months - treasury_distribution: - total_e8s: 20000 - swap_distribution: - total_e8s: 3000000000000 - initial_swap_amount_e8s: 3000000000000 - airdrop_distribution: - airdrop_neurons: -DELETE THIS LINE, then run `./generate_airdrop_entries.sh >>sns_lots_of_airdrops.yml` \ No newline at end of file From 5898d8bd3133e0b9e8e24d5ff2b8a13d09cb63a9 Mon Sep 17 00:00:00 2001 From: Arshavir Ter-Gabrielyan Date: Thu, 27 Feb 2025 11:29:08 +0000 Subject: [PATCH 4/7] second --- .../tests/constraints_dependencies.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/rs/nervous_system/integration_tests/tests/constraints_dependencies.rs b/rs/nervous_system/integration_tests/tests/constraints_dependencies.rs index fce178b276c..b063d83ed78 100644 --- a/rs/nervous_system/integration_tests/tests/constraints_dependencies.rs +++ b/rs/nervous_system/integration_tests/tests/constraints_dependencies.rs @@ -44,15 +44,11 @@ fn test_max_number_of_sns_neurons_adds_up() { >= MAX_SNS_NEURONS_PER_BASKET * MAX_NEURONS_FUND_PARTICIPANTS + MAX_NEURONS_FOR_DIRECT_PARTICIPANTS + MAX_DEVELOPER_DISTRIBUTION_COUNT as u64, - "MAX_NUMBER_OF_NEURONS_CEILING ({}) must be >= \ - MAX_SNS_NEURONS_PER_BASKET ({}) * MAX_NEURONS_FUND_PARTICIPANTS ({}) \ - + MAX_NEURONS_FOR_DIRECT_PARTICIPANTS ({}) \ - + MAX_DEVELOPER_DISTRIBUTION_COUNT ({})", - NervousSystemParameters::MAX_NUMBER_OF_NEURONS_CEILING, - MAX_SNS_NEURONS_PER_BASKET, - MAX_NEURONS_FUND_PARTICIPANTS, - MAX_NEURONS_FOR_DIRECT_PARTICIPANTS, - MAX_DEVELOPER_DISTRIBUTION_COUNT, - RECOMMENDATION + "MAX_NUMBER_OF_NEURONS_CEILING ({NervousSystemParameters::MAX_NUMBER_OF_NEURONS_CEILING}) \ + must be >= MAX_SNS_NEURONS_PER_BASKET ({MAX_SNS_NEURONS_PER_BASKET}) * \ + MAX_NEURONS_FUND_PARTICIPANTS ({MAX_NEURONS_FUND_PARTICIPANTS}) \ + + MAX_NEURONS_FOR_DIRECT_PARTICIPANTS ({MAX_NEURONS_FOR_DIRECT_PARTICIPANTS}) \ + + MAX_DEVELOPER_DISTRIBUTION_COUNT ({MAX_DEVELOPER_DISTRIBUTION_COUNT}).\n\ + {RECOMMENDATION}", ); } From 764aea0bd69d04d5c63450eab4cf80ddd0a2f1f9 Mon Sep 17 00:00:00 2001 From: Arshavir Ter-Gabrielyan Date: Thu, 27 Feb 2025 11:41:29 +0000 Subject: [PATCH 5/7] lint --- .../integration_tests/tests/constraints_dependencies.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rs/nervous_system/integration_tests/tests/constraints_dependencies.rs b/rs/nervous_system/integration_tests/tests/constraints_dependencies.rs index b063d83ed78..b62399b76b4 100644 --- a/rs/nervous_system/integration_tests/tests/constraints_dependencies.rs +++ b/rs/nervous_system/integration_tests/tests/constraints_dependencies.rs @@ -44,11 +44,12 @@ fn test_max_number_of_sns_neurons_adds_up() { >= MAX_SNS_NEURONS_PER_BASKET * MAX_NEURONS_FUND_PARTICIPANTS + MAX_NEURONS_FOR_DIRECT_PARTICIPANTS + MAX_DEVELOPER_DISTRIBUTION_COUNT as u64, - "MAX_NUMBER_OF_NEURONS_CEILING ({NervousSystemParameters::MAX_NUMBER_OF_NEURONS_CEILING}) \ - must be >= MAX_SNS_NEURONS_PER_BASKET ({MAX_SNS_NEURONS_PER_BASKET}) * \ - MAX_NEURONS_FUND_PARTICIPANTS ({MAX_NEURONS_FUND_PARTICIPANTS}) \ + "MAX_NUMBER_OF_NEURONS_CEILING ({}) must be >= \ + MAX_SNS_NEURONS_PER_BASKET ({MAX_SNS_NEURONS_PER_BASKET}) * \ + MAX_NEURONS_FUND_PARTICIPANTS ({MAX_NEURONS_FUND_PARTICIPANTS}) \ + MAX_NEURONS_FOR_DIRECT_PARTICIPANTS ({MAX_NEURONS_FOR_DIRECT_PARTICIPANTS}) \ + MAX_DEVELOPER_DISTRIBUTION_COUNT ({MAX_DEVELOPER_DISTRIBUTION_COUNT}).\n\ {RECOMMENDATION}", + NervousSystemParameters::MAX_NUMBER_OF_NEURONS_CEILING ); } From 022c4c9ff248973c2e424e2ef7f942b341787d14 Mon Sep 17 00:00:00 2001 From: Arshavir Ter-Gabrielyan Date: Tue, 4 Mar 2025 15:56:58 +0000 Subject: [PATCH 6/7] Fix tests --- rs/nns/governance/src/governance/tests/mod.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/rs/nns/governance/src/governance/tests/mod.rs b/rs/nns/governance/src/governance/tests/mod.rs index f90393a853a..4e3fa7da1c9 100644 --- a/rs/nns/governance/src/governance/tests/mod.rs +++ b/rs/nns/governance/src/governance/tests/mod.rs @@ -451,9 +451,7 @@ mod convert_from_create_service_nervous_system_to_sns_init_payload_tests { total_e8s: swap_total_e8s, initial_swap_amount_e8s: swap_total_e8s, },), - airdrop_distribution: Some(sns_init_pb::AirdropDistribution { - airdrop_neurons: vec![], - },), + airdrop_distribution: None, }, ), ); @@ -795,9 +793,7 @@ mod convert_create_service_nervous_system_proposal_to_sns_init_payload_tests_wit total_e8s: swap_total_e8s, initial_swap_amount_e8s: swap_total_e8s, },), - airdrop_distribution: Some(sns_init_pb::AirdropDistribution { - airdrop_neurons: vec![], - },), + airdrop_distribution: None, }, ), ); From 5c56ca108196f147b374a6a17cdd83c7467a9ed4 Mon Sep 17 00:00:00 2001 From: Arshavir Ter-Gabrielyan Date: Tue, 4 Mar 2025 16:50:50 +0000 Subject: [PATCH 7/7] notes --- rs/nns/sns-wasm/unreleased_changelog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rs/nns/sns-wasm/unreleased_changelog.md b/rs/nns/sns-wasm/unreleased_changelog.md index 94126a0ff42..0df4c79d72c 100644 --- a/rs/nns/sns-wasm/unreleased_changelog.md +++ b/rs/nns/sns-wasm/unreleased_changelog.md @@ -15,6 +15,8 @@ on the process that this file is part of, see ## Removed +* Remove (previously deprecated) airdrop neurons from initial SNS configuration. `SnsInitPayload.initial_token_distribution` must not specify any neurons in `airdrop_distribution`. + ## Fixed ## Security