Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions rs/nns/governance/api/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4572,6 +4572,18 @@ pub enum SelfDescribingValue {
Map(HashMap<String, SelfDescribingValue>),
}

impl From<&str> for SelfDescribingValue {
fn from(value: &str) -> Self {
SelfDescribingValue::Text(value.to_string())
}
}

impl From<u64> 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<String>,
Expand Down
1 change: 1 addition & 0 deletions rs/nns/governance/protobuf_generator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
11 changes: 11 additions & 0 deletions rs/nns/governance/src/gen/ic_nns_governance.pb.v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2238,6 +2238,7 @@ pub struct OpenSnsTokenSwap {
candid::Deserialize,
serde::Serialize,
comparable::Comparable,
ic_nns_governance_derive_self_describing::SelfDescribing,
Clone,
PartialEq,
::prost::Message,
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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())
}
}
54 changes: 53 additions & 1 deletion rs/nns/governance/src/proposals/self_describing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -315,6 +317,56 @@ where
Value::Int(bytes)
}

impl From<Duration> for SelfDescribingValue {
fn from(value: Duration) -> Self {
let Duration { seconds } = value;
ValueBuilder::new().add_field("seconds", seconds).build()
}
}

impl From<Tokens> for SelfDescribingValue {
fn from(value: Tokens) -> Self {
let Tokens { e8s } = value;
ValueBuilder::new().add_field("e8s", e8s).build()
}
}

impl From<Image> for SelfDescribingValue {
fn from(value: Image) -> Self {
let Image { base64_encoding } = value;
ValueBuilder::new()
.add_field("base64_encoding", base64_encoding)
.build()
}
}

impl From<Countries> for SelfDescribingValue {
fn from(value: Countries) -> Self {
let Countries { iso_codes } = value;
ValueBuilder::new()
.add_field("iso_codes", iso_codes)
.build()
}
}

impl From<GlobalTimeOfDay> 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<Canister> for SelfDescribingValue {
fn from(value: Canister) -> Self {
let Canister { id } = value;
Self::from(id)
}
}

#[path = "self_describing_tests.rs"]
#[cfg(test)]
pub mod tests;
140 changes: 139 additions & 1 deletion rs/nns/governance/src/proposals/self_describing_tests.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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.
Expand Down
Loading