diff --git a/rs/nns/governance/api/src/types.rs b/rs/nns/governance/api/src/types.rs index b15f9b960aef..92b53daa771e 100644 --- a/rs/nns/governance/api/src/types.rs +++ b/rs/nns/governance/api/src/types.rs @@ -4572,6 +4572,18 @@ pub enum SelfDescribingValue { Map(HashMap), } +impl From<&str> for SelfDescribingValue { + fn from(value: &str) -> Self { + SelfDescribingValue::Text(value.to_string()) + } +} + +impl From for SelfDescribingValue { + fn from(value: u64) -> Self { + SelfDescribingValue::Nat(Nat::from(value)) + } +} + #[derive(candid::CandidType, candid::Deserialize, serde::Serialize, Debug, Clone, PartialEq)] pub struct SelfDescribingProposalAction { pub type_name: Option, diff --git a/rs/nns/governance/protobuf_generator/src/lib.rs b/rs/nns/governance/protobuf_generator/src/lib.rs index 024c61b7a497..a186db6ed9f1 100644 --- a/rs/nns/governance/protobuf_generator/src/lib.rs +++ b/rs/nns/governance/protobuf_generator/src/lib.rs @@ -151,6 +151,7 @@ pub fn generate_prost_files(proto: ProtoPaths<'_>, out: &Path) { "NeuronsFundEconomics", "NeuronsFundMatchedFundingCurveCoefficients", "VotingPowerEconomics", + "CreateServiceNervousSystem", ]; for type_name in self_describing_types { config.type_attribute( diff --git a/rs/nns/governance/src/gen/ic_nns_governance.pb.v1.rs b/rs/nns/governance/src/gen/ic_nns_governance.pb.v1.rs index b7795d5807a1..1fd9e985cdb0 100644 --- a/rs/nns/governance/src/gen/ic_nns_governance.pb.v1.rs +++ b/rs/nns/governance/src/gen/ic_nns_governance.pb.v1.rs @@ -2238,6 +2238,7 @@ pub struct OpenSnsTokenSwap { candid::Deserialize, serde::Serialize, comparable::Comparable, + ic_nns_governance_derive_self_describing::SelfDescribing, Clone, PartialEq, ::prost::Message, @@ -2273,6 +2274,7 @@ pub mod create_service_nervous_system { candid::Deserialize, serde::Serialize, comparable::Comparable, + ic_nns_governance_derive_self_describing::SelfDescribing, Clone, PartialEq, ::prost::Message, @@ -2294,6 +2296,7 @@ pub mod create_service_nervous_system { candid::Deserialize, serde::Serialize, comparable::Comparable, + ic_nns_governance_derive_self_describing::SelfDescribing, Clone, PartialEq, ::prost::Message, @@ -2310,6 +2313,7 @@ pub mod create_service_nervous_system { candid::Deserialize, serde::Serialize, comparable::Comparable, + ic_nns_governance_derive_self_describing::SelfDescribing, Clone, PartialEq, ::prost::Message, @@ -2334,6 +2338,7 @@ pub mod create_service_nervous_system { candid::Deserialize, serde::Serialize, comparable::Comparable, + ic_nns_governance_derive_self_describing::SelfDescribing, Clone, Copy, PartialEq, @@ -2348,6 +2353,7 @@ pub mod create_service_nervous_system { candid::Deserialize, serde::Serialize, comparable::Comparable, + ic_nns_governance_derive_self_describing::SelfDescribing, Clone, Copy, PartialEq, @@ -2363,6 +2369,7 @@ pub mod create_service_nervous_system { candid::Deserialize, serde::Serialize, comparable::Comparable, + ic_nns_governance_derive_self_describing::SelfDescribing, Clone, PartialEq, ::prost::Message, @@ -2418,6 +2425,7 @@ pub mod create_service_nervous_system { candid::Deserialize, serde::Serialize, comparable::Comparable, + ic_nns_governance_derive_self_describing::SelfDescribing, Clone, Copy, PartialEq, @@ -2436,6 +2444,7 @@ pub mod create_service_nervous_system { candid::Deserialize, serde::Serialize, comparable::Comparable, + ic_nns_governance_derive_self_describing::SelfDescribing, Clone, PartialEq, ::prost::Message, @@ -2457,6 +2466,7 @@ pub mod create_service_nervous_system { candid::Deserialize, serde::Serialize, comparable::Comparable, + ic_nns_governance_derive_self_describing::SelfDescribing, Clone, Copy, PartialEq, @@ -2500,6 +2510,7 @@ pub mod create_service_nervous_system { candid::Deserialize, serde::Serialize, comparable::Comparable, + ic_nns_governance_derive_self_describing::SelfDescribing, Clone, Copy, PartialEq, diff --git a/rs/nns/governance/src/proposals/create_service_nervous_system.rs b/rs/nns/governance/src/proposals/create_service_nervous_system.rs index e39cb43f0443..13cfbc69c8a0 100644 --- a/rs/nns/governance/src/proposals/create_service_nervous_system.rs +++ b/rs/nns/governance/src/proposals/create_service_nervous_system.rs @@ -1,4 +1,8 @@ -use crate::pb::v1::CreateServiceNervousSystem; +use crate::{ + pb::v1::{CreateServiceNervousSystem, SelfDescribingValue}, + proposals::self_describing::LocallyDescribableProposalAction, +}; + use ic_nervous_system_proto::pb::v1::{Duration, GlobalTimeOfDay}; impl CreateServiceNervousSystem { @@ -24,3 +28,12 @@ impl CreateServiceNervousSystem { ) } } + +impl LocallyDescribableProposalAction for CreateServiceNervousSystem { + const TYPE_NAME: &'static str = "Create Service Nervous System (SNS)"; + const TYPE_DESCRIPTION: &'static str = "Create a new Service Nervous System (SNS)."; + + fn to_self_describing_value(&self) -> SelfDescribingValue { + SelfDescribingValue::from(self.clone()) + } +} diff --git a/rs/nns/governance/src/proposals/self_describing.rs b/rs/nns/governance/src/proposals/self_describing.rs index 42af3016271e..3cc76bf345ae 100644 --- a/rs/nns/governance/src/proposals/self_describing.rs +++ b/rs/nns/governance/src/proposals/self_describing.rs @@ -6,7 +6,9 @@ use crate::pb::v1::{ use ic_base_types::PrincipalId; use ic_cdk::println; -use ic_nervous_system_proto::pb::v1::{Decimal, Percentage}; +use ic_nervous_system_proto::pb::v1::{ + Canister, Countries, Decimal, Duration, GlobalTimeOfDay, Image, Percentage, Tokens, +}; use ic_nns_common::pb::v1::{NeuronId, ProposalId}; use icp_ledger::protobuf::AccountIdentifier; use std::{collections::HashMap, marker::PhantomData}; @@ -315,6 +317,56 @@ where Value::Int(bytes) } +impl From for SelfDescribingValue { + fn from(value: Duration) -> Self { + let Duration { seconds } = value; + ValueBuilder::new().add_field("seconds", seconds).build() + } +} + +impl From for SelfDescribingValue { + fn from(value: Tokens) -> Self { + let Tokens { e8s } = value; + ValueBuilder::new().add_field("e8s", e8s).build() + } +} + +impl From for SelfDescribingValue { + fn from(value: Image) -> Self { + let Image { base64_encoding } = value; + ValueBuilder::new() + .add_field("base64_encoding", base64_encoding) + .build() + } +} + +impl From for SelfDescribingValue { + fn from(value: Countries) -> Self { + let Countries { iso_codes } = value; + ValueBuilder::new() + .add_field("iso_codes", iso_codes) + .build() + } +} + +impl From for SelfDescribingValue { + fn from(value: GlobalTimeOfDay) -> Self { + let GlobalTimeOfDay { + seconds_after_utc_midnight, + } = value; + ValueBuilder::new() + .add_field("seconds_after_utc_midnight", seconds_after_utc_midnight) + .build() + } +} + +impl From for SelfDescribingValue { + fn from(value: Canister) -> Self { + let Canister { id } = value; + Self::from(id) + } +} + #[path = "self_describing_tests.rs"] #[cfg(test)] pub mod tests; diff --git a/rs/nns/governance/src/proposals/self_describing_tests.rs b/rs/nns/governance/src/proposals/self_describing_tests.rs index b32440e77e63..861a9fd266dd 100644 --- a/rs/nns/governance/src/proposals/self_describing_tests.rs +++ b/rs/nns/governance/src/proposals/self_describing_tests.rs @@ -1,6 +1,9 @@ use super::*; -use crate::pb::v1::{NetworkEconomics, SelfDescribingValue as SelfDescribingValuePb, Topic}; +use crate::{ + governance::test_data::{CREATE_SERVICE_NERVOUS_SYSTEM, IMAGE_1, IMAGE_2}, + pb::v1::{NetworkEconomics, SelfDescribingValue as SelfDescribingValuePb, Topic}, +}; use ic_base_types::PrincipalId; use ic_nns_governance_api::SelfDescribingValue; @@ -168,6 +171,141 @@ fn test_network_economics_to_self_describing_minimal() { ); } +#[test] +fn test_create_service_nervous_system_to_self_describing() { + assert_proposal_action_self_describing_value_is( + CREATE_SERVICE_NERVOUS_SYSTEM.clone(), + SelfDescribingValue::Map(hashmap! { + "name".to_string() => SelfDescribingValue::from("Hello, world!"), + "description".to_string() => SelfDescribingValue::from("Best app that you ever did saw."), + "url".to_string() => SelfDescribingValue::from("https://best.app"), + "logo".to_string() => SelfDescribingValue::Map(hashmap! { + "base64_encoding".to_string() => SelfDescribingValue::from(IMAGE_1), + }), + "fallback_controller_principal_ids".to_string() => SelfDescribingValue::Array(vec![ + SelfDescribingValue::from("iakpb-r4pky-cqaaa-aaaap-4ai"), + ]), + "dapp_canisters".to_string() => SelfDescribingValue::Array(vec![ + SelfDescribingValue::from("uc7f6-kaaaa-aaaaq-qaaaa-cai"), + ]), + "initial_token_distribution".to_string() => SelfDescribingValue::Map(hashmap! { + "developer_distribution".to_string() => SelfDescribingValue::Map(hashmap! { + "developer_neurons".to_string() => SelfDescribingValue::Array(vec![ + SelfDescribingValue::Map(hashmap! { + "controller".to_string() => SelfDescribingValue::from("qarve-vpdvu-gaaaa-aaaap-4ai"), + "dissolve_delay".to_string() => SelfDescribingValue::Map(hashmap! { + "seconds".to_string() => SelfDescribingValue::from(15_778_800_u64), + }), + "memo".to_string() => SelfDescribingValue::from(763535_u64), + "stake".to_string() => SelfDescribingValue::Map(hashmap! { + "e8s".to_string() => SelfDescribingValue::from(756575_u64), + }), + "vesting_period".to_string() => SelfDescribingValue::Map(hashmap! { + "seconds".to_string() => SelfDescribingValue::from(0_u64), + }), + }), + ]), + }), + "treasury_distribution".to_string() => SelfDescribingValue::Map(hashmap! { + "total".to_string() => SelfDescribingValue::Map(hashmap! { + "e8s".to_string() => SelfDescribingValue::from(307064_u64), + }), + }), + "swap_distribution".to_string() => SelfDescribingValue::Map(hashmap! { + "total".to_string() => SelfDescribingValue::Map(hashmap! { + "e8s".to_string() => SelfDescribingValue::from(1_840_880_000_u64), + }), + }), + }), + "ledger_parameters".to_string() => SelfDescribingValue::Map(hashmap! { + "transaction_fee".to_string() => SelfDescribingValue::Map(hashmap! { + "e8s".to_string() => SelfDescribingValue::from(11143_u64), + }), + "token_name".to_string() => SelfDescribingValue::from("Most valuable SNS of all time."), + "token_symbol".to_string() => SelfDescribingValue::from("Kanye"), + "token_logo".to_string() => SelfDescribingValue::Map(hashmap! { + "base64_encoding".to_string() => SelfDescribingValue::from(IMAGE_2), + }), + }), + "governance_parameters".to_string() => SelfDescribingValue::Map(hashmap! { + "proposal_rejection_fee".to_string() => SelfDescribingValue::Map(hashmap! { + "e8s".to_string() => SelfDescribingValue::from(372250_u64), + }), + "proposal_initial_voting_period".to_string() => SelfDescribingValue::Map(hashmap! { + "seconds".to_string() => SelfDescribingValue::from(709_499_u64), + }), + "proposal_wait_for_quiet_deadline_increase".to_string() => SelfDescribingValue::Map(hashmap! { + "seconds".to_string() => SelfDescribingValue::from(75_891_u64), + }), + "neuron_minimum_stake".to_string() => SelfDescribingValue::Map(hashmap! { + "e8s".to_string() => SelfDescribingValue::from(250_000_u64), + }), + "neuron_minimum_dissolve_delay_to_vote".to_string() => SelfDescribingValue::Map(hashmap! { + "seconds".to_string() => SelfDescribingValue::from(482538_u64), + }), + "neuron_maximum_dissolve_delay".to_string() => SelfDescribingValue::Map(hashmap! { + "seconds".to_string() => SelfDescribingValue::from(31_557_600_u64), + }), + "neuron_maximum_dissolve_delay_bonus".to_string() => SelfDescribingValue::Map(hashmap! { + "basis_points".to_string() => SelfDescribingValue::from(1800_u64), + }), + "neuron_maximum_age_for_age_bonus".to_string() => SelfDescribingValue::Map(hashmap! { + "seconds".to_string() => SelfDescribingValue::from(740908_u64), + }), + "neuron_maximum_age_bonus".to_string() => SelfDescribingValue::Map(hashmap! { + "basis_points".to_string() => SelfDescribingValue::from(5400_u64), + }), + "voting_reward_parameters".to_string() => SelfDescribingValue::Map(hashmap! { + "initial_reward_rate".to_string() => SelfDescribingValue::Map(hashmap! { + "basis_points".to_string() => SelfDescribingValue::from(2592_u64), + }), + "final_reward_rate".to_string() => SelfDescribingValue::Map(hashmap! { + "basis_points".to_string() => SelfDescribingValue::from(740_u64), + }), + "reward_rate_transition_duration".to_string() => SelfDescribingValue::Map(hashmap! { + "seconds".to_string() => SelfDescribingValue::from(378025_u64), + }), + }), + }), + "swap_parameters".to_string() => SelfDescribingValue::Map(hashmap! { + "minimum_participants".to_string() => SelfDescribingValue::from(50_u64), + "minimum_direct_participation_icp".to_string() => SelfDescribingValue::Map(hashmap! { + "e8s".to_string() => SelfDescribingValue::from(6_200_000_000_u64), + }), + "maximum_direct_participation_icp".to_string() => SelfDescribingValue::Map(hashmap! { + "e8s".to_string() => SelfDescribingValue::from(18_900_000_000_u64), + }), + "minimum_participant_icp".to_string() => SelfDescribingValue::Map(hashmap! { + "e8s".to_string() => SelfDescribingValue::from(100_000_000_u64), + }), + "maximum_participant_icp".to_string() => SelfDescribingValue::Map(hashmap! { + "e8s".to_string() => SelfDescribingValue::from(10_000_000_000_u64), + }), + "neuron_basket_construction_parameters".to_string() => SelfDescribingValue::Map(hashmap! { + "count".to_string() => SelfDescribingValue::from(2_u64), + "dissolve_delay_interval".to_string() => SelfDescribingValue::Map(hashmap! { + "seconds".to_string() => SelfDescribingValue::from(10_001_u64), + }), + }), + "confirmation_text".to_string() => SelfDescribingValue::from("Confirm you are a human"), + "restricted_countries".to_string() => SelfDescribingValue::Map(hashmap! { + "iso_codes".to_string() => SelfDescribingValue::Array(vec![SelfDescribingValue::from("CH")]), + }), + "start_time".to_string() => SelfDescribingValue::Map(hashmap! { + "seconds_after_utc_midnight".to_string() => SelfDescribingValue::from(0_u64), + }), + "duration".to_string() => SelfDescribingValue::Map(hashmap! { + "seconds".to_string() => SelfDescribingValue::from(604_800_u64), + }), + "neurons_fund_participation".to_string() => SelfDescribingValue::from(0_u64), + "minimum_icp".to_string() => SelfDescribingValue::Null, + "maximum_icp".to_string() => SelfDescribingValue::Null, + "neurons_fund_investment_icp".to_string() => SelfDescribingValue::Null, + }), + }), + ); +} + // Tests for the SelfDescribing derive macro /// Test struct with named fields.