diff --git a/Cargo.lock b/Cargo.lock index 9b1c448..1c64715 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -753,6 +753,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + [[package]] name = "derive_builder" version = "0.20.2" @@ -1102,6 +1112,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hstr" version = "0.2.12" @@ -1360,6 +1376,7 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", + "serde", ] [[package]] @@ -1771,6 +1788,12 @@ dependencies = [ "serde", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" version = "0.1.46" @@ -2038,6 +2061,12 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.20" @@ -2523,6 +2552,8 @@ dependencies = [ "prost", "rand", "serde", + "serde_json", + "serde_with", "thiserror 2.0.3", "tracing", "uuid", @@ -2630,6 +2661,36 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.6.0", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "sha1" version = "0.10.6" @@ -4001,6 +4062,37 @@ dependencies = [ "once_cell", ] +[[package]] +name = "time" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tinyvec" version = "1.8.0" diff --git a/README.md b/README.md index a083f3a..c84e7f6 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,7 @@ docker run \ ### 2. Compile and run the indexer In a separate terminal, run the following commands: ```bash -cargo run --bin kg-node -- \ - --rollup \ +cargo run --bin sink -- \ --reset-db \ --neo4j-uri neo4j://localhost:7687 \ --neo4j-user neo4j \ diff --git a/geo-substream.spkg b/geo-substream.spkg index c579f66..f596193 100644 Binary files a/geo-substream.spkg and b/geo-substream.spkg differ diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index f3d9e87..350b8d6 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -11,6 +11,8 @@ neo4rs = "0.8.0" prost = "0.13.3" rand = "0.8.5" serde = { version = "1.0.215", features = ["derive"] } +serde_json = "1.0.133" +serde_with = "3.11.0" thiserror = "2.0.3" tracing = "0.1.40" uuid = { version = "1.11.0", features = ["v4"] } diff --git a/sdk/proto/geo.proto b/sdk/proto/geo.proto index e3aa117..bda2ba5 100644 --- a/sdk/proto/geo.proto +++ b/sdk/proto/geo.proto @@ -2,21 +2,6 @@ syntax = "proto3"; package geo; -/** - * Profiles represent the users of Geo. Profiles are registered in the GeoProfileRegistry - * contract and are associated with a user's EVM-based address and the space where metadata - * representing their profile resides in. -*/ -message GeoProfileRegistered { - string requestor = 1; - string space = 2; - string id = 3; -} - -message GeoProfilesRegistered { - repeated GeoProfileRegistered profiles = 1; -} - /** * The new DAO-based contracts allow forking of spaces into successor spaces. This is so * users can create new spaces whose data is derived from another space. @@ -25,8 +10,9 @@ message GeoProfilesRegistered { * but it's generally applicable across any space. */ message SuccessorSpaceCreated { - string predecessorSpace = 1; - string pluginAddress = 2; + string predecessor_space = 1; + string plugin_address = 2; + string dao_address = 3; } message SuccessorSpacesCreated { @@ -42,8 +28,8 @@ message SuccessorSpacesCreated { * address with the address of the DAO contract. */ message GeoSpaceCreated { - string daoAddress = 1; - string spaceAddress = 2; + string dao_address = 1; + string space_address = 2; } message GeoSpacesCreated { @@ -63,9 +49,9 @@ message GeoSpacesCreated { * 2. Member access plugin – This defines the membership rules and behaviors for a DAO */ message GeoGovernancePluginCreated { - string daoAddress = 1; - string mainVotingAddress = 2; - string memberAccessAddress = 3; + string dao_address = 1; + string main_voting_address = 2; + string member_access_address = 3; } message GeoGovernancePluginsCreated { @@ -73,9 +59,9 @@ message GeoGovernancePluginsCreated { } message GeoPersonalSpaceAdminPluginCreated { - string daoAddress = 1; - string personalAdminAddress = 2; - string initialEditor = 3; + string dao_address = 1; + string personal_admin_address = 2; + string initial_editor = 3; } message GeoPersonalSpaceAdminPluginsCreated { @@ -104,52 +90,14 @@ message InitialEditorAdded { // when first creating the governance plugin. After that we only emit one // address at a time via proposals. repeated string addresses = 1; - string pluginAddress = 2; + string plugin_address = 2; + string dao_address = 3; } message InitialEditorsAdded { repeated InitialEditorAdded editors = 1; } -/** - * Proposals represent a proposal to change the state of a DAO-based space. Proposals can - * represent changes to content, membership (editor or member), governance changes, subspace - * membership, or anything else that can be executed by a DAO. - * - * Currently we use a simple majority voting model, where a proposal requires 51% of the - * available votes in order to pass. Only editors are allowed to vote on proposals, but editors - * _and_ members can create them. - * - * Proposals require encoding a "callback" that represents the action to be taken if the proposal - * succeeds. For example, if a proposal is to add a new editor to the space, the callback would - * be the encoded function call to add the editor to the space. - * - * ```ts - * { - * to: `0x123...`, // The address of the membership contract - * data: `0x123...`, // The encoded function call parameters - * } - * ``` - */ -message DaoAction { - string to = 1; - uint64 value = 2; - bytes data = 3; -} - -message ProposalCreated { - string proposal_id = 1; - string creator = 2; - string start_time = 3; - string end_time = 4; - string metadata_uri = 5; - string plugin_address = 6; -} - -message ProposalsCreated { - repeated ProposalCreated proposals = 1; -} - // Executed proposals have been approved and executed onchain in a DAO-based // space's main voting plugin. The DAO itself also emits the executed event, // but the ABI/interface is different. We really only care about the one @@ -171,25 +119,27 @@ message ProposalsExecuted { * only consume the `proposalId` in the content URI to map the processed * data to an existing proposal onchain and in the sink. */ -message ProposalProcessed { +message EditPublished { string content_uri = 1; string plugin_address = 2; + string dao_address = 3; } -message ProposalsProcessed { - repeated ProposalProcessed proposals = 1; +message EditsPublished { + repeated EditPublished edits = 1; } /** * Added or Removed Subspaces represent adding a space contracto to the hierarchy * of the DAO-based space. This is useful to "link" Spaces together in a - * tree of spaces, allowing us to curate the graph of their knowledge and + * tree of spaces, allowing us to curate the graph of their knowledge and * permissions. */ message SubspaceAdded { string subspace = 1; string plugin_address = 2; string change_type = 3; + string dao_address = 4; } message SubspacesAdded { @@ -200,6 +150,7 @@ message SubspaceRemoved { string subspace = 1; string plugin_address = 2; string change_type = 3; + string dao_address = 4; } message SubspacesRemoved { @@ -217,7 +168,7 @@ message VoteCast { string onchain_proposal_id = 1; string voter = 2; uint64 vote_option = 3; - string plugin_address = 5; + string plugin_address = 4; } message VotesCast { @@ -228,6 +179,7 @@ message MemberAdded { string member_address = 1; string main_voting_plugin_address = 2; string change_type = 3; + string dao_address = 4; } message MembersAdded { @@ -236,9 +188,9 @@ message MembersAdded { message MemberRemoved { string member_address = 1; - string dao_address = 2; - string plugin_address = 3; - string change_type = 4; + string plugin_address = 2; + string change_type = 3; + string dao_address = 4; } message MembersRemoved { @@ -249,6 +201,7 @@ message EditorAdded { string editor_address = 1; string main_voting_plugin_address = 2; string change_type = 3; + string dao_address = 4; } message EditorsAdded { @@ -257,30 +210,141 @@ message EditorsAdded { message EditorRemoved { string editor_address = 1; - string dao_address = 2; - string plugin_address = 3; - string change_type = 4; + string plugin_address = 2; + string change_type = 3; + string dao_address = 4; } message EditorsRemoved { repeated EditorRemoved editors = 1; } +message PublishEditProposalCreated { + string proposal_id = 1; + string creator = 2; + string start_time = 3; + string end_time = 4; + string content_uri = 5; + string dao_address = 6; + string plugin_address = 7; +} + +message PublishEditsProposalsCreated { + repeated PublishEditProposalCreated edits = 1; +} + +message AddMemberProposalCreated { + string proposal_id = 1; + string creator = 2; + string start_time = 3; + string end_time = 4; + string member = 5; + string dao_address = 6; + string plugin_address = 7; + string change_type = 8; +} + +message AddMemberProposalsCreated { + repeated AddMemberProposalCreated proposed_members = 1; +} + +message RemoveMemberProposalCreated { + string proposal_id = 1; + string creator = 2; + string start_time = 3; + string end_time = 4; + string member = 5; + string dao_address = 6; + string plugin_address = 7; + string change_type = 8; +} + +message RemoveMemberProposalsCreated { + repeated RemoveMemberProposalCreated proposed_members = 1; +} + +message AddEditorProposalCreated { + string proposal_id = 1; + string creator = 2; + string start_time = 3; + string end_time = 4; + string editor = 5; + string dao_address = 6; + string plugin_address = 7; + string change_type = 8; +} + +message AddEditorProposalsCreated { + repeated AddEditorProposalCreated proposed_editors = 1; +} + +message RemoveEditorProposalCreated { + string proposal_id = 1; + string creator = 2; + string start_time = 3; + string end_time = 4; + string editor = 5; + string dao_address = 6; + string plugin_address = 7; + string change_type = 8; +} + +message RemoveEditorProposalsCreated { + repeated RemoveEditorProposalCreated proposed_editors = 1; +} + +message AddSubspaceProposalCreated { + string proposal_id = 1; + string creator = 2; + string start_time = 3; + string end_time = 4; + string subspace = 5; + string dao_address = 6; + string plugin_address = 7; + string change_type = 8; +} + +message AddSubspaceProposalsCreated { + repeated AddSubspaceProposalCreated proposed_subspaces = 1; +} + +message RemoveSubspaceProposalCreated { + string proposal_id = 1; + string creator = 2; + string start_time = 3; + string end_time = 4; + string subspace = 5; + string dao_address = 6; + string plugin_address = 7; + string change_type = 8; +} + +message RemoveSubspaceProposalsCreated { + repeated RemoveSubspaceProposalCreated proposed_subspaces = 1; +} + message GeoOutput { - repeated GeoProfileRegistered profiles_registered = 1; - repeated GeoSpaceCreated spaces_created = 2; - repeated GeoGovernancePluginCreated governance_plugins_created = 3; - repeated InitialEditorAdded initial_editors_added = 4; - repeated ProposalCreated proposals_created = 5; - repeated VoteCast votes_cast = 6; - repeated ProposalProcessed proposals_processed = 7; - repeated SuccessorSpaceCreated successor_spaces_created = 8; - repeated SubspaceAdded subspaces_added = 9; - repeated SubspaceRemoved subspaces_removed = 10; - repeated ProposalExecuted executed_proposals = 11; - repeated MemberAdded members_added = 12; - repeated EditorAdded editors_added = 13; - repeated GeoPersonalSpaceAdminPluginCreated personal_plugins_created = 14; - repeated MemberRemoved members_removed = 15; - repeated EditorRemoved editors_removed = 16; + repeated GeoSpaceCreated spaces_created = 1; + repeated GeoGovernancePluginCreated governance_plugins_created = 2; + repeated InitialEditorAdded initial_editors_added = 3; + repeated VoteCast votes_cast = 4; + repeated EditPublished edits_published = 5; + repeated SuccessorSpaceCreated successor_spaces_created = 6; + repeated SubspaceAdded subspaces_added = 7; + repeated SubspaceRemoved subspaces_removed = 8; + repeated ProposalExecuted executed_proposals = 9; + repeated MemberAdded members_added = 10; + repeated EditorAdded editors_added = 11; + repeated GeoPersonalSpaceAdminPluginCreated personal_plugins_created = 12; + repeated MemberRemoved members_removed = 13; + repeated EditorRemoved editors_removed = 14; + + repeated PublishEditProposalCreated edits = 15; + + repeated AddMemberProposalCreated proposed_added_members = 16; + repeated RemoveMemberProposalCreated proposed_removed_members = 17; + repeated AddEditorProposalCreated proposed_added_editors = 18; + repeated RemoveEditorProposalCreated proposed_removed_editors = 19; + repeated AddSubspaceProposalCreated proposed_added_subspaces = 20; + repeated RemoveSubspaceProposalCreated proposed_removed_subspaces = 21; } diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 741a73f..47bdf41 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -4,6 +4,7 @@ pub mod graph_uri; pub mod ids; pub mod models; pub mod pb; +pub mod mapping; pub mod relation; pub use ids::network_ids; diff --git a/sink/src/kg/mapping.rs b/sdk/src/mapping.rs similarity index 51% rename from sink/src/kg/mapping.rs rename to sdk/src/mapping.rs index 10fb829..b92d43c 100644 --- a/sink/src/kg/mapping.rs +++ b/sdk/src/mapping.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; -use serde::Deserialize; +use serde::{ser::SerializeMap, Deserialize, Serialize}; +use serde_with::with_prefix; #[derive(Debug, Deserialize, PartialEq)] pub struct Relation { @@ -103,16 +104,6 @@ where } } -/// Neo4j node representing a GRC20 entity of type `T`. -#[derive(Debug, Deserialize, PartialEq)] -pub struct Attributes { - pub id: String, - pub space_id: String, - // pub space_id: String, - #[serde(flatten)] - pub attributes: T, -} - fn deserialize_labels<'de, D>(deserializer: D) -> Result, D::Error> where D: serde::Deserializer<'de>, @@ -195,12 +186,239 @@ impl Node { } } +/// Neo4j node representing a GRC20 entity of type `T`. +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] +pub struct Attributes { + pub id: String, + pub space_id: String, + // pub space_id: String, + #[serde(flatten)] + pub attributes: T, +} + +#[derive(Clone, Debug, PartialEq)] +pub struct Triple { + pub value: String, + pub r#type: ValueType, + pub options: Options, +} + +impl Serialize for Triple { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut map = serializer.serialize_map(None)?; + map.serialize_entry("", &self.value)?; + map.serialize_entry(".type", &self.r#type)?; + if let Some(ref format) = self.options.format { + map.serialize_entry(".options.format", format)?; + } + if let Some(ref unit) = self.options.unit { + map.serialize_entry(".options.unit", unit)?; + } + if let Some(ref language) = self.options.language { + map.serialize_entry(".options.language", language)?; + } + if let Some(ref space) = self.options.space { + map.serialize_entry(".options.space", space)?; + } + map.end() + } +} + +impl<'de> Deserialize<'de> for Triple { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + #[derive(Deserialize)] + struct TripleHelper { + #[serde(rename = "")] + value: String, + #[serde(rename = ".type")] + r#type: ValueType, + #[serde(rename = ".options.format")] + format: Option, + #[serde(rename = ".options.unit")] + unit: Option, + #[serde(rename = ".options.language")] + language: Option, + #[serde(rename = ".options.space")] + space: Option, + } + + let helper = TripleHelper::deserialize(deserializer)?; + Ok(Triple { + value: helper.value, + r#type: helper.r#type, + options: Options { + format: helper.format, + unit: helper.unit, + language: helper.language, + space: helper.space, + }, + }) + } +} + +#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq)] +pub struct Options { + pub format: Option, + pub unit: Option, + pub language: Option, + pub space: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum ValueType { + Text, + Number, + Checkbox, + Url, + Time, + Point, +} + #[cfg(test)] mod tests { use std::collections::HashMap; use super::*; + #[test] + pub fn test_serialize_triple() { + with_prefix!(foo_prefix "foo"); + #[derive(Debug, Deserialize, Serialize, PartialEq)] + struct Foo { + #[serde(flatten, with = "foo_prefix")] + foo: Triple, + } + + let value = Foo { + foo: Triple { + value: "Hello, World!".to_string(), + r#type: ValueType::Text, + options: Options { + format: Some("text".to_string()), + unit: Some("unit".to_string()), + ..Default::default() + }, + }, + }; + + let serialized = serde_json::to_value(&value).expect("Failed to serialize Value"); + + assert_eq!( + serialized, + serde_json::json!({ + "foo": "Hello, World!", + "foo.type": "TEXT", + "foo.options.format": "text", + "foo.options.unit": "unit", + }) + ) + } + + #[test] + pub fn test_serialize_triple_multiple_fields() { + with_prefix!(foo_prefix "foo"); + with_prefix!(bar_prefix "bar"); + #[derive(Debug, Deserialize, Serialize, PartialEq)] + struct Foo { + #[serde(flatten, with = "foo_prefix")] + foo: Triple, + + #[serde(flatten, with = "bar_prefix")] + bar: Triple, + + other_field: String, + } + + let value = Foo { + foo: Triple { + value: "Hello, World!".to_string(), + r#type: ValueType::Text, + options: Options { + format: Some("text".to_string()), + ..Default::default() + }, + }, + bar: Triple { + value: "123".to_string(), + r#type: ValueType::Number, + options: Options { + unit: Some("int".to_string()), + ..Default::default() + }, + }, + other_field: "other".to_string(), + }; + + let serialized = serde_json::to_value(&value).expect("Failed to serialize Value"); + + assert_eq!( + serialized, + serde_json::json!({ + "foo": "Hello, World!", + "foo.type": "TEXT", + "foo.options.format": "text", + "bar": "123", + "bar.type": "NUMBER", + "bar.options.unit": "int", + "other_field": "other", + }) + ) + } + + #[test] + pub fn test_serialize_triple_hashmap() { + with_prefix!(foo_prefix "foo"); + with_prefix!(bar_prefix "bar"); + #[derive(Debug, Deserialize, Serialize, PartialEq)] + struct Foo { + #[serde(flatten)] + fields: HashMap, + } + + let value = Foo { + fields: HashMap::from([ + ("foo".to_string(), Triple { + value: "Hello, World!".to_string(), + r#type: ValueType::Text, + options: Options { + format: Some("text".to_string()), + ..Default::default() + }, + }), + ("bar".to_string(), Triple { + value: "123".to_string(), + r#type: ValueType::Number, + options: Options { + unit: Some("int".to_string()), + ..Default::default() + }, + }) + ]) + }; + + let serialized = serde_json::to_value(&value).expect("Failed to serialize Value"); + + assert_eq!( + serialized, + serde_json::json!({ + "foo": "Hello, World!", + "foo.type": "TEXT", + "foo.options.format": "text", + "bar": "123", + "bar.type": "NUMBER", + "bar.options.unit": "int", + }) + ) + } + + #[test] pub fn test_node_conversion() { let node = neo4rs::Node::new(neo4rs::BoltNode { diff --git a/sdk/src/models.rs b/sdk/src/models.rs index eee28d8..fbb9ce7 100644 --- a/sdk/src/models.rs +++ b/sdk/src/models.rs @@ -5,9 +5,7 @@ use serde::{Deserialize, Serialize}; use web3_utils::checksum_address; use crate::{ - ids, - pb::{self, grc20}, - system_ids, + ids, mapping::Node, pb::{self, grc20}, system_ids }; pub struct BlockMetadata { @@ -47,9 +45,9 @@ pub enum SpaceType { #[derive(Clone, Default, Deserialize, Serialize)] #[serde(rename = "306598522df542f69ad72921c33ad84b", tag = "$type")] pub struct Space { - pub id: String, + // pub id: String, pub network: String, - #[serde(rename = "`65da3fab6e1c48b7921a6a3260119b48`")] + // #[serde(rename = "`65da3fab6e1c48b7921a6a3260119b48`")] pub r#type: SpaceType, /// The address of the space's DAO contract. pub dao_contract_address: String, diff --git a/sdk/src/pb/geo.rs b/sdk/src/pb/geo.rs index 04b4855..baf48be 100644 --- a/sdk/src/pb/geo.rs +++ b/sdk/src/pb/geo.rs @@ -1,26 +1,6 @@ // @generated // This file is @generated by prost-build. /// * -/// Profiles represent the users of Geo. Profiles are registered in the GeoProfileRegistry -/// contract and are associated with a user's EVM-based address and the space where metadata -/// representing their profile resides in. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GeoProfileRegistered { - #[prost(string, tag="1")] - pub requestor: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub space: ::prost::alloc::string::String, - #[prost(string, tag="3")] - pub id: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GeoProfilesRegistered { - #[prost(message, repeated, tag="1")] - pub profiles: ::prost::alloc::vec::Vec, -} -/// * /// The new DAO-based contracts allow forking of spaces into successor spaces. This is so /// users can create new spaces whose data is derived from another space. /// @@ -33,6 +13,8 @@ pub struct SuccessorSpaceCreated { pub predecessor_space: ::prost::alloc::string::String, #[prost(string, tag="2")] pub plugin_address: ::prost::alloc::string::String, + #[prost(string, tag="3")] + pub dao_address: ::prost::alloc::string::String, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -130,6 +112,8 @@ pub struct InitialEditorAdded { pub addresses: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, #[prost(string, tag="2")] pub plugin_address: ::prost::alloc::string::String, + #[prost(string, tag="3")] + pub dao_address: ::prost::alloc::string::String, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -137,57 +121,6 @@ pub struct InitialEditorsAdded { #[prost(message, repeated, tag="1")] pub editors: ::prost::alloc::vec::Vec, } -/// * -/// Proposals represent a proposal to change the state of a DAO-based space. Proposals can -/// represent changes to content, membership (editor or member), governance changes, subspace -/// membership, or anything else that can be executed by a DAO. -/// -/// Currently we use a simple majority voting model, where a proposal requires 51% of the -/// available votes in order to pass. Only editors are allowed to vote on proposals, but editors -/// _and_ members can create them. -/// -/// Proposals require encoding a "callback" that represents the action to be taken if the proposal -/// succeeds. For example, if a proposal is to add a new editor to the space, the callback would -/// be the encoded function call to add the editor to the space. -/// -/// ```ts -/// { -/// to: `0x123...`, // The address of the membership contract -/// data: `0x123...`, // The encoded function call parameters -/// } -/// ``` -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct DaoAction { - #[prost(string, tag="1")] - pub to: ::prost::alloc::string::String, - #[prost(uint64, tag="2")] - pub value: u64, - #[prost(bytes="vec", tag="3")] - pub data: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ProposalCreated { - #[prost(string, tag="1")] - pub proposal_id: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub creator: ::prost::alloc::string::String, - #[prost(string, tag="3")] - pub start_time: ::prost::alloc::string::String, - #[prost(string, tag="4")] - pub end_time: ::prost::alloc::string::String, - #[prost(string, tag="5")] - pub metadata_uri: ::prost::alloc::string::String, - #[prost(string, tag="6")] - pub plugin_address: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ProposalsCreated { - #[prost(message, repeated, tag="1")] - pub proposals: ::prost::alloc::vec::Vec, -} /// Executed proposals have been approved and executed onchain in a DAO-based /// space's main voting plugin. The DAO itself also emits the executed event, /// but the ABI/interface is different. We really only care about the one @@ -215,22 +148,24 @@ pub struct ProposalsExecuted { /// data to an existing proposal onchain and in the sink. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct ProposalProcessed { +pub struct EditPublished { #[prost(string, tag="1")] pub content_uri: ::prost::alloc::string::String, #[prost(string, tag="2")] pub plugin_address: ::prost::alloc::string::String, + #[prost(string, tag="3")] + pub dao_address: ::prost::alloc::string::String, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct ProposalsProcessed { +pub struct EditsPublished { #[prost(message, repeated, tag="1")] - pub proposals: ::prost::alloc::vec::Vec, + pub edits: ::prost::alloc::vec::Vec, } /// * /// Added or Removed Subspaces represent adding a space contracto to the hierarchy /// of the DAO-based space. This is useful to "link" Spaces together in a -/// tree of spaces, allowing us to curate the graph of their knowledge and +/// tree of spaces, allowing us to curate the graph of their knowledge and /// permissions. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -241,6 +176,8 @@ pub struct SubspaceAdded { pub plugin_address: ::prost::alloc::string::String, #[prost(string, tag="3")] pub change_type: ::prost::alloc::string::String, + #[prost(string, tag="4")] + pub dao_address: ::prost::alloc::string::String, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -257,6 +194,8 @@ pub struct SubspaceRemoved { pub plugin_address: ::prost::alloc::string::String, #[prost(string, tag="3")] pub change_type: ::prost::alloc::string::String, + #[prost(string, tag="4")] + pub dao_address: ::prost::alloc::string::String, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -279,7 +218,7 @@ pub struct VoteCast { pub voter: ::prost::alloc::string::String, #[prost(uint64, tag="3")] pub vote_option: u64, - #[prost(string, tag="5")] + #[prost(string, tag="4")] pub plugin_address: ::prost::alloc::string::String, } #[allow(clippy::derive_partial_eq_without_eq)] @@ -297,6 +236,8 @@ pub struct MemberAdded { pub main_voting_plugin_address: ::prost::alloc::string::String, #[prost(string, tag="3")] pub change_type: ::prost::alloc::string::String, + #[prost(string, tag="4")] + pub dao_address: ::prost::alloc::string::String, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -310,11 +251,11 @@ pub struct MemberRemoved { #[prost(string, tag="1")] pub member_address: ::prost::alloc::string::String, #[prost(string, tag="2")] - pub dao_address: ::prost::alloc::string::String, - #[prost(string, tag="3")] pub plugin_address: ::prost::alloc::string::String, - #[prost(string, tag="4")] + #[prost(string, tag="3")] pub change_type: ::prost::alloc::string::String, + #[prost(string, tag="4")] + pub dao_address: ::prost::alloc::string::String, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -331,6 +272,8 @@ pub struct EditorAdded { pub main_voting_plugin_address: ::prost::alloc::string::String, #[prost(string, tag="3")] pub change_type: ::prost::alloc::string::String, + #[prost(string, tag="4")] + pub dao_address: ::prost::alloc::string::String, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -344,52 +287,242 @@ pub struct EditorRemoved { #[prost(string, tag="1")] pub editor_address: ::prost::alloc::string::String, #[prost(string, tag="2")] + pub plugin_address: ::prost::alloc::string::String, + #[prost(string, tag="3")] + pub change_type: ::prost::alloc::string::String, + #[prost(string, tag="4")] pub dao_address: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EditorsRemoved { + #[prost(message, repeated, tag="1")] + pub editors: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PublishEditProposalCreated { + #[prost(string, tag="1")] + pub proposal_id: ::prost::alloc::string::String, + #[prost(string, tag="2")] + pub creator: ::prost::alloc::string::String, #[prost(string, tag="3")] + pub start_time: ::prost::alloc::string::String, + #[prost(string, tag="4")] + pub end_time: ::prost::alloc::string::String, + #[prost(string, tag="5")] + pub content_uri: ::prost::alloc::string::String, + #[prost(string, tag="6")] + pub dao_address: ::prost::alloc::string::String, + #[prost(string, tag="7")] pub plugin_address: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PublishEditsProposalsCreated { + #[prost(message, repeated, tag="1")] + pub edits: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AddMemberProposalCreated { + #[prost(string, tag="1")] + pub proposal_id: ::prost::alloc::string::String, + #[prost(string, tag="2")] + pub creator: ::prost::alloc::string::String, + #[prost(string, tag="3")] + pub start_time: ::prost::alloc::string::String, #[prost(string, tag="4")] + pub end_time: ::prost::alloc::string::String, + #[prost(string, tag="5")] + pub member: ::prost::alloc::string::String, + #[prost(string, tag="6")] + pub dao_address: ::prost::alloc::string::String, + #[prost(string, tag="7")] + pub plugin_address: ::prost::alloc::string::String, + #[prost(string, tag="8")] pub change_type: ::prost::alloc::string::String, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct EditorsRemoved { +pub struct AddMemberProposalsCreated { #[prost(message, repeated, tag="1")] - pub editors: ::prost::alloc::vec::Vec, + pub proposed_members: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RemoveMemberProposalCreated { + #[prost(string, tag="1")] + pub proposal_id: ::prost::alloc::string::String, + #[prost(string, tag="2")] + pub creator: ::prost::alloc::string::String, + #[prost(string, tag="3")] + pub start_time: ::prost::alloc::string::String, + #[prost(string, tag="4")] + pub end_time: ::prost::alloc::string::String, + #[prost(string, tag="5")] + pub member: ::prost::alloc::string::String, + #[prost(string, tag="6")] + pub dao_address: ::prost::alloc::string::String, + #[prost(string, tag="7")] + pub plugin_address: ::prost::alloc::string::String, + #[prost(string, tag="8")] + pub change_type: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RemoveMemberProposalsCreated { + #[prost(message, repeated, tag="1")] + pub proposed_members: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AddEditorProposalCreated { + #[prost(string, tag="1")] + pub proposal_id: ::prost::alloc::string::String, + #[prost(string, tag="2")] + pub creator: ::prost::alloc::string::String, + #[prost(string, tag="3")] + pub start_time: ::prost::alloc::string::String, + #[prost(string, tag="4")] + pub end_time: ::prost::alloc::string::String, + #[prost(string, tag="5")] + pub editor: ::prost::alloc::string::String, + #[prost(string, tag="6")] + pub dao_address: ::prost::alloc::string::String, + #[prost(string, tag="7")] + pub plugin_address: ::prost::alloc::string::String, + #[prost(string, tag="8")] + pub change_type: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AddEditorProposalsCreated { + #[prost(message, repeated, tag="1")] + pub proposed_editors: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RemoveEditorProposalCreated { + #[prost(string, tag="1")] + pub proposal_id: ::prost::alloc::string::String, + #[prost(string, tag="2")] + pub creator: ::prost::alloc::string::String, + #[prost(string, tag="3")] + pub start_time: ::prost::alloc::string::String, + #[prost(string, tag="4")] + pub end_time: ::prost::alloc::string::String, + #[prost(string, tag="5")] + pub editor: ::prost::alloc::string::String, + #[prost(string, tag="6")] + pub dao_address: ::prost::alloc::string::String, + #[prost(string, tag="7")] + pub plugin_address: ::prost::alloc::string::String, + #[prost(string, tag="8")] + pub change_type: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RemoveEditorProposalsCreated { + #[prost(message, repeated, tag="1")] + pub proposed_editors: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AddSubspaceProposalCreated { + #[prost(string, tag="1")] + pub proposal_id: ::prost::alloc::string::String, + #[prost(string, tag="2")] + pub creator: ::prost::alloc::string::String, + #[prost(string, tag="3")] + pub start_time: ::prost::alloc::string::String, + #[prost(string, tag="4")] + pub end_time: ::prost::alloc::string::String, + #[prost(string, tag="5")] + pub subspace: ::prost::alloc::string::String, + #[prost(string, tag="6")] + pub dao_address: ::prost::alloc::string::String, + #[prost(string, tag="7")] + pub plugin_address: ::prost::alloc::string::String, + #[prost(string, tag="8")] + pub change_type: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AddSubspaceProposalsCreated { + #[prost(message, repeated, tag="1")] + pub proposed_subspaces: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RemoveSubspaceProposalCreated { + #[prost(string, tag="1")] + pub proposal_id: ::prost::alloc::string::String, + #[prost(string, tag="2")] + pub creator: ::prost::alloc::string::String, + #[prost(string, tag="3")] + pub start_time: ::prost::alloc::string::String, + #[prost(string, tag="4")] + pub end_time: ::prost::alloc::string::String, + #[prost(string, tag="5")] + pub subspace: ::prost::alloc::string::String, + #[prost(string, tag="6")] + pub dao_address: ::prost::alloc::string::String, + #[prost(string, tag="7")] + pub plugin_address: ::prost::alloc::string::String, + #[prost(string, tag="8")] + pub change_type: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RemoveSubspaceProposalsCreated { + #[prost(message, repeated, tag="1")] + pub proposed_subspaces: ::prost::alloc::vec::Vec, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct GeoOutput { #[prost(message, repeated, tag="1")] - pub profiles_registered: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag="2")] pub spaces_created: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag="3")] + #[prost(message, repeated, tag="2")] pub governance_plugins_created: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag="4")] + #[prost(message, repeated, tag="3")] pub initial_editors_added: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="4")] + pub votes_cast: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag="5")] - pub proposals_created: ::prost::alloc::vec::Vec, + pub edits_published: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag="6")] - pub votes_cast: ::prost::alloc::vec::Vec, + pub successor_spaces_created: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag="7")] - pub proposals_processed: ::prost::alloc::vec::Vec, + pub subspaces_added: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag="8")] - pub successor_spaces_created: ::prost::alloc::vec::Vec, + pub subspaces_removed: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag="9")] - pub subspaces_added: ::prost::alloc::vec::Vec, + pub executed_proposals: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag="10")] - pub subspaces_removed: ::prost::alloc::vec::Vec, + pub members_added: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag="11")] - pub executed_proposals: ::prost::alloc::vec::Vec, + pub editors_added: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag="12")] - pub members_added: ::prost::alloc::vec::Vec, + pub personal_plugins_created: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag="13")] - pub editors_added: ::prost::alloc::vec::Vec, + pub members_removed: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag="14")] - pub personal_plugins_created: ::prost::alloc::vec::Vec, + pub editors_removed: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag="15")] - pub members_removed: ::prost::alloc::vec::Vec, + pub edits: ::prost::alloc::vec::Vec, #[prost(message, repeated, tag="16")] - pub editors_removed: ::prost::alloc::vec::Vec, + pub proposed_added_members: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="17")] + pub proposed_removed_members: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="18")] + pub proposed_added_editors: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="19")] + pub proposed_removed_editors: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="20")] + pub proposed_added_subspaces: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="21")] + pub proposed_removed_subspaces: ::prost::alloc::vec::Vec, } // @@protoc_insertion_point(module) diff --git a/sdk/src/pb/schema.rs b/sdk/src/pb/schema.rs deleted file mode 100644 index 04b4855..0000000 --- a/sdk/src/pb/schema.rs +++ /dev/null @@ -1,395 +0,0 @@ -// @generated -// This file is @generated by prost-build. -/// * -/// Profiles represent the users of Geo. Profiles are registered in the GeoProfileRegistry -/// contract and are associated with a user's EVM-based address and the space where metadata -/// representing their profile resides in. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GeoProfileRegistered { - #[prost(string, tag="1")] - pub requestor: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub space: ::prost::alloc::string::String, - #[prost(string, tag="3")] - pub id: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GeoProfilesRegistered { - #[prost(message, repeated, tag="1")] - pub profiles: ::prost::alloc::vec::Vec, -} -/// * -/// The new DAO-based contracts allow forking of spaces into successor spaces. This is so -/// users can create new spaces whose data is derived from another space. -/// -/// This is immediately useful when migrating from legacy spaces to the new DAO-based spaces, -/// but it's generally applicable across any space. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SuccessorSpaceCreated { - #[prost(string, tag="1")] - pub predecessor_space: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub plugin_address: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SuccessorSpacesCreated { - #[prost(message, repeated, tag="1")] - pub spaces: ::prost::alloc::vec::Vec, -} -/// * -/// The new DAO-based space contracts are based on Aragon's OSX architecture which uses -/// plugins to define functionality assigned to a DAO (See the top level comment for more -/// information on Aragon's DAO architecture). -/// -/// This event maps creation of the Space plugin and associates the Space plugin contract -/// address with the address of the DAO contract. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GeoSpaceCreated { - #[prost(string, tag="1")] - pub dao_address: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub space_address: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GeoSpacesCreated { - #[prost(message, repeated, tag="1")] - pub spaces: ::prost::alloc::vec::Vec, -} -/// * -/// The new DAO-based space contracts are based on Aragon's OSX architecture which uses -/// plugins to define functionality assigned to a DAO (See the top level comment for more -/// information on Aragon's DAO architecture). -/// -/// This event maps creation of any governance plugins and associates the governance plugins -/// contract addresses with the address of the DAO contract. -/// -/// As of January 23, 2024 there are two governance plugins: -/// 1. Voting plugin – This defines the voting and proposal rules and behaviors for a DAO -/// 2. Member access plugin – This defines the membership rules and behaviors for a DAO -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GeoGovernancePluginCreated { - #[prost(string, tag="1")] - pub dao_address: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub main_voting_address: ::prost::alloc::string::String, - #[prost(string, tag="3")] - pub member_access_address: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GeoGovernancePluginsCreated { - #[prost(message, repeated, tag="1")] - pub plugins: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GeoPersonalSpaceAdminPluginCreated { - #[prost(string, tag="1")] - pub dao_address: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub personal_admin_address: ::prost::alloc::string::String, - #[prost(string, tag="3")] - pub initial_editor: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GeoPersonalSpaceAdminPluginsCreated { - #[prost(message, repeated, tag="1")] - pub plugins: ::prost::alloc::vec::Vec, -} -/// * -/// This event represents adding editors to a DAO-based space -/// -/// The data model for DAO-based spaces works slightly differently than in legacy spaces. -/// This means there will be a period where we need to support both data models depending -/// on which space/contract we are working with. Eventually these data models will be merged -/// and usage of the legacy space contracts will be migrated to the DAO-based contracts, but -/// for now we are appending "V2" to permissions data models to denote it's used for the -/// DAO-based spaces. -/// -/// An editor has editing and voting permissions in a DAO-based space. Editors join a space -/// one of two ways: -/// 1. They submit a request to join the space as an editor which goes to a vote. The editors -/// in the space vote on whether to accept the new editor. -/// 2. They are added as a set of initial editors when first creating the space. This allows -/// space deployers to bootstrap a set of editors on space creation. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct InitialEditorAdded { - /// The event emits an array of addresses. We only emit multiple addresses - /// when first creating the governance plugin. After that we only emit one - /// address at a time via proposals. - #[prost(string, repeated, tag="1")] - pub addresses: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - #[prost(string, tag="2")] - pub plugin_address: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct InitialEditorsAdded { - #[prost(message, repeated, tag="1")] - pub editors: ::prost::alloc::vec::Vec, -} -/// * -/// Proposals represent a proposal to change the state of a DAO-based space. Proposals can -/// represent changes to content, membership (editor or member), governance changes, subspace -/// membership, or anything else that can be executed by a DAO. -/// -/// Currently we use a simple majority voting model, where a proposal requires 51% of the -/// available votes in order to pass. Only editors are allowed to vote on proposals, but editors -/// _and_ members can create them. -/// -/// Proposals require encoding a "callback" that represents the action to be taken if the proposal -/// succeeds. For example, if a proposal is to add a new editor to the space, the callback would -/// be the encoded function call to add the editor to the space. -/// -/// ```ts -/// { -/// to: `0x123...`, // The address of the membership contract -/// data: `0x123...`, // The encoded function call parameters -/// } -/// ``` -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct DaoAction { - #[prost(string, tag="1")] - pub to: ::prost::alloc::string::String, - #[prost(uint64, tag="2")] - pub value: u64, - #[prost(bytes="vec", tag="3")] - pub data: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ProposalCreated { - #[prost(string, tag="1")] - pub proposal_id: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub creator: ::prost::alloc::string::String, - #[prost(string, tag="3")] - pub start_time: ::prost::alloc::string::String, - #[prost(string, tag="4")] - pub end_time: ::prost::alloc::string::String, - #[prost(string, tag="5")] - pub metadata_uri: ::prost::alloc::string::String, - #[prost(string, tag="6")] - pub plugin_address: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ProposalsCreated { - #[prost(message, repeated, tag="1")] - pub proposals: ::prost::alloc::vec::Vec, -} -/// Executed proposals have been approved and executed onchain in a DAO-based -/// space's main voting plugin. The DAO itself also emits the executed event, -/// but the ABI/interface is different. We really only care about the one -/// from our plugins. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ProposalExecuted { - #[prost(string, tag="1")] - pub proposal_id: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub plugin_address: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ProposalsExecuted { - #[prost(message, repeated, tag="1")] - pub executed_proposals: ::prost::alloc::vec::Vec, -} -/// * -/// Processed Proposals represent content that has been approved by a DAO -/// and executed onchain. -/// -/// We use the content URI to represent the content that was approved. We -/// only consume the `proposalId` in the content URI to map the processed -/// data to an existing proposal onchain and in the sink. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ProposalProcessed { - #[prost(string, tag="1")] - pub content_uri: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub plugin_address: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ProposalsProcessed { - #[prost(message, repeated, tag="1")] - pub proposals: ::prost::alloc::vec::Vec, -} -/// * -/// Added or Removed Subspaces represent adding a space contracto to the hierarchy -/// of the DAO-based space. This is useful to "link" Spaces together in a -/// tree of spaces, allowing us to curate the graph of their knowledge and -/// permissions. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SubspaceAdded { - #[prost(string, tag="1")] - pub subspace: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub plugin_address: ::prost::alloc::string::String, - #[prost(string, tag="3")] - pub change_type: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SubspacesAdded { - #[prost(message, repeated, tag="1")] - pub subspaces: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SubspaceRemoved { - #[prost(string, tag="1")] - pub subspace: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub plugin_address: ::prost::alloc::string::String, - #[prost(string, tag="3")] - pub change_type: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SubspacesRemoved { - #[prost(message, repeated, tag="1")] - pub subspaces: ::prost::alloc::vec::Vec, -} -/// * -/// Votes represent a vote on a proposal in a DAO-based space. -/// -/// Currently we use a simple majority voting model, where a proposal requires 51% of the -/// available votes in order to pass. Only editors are allowed to vote on proposals, but editors -/// _and_ members can create them. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct VoteCast { - #[prost(string, tag="1")] - pub onchain_proposal_id: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub voter: ::prost::alloc::string::String, - #[prost(uint64, tag="3")] - pub vote_option: u64, - #[prost(string, tag="5")] - pub plugin_address: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct VotesCast { - #[prost(message, repeated, tag="1")] - pub votes: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct MemberAdded { - #[prost(string, tag="1")] - pub member_address: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub main_voting_plugin_address: ::prost::alloc::string::String, - #[prost(string, tag="3")] - pub change_type: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct MembersAdded { - #[prost(message, repeated, tag="1")] - pub members: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct MemberRemoved { - #[prost(string, tag="1")] - pub member_address: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub dao_address: ::prost::alloc::string::String, - #[prost(string, tag="3")] - pub plugin_address: ::prost::alloc::string::String, - #[prost(string, tag="4")] - pub change_type: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct MembersRemoved { - #[prost(message, repeated, tag="1")] - pub members: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct EditorAdded { - #[prost(string, tag="1")] - pub editor_address: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub main_voting_plugin_address: ::prost::alloc::string::String, - #[prost(string, tag="3")] - pub change_type: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct EditorsAdded { - #[prost(message, repeated, tag="1")] - pub editors: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct EditorRemoved { - #[prost(string, tag="1")] - pub editor_address: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub dao_address: ::prost::alloc::string::String, - #[prost(string, tag="3")] - pub plugin_address: ::prost::alloc::string::String, - #[prost(string, tag="4")] - pub change_type: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct EditorsRemoved { - #[prost(message, repeated, tag="1")] - pub editors: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GeoOutput { - #[prost(message, repeated, tag="1")] - pub profiles_registered: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag="2")] - pub spaces_created: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag="3")] - pub governance_plugins_created: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag="4")] - pub initial_editors_added: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag="5")] - pub proposals_created: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag="6")] - pub votes_cast: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag="7")] - pub proposals_processed: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag="8")] - pub successor_spaces_created: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag="9")] - pub subspaces_added: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag="10")] - pub subspaces_removed: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag="11")] - pub executed_proposals: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag="12")] - pub members_added: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag="13")] - pub editors_added: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag="14")] - pub personal_plugins_created: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag="15")] - pub members_removed: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag="16")] - pub editors_removed: ::prost::alloc::vec::Vec, -} -// @@protoc_insertion_point(module) diff --git a/sink/src/events/proposal_processed.rs b/sink/src/events/edit_published.rs similarity index 80% rename from sink/src/events/proposal_processed.rs rename to sink/src/events/edit_published.rs index 1e429b7..4a16ab8 100644 --- a/sink/src/events/proposal_processed.rs +++ b/sink/src/events/edit_published.rs @@ -1,22 +1,21 @@ use futures::{stream, StreamExt, TryStreamExt}; use ipfs::deserialize; use sdk::{ - models::{self, EditProposal}, - pb::{self, geo, grc20}, + mapping::Node, models::{self, EditProposal}, pb::{self, geo, grc20} }; use super::{handler::HandlerError, EventHandler}; impl EventHandler { - pub async fn handle_proposals_processed( + pub async fn handle_edits_published( &self, - proposals_processed: &[geo::ProposalProcessed], + edits_published: &[geo::EditPublished], _created_space_ids: &[String], block: &models::BlockMetadata, ) -> Result<(), HandlerError> { - let proposals = stream::iter(proposals_processed) + let proposals = stream::iter(edits_published) .then(|proposal| async { - let edits = self.fetch_edit_proposals(proposal).await?; + let edits = self.fetch_edit(proposal).await?; anyhow::Ok(edits) }) .try_collect::>() @@ -46,36 +45,36 @@ impl EventHandler { Ok(()) } - async fn fetch_edit_proposals( + async fn fetch_edit( &self, - proposal_processed: &geo::ProposalProcessed, + edit: &geo::EditPublished, ) -> Result, HandlerError> { let space = if let Some(space) = self .kg - .get_space_by_space_plugin_address(&proposal_processed.plugin_address) + .get_space_by_space_plugin_address(&edit.plugin_address) .await .map_err(|e| HandlerError::Other(format!("{e:?}").into()))? { space } else { tracing::warn!( - "Matching space in Proposal not found for plugin address {}", - proposal_processed.plugin_address + "Matching space in edit not found for plugin address {}", + edit.plugin_address ); return Ok(vec![]); }; let bytes = self .ipfs - .get_bytes(&proposal_processed.content_uri.replace("ipfs://", ""), true) + .get_bytes(&edit.content_uri.replace("ipfs://", ""), true) .await?; let metadata = if let Ok(metadata) = deserialize::(&bytes) { metadata } else { tracing::warn!( - "Invalid metadata for proposal {}", - proposal_processed.content_uri + "Invalid metadata for edit {}", + edit.content_uri ); return Ok(vec![]); }; @@ -86,9 +85,11 @@ impl EventHandler { Ok(vec![EditProposal { name: edit.name, proposal_id: edit.id, - space: space.id, + space: space.id().to_string(), space_address: space + .attributes() .space_plugin_address + .clone() .expect("Space plugin address not found"), creator: edit.authors[0].clone(), ops: edit.ops, @@ -110,8 +111,9 @@ impl EventHandler { .map(|edit| EditProposal { name: edit.name, proposal_id: edit.id, - space: space.id.clone(), + space: space.id().to_string(), space_address: space + .attributes() .space_plugin_address .clone() .expect("Space plugin address not found"), diff --git a/sink/src/events/editor_added.rs b/sink/src/events/editor_added.rs index 4141932..56791e5 100644 --- a/sink/src/events/editor_added.rs +++ b/sink/src/events/editor_added.rs @@ -21,7 +21,7 @@ impl EventHandler { let editor = models::GeoAccount::new(editor_added.editor_address.clone()); self.kg - .add_editor(&space.id, &editor, &models::SpaceEditor, block) + .add_editor(&space.id(), &editor, &models::SpaceEditor, block) .await .map_err(|e| HandlerError::Other(format!("{e:?}").into()))?; } diff --git a/sink/src/events/editor_removed.rs b/sink/src/events/editor_removed.rs index 4d0afd6..8cbaece 100644 --- a/sink/src/events/editor_removed.rs +++ b/sink/src/events/editor_removed.rs @@ -18,7 +18,7 @@ impl EventHandler { self.kg .remove_editor( &models::GeoAccount::id_from_address(&editor_removed.editor_address), - &space.id, + &space.id(), block, ) .await diff --git a/sink/src/events/handler.rs b/sink/src/events/handler.rs index b9787d3..f6859fe 100644 --- a/sink/src/events/handler.rs +++ b/sink/src/events/handler.rs @@ -66,17 +66,35 @@ impl substreams_utils::Sink for EventHandler { let value = GeoOutput::decode(output.value.as_slice())?; // Handle new space creation + tracing::info!( + "Block #{} ({}): Processing {} space created events", + block.block_number, + block.timestamp, + value.spaces_created.len() + ); let created_space_ids = self - .handle_spaces_created(&value.spaces_created, &value.proposals_processed, &block) + .handle_spaces_created(&value.spaces_created, &value.edits_published, &block) .await?; // Handle personal space creation + tracing::info!( + "Block #{} ({}): Processing {} personal space created events", + block.block_number, + block.timestamp, + value.personal_plugins_created.len() + ); stream::iter(&value.personal_plugins_created) .map(Ok) .try_for_each(|event| async { self.handle_personal_space_created(event, &block).await }) .await?; // Handle new governance plugin creation + tracing::info!( + "Block #{} ({}): Processing {} governance plugin created events", + block.block_number, + block.timestamp, + value.governance_plugins_created.len() + ); stream::iter(&value.governance_plugins_created) .map(Ok) .try_for_each(|event| async { @@ -84,19 +102,13 @@ impl substreams_utils::Sink for EventHandler { }) .await?; - // Handle subspaces creation - stream::iter(&value.subspaces_added) - .map(Ok) - .try_for_each(|event| async { self.handle_subspace_added(event, &block).await }) - .await?; - - // Handle subspace removal - stream::iter(&value.subspaces_removed) - .map(Ok) - .try_for_each(|event| async { self.handle_subspace_removed(event, &block).await }) - .await?; - // Handle initial editors added + tracing::info!( + "Block #{} ({}): Processing {} initial editors added events", + block.block_number, + block.timestamp, + value.initial_editors_added.len() + ); stream::iter(&value.initial_editors_added) .map(Ok) .try_for_each(|event| async { @@ -104,17 +116,13 @@ impl substreams_utils::Sink for EventHandler { }) .await?; - // Handle proposal creation - stream::iter(&value.proposals_created) - .map(Ok) - .try_for_each(|event| async { self.handle_proposal_created(event, &block).await }) - .await?; - - // Handle proposal processing - self.handle_proposals_processed(&value.proposals_processed, &created_space_ids, &block) - .await?; - // Handle members added + tracing::info!( + "Block #{} ({}): Processing {} members added events", + block.block_number, + block.timestamp, + value.members_added.len() + ); stream::iter(&value.members_added) .map(Ok) .try_for_each(|event| async { self.handle_member_added(event, &block).await }) @@ -138,12 +146,42 @@ impl substreams_utils::Sink for EventHandler { .try_for_each(|event| async { self.handle_editor_removed(event, &block).await }) .await?; + // Handle subspaces creation + stream::iter(&value.subspaces_added) + .map(Ok) + .try_for_each(|event| async { self.handle_subspace_added(event, &block).await }) + .await?; + + // Handle subspace removal + stream::iter(&value.subspaces_removed) + .map(Ok) + .try_for_each(|event| async { self.handle_subspace_removed(event, &block).await }) + .await?; + + // Handle proposal creation + // stream::iter(&value.proposals_created) + // .map(Ok) + // .try_for_each(|event| async { self.handle_proposal_created(event, &block).await }) + // .await?; + + // TODO: Handle AddMemberProposalCreated events + // TODO: Handle RemoveMemberProposalCreated events + // TODO: Handle AddEditorProposalCreated events + // TODO: Handle RemoveEditorProposalCreated events + // TODO: Handle AddSubspaceProposalCreated events + // TODO: Handle RemoveSubspaceProposalCreated events + // TODO: Handle PublishEditProposalCreated events + // Handle vote cast stream::iter(&value.votes_cast) .map(Ok) .try_for_each(|event| async { self.handle_vote_cast(event, &block).await }) .await?; + // Handle proposal processing + self.handle_edits_published(&value.edits_published, &created_space_ids, &block) + .await?; + // Handle executed proposal stream::iter(&value.executed_proposals) .map(Ok) diff --git a/sink/src/events/initial_editors_added.rs b/sink/src/events/initial_editors_added.rs index 7435071..2efb279 100644 --- a/sink/src/events/initial_editors_added.rs +++ b/sink/src/events/initial_editors_added.rs @@ -21,7 +21,7 @@ impl EventHandler { .try_for_each(|editor| async move { let editor = models::GeoAccount::new(editor.clone()); self.kg - .add_editor(&space.id, &editor, &models::SpaceEditor, block) + .add_editor(&space.id(), &editor, &models::SpaceEditor, block) .await .map_err(|e| HandlerError::Other(format!("{e:?}").into()))?; // TODO: Convert anyhow::Error to HandlerError properly @@ -34,7 +34,7 @@ impl EventHandler { block.block_number, block.timestamp, initial_editor_added.addresses.len(), - space.id + space.id() ); } else { tracing::warn!( diff --git a/sink/src/events/member_added.rs b/sink/src/events/member_added.rs index 3691969..518a58c 100644 --- a/sink/src/events/member_added.rs +++ b/sink/src/events/member_added.rs @@ -20,7 +20,7 @@ impl EventHandler { let member = models::GeoAccount::new(member_added.member_address.clone()); self.kg - .add_member(&space.id, &member, &models::SpaceMember, block) + .add_member(&space.id(), &member, &models::SpaceMember, block) .await .map_err(|e| HandlerError::Other(format!("{e:?}").into()))?; } diff --git a/sink/src/events/member_removed.rs b/sink/src/events/member_removed.rs index e3a0185..078051b 100644 --- a/sink/src/events/member_removed.rs +++ b/sink/src/events/member_removed.rs @@ -18,7 +18,7 @@ impl EventHandler { self.kg .remove_member( &models::GeoAccount::id_from_address(&member_removed.member_address), - &space.id, + &space.id(), block, ) .await diff --git a/sink/src/events/mod.rs b/sink/src/events/mod.rs index f4f5433..1b5bd70 100644 --- a/sink/src/events/mod.rs +++ b/sink/src/events/mod.rs @@ -5,9 +5,9 @@ mod editor_removed; mod initial_editors_added; mod member_added; mod member_removed; -mod proposal_created; +// mod proposal_created; mod proposal_executed; -mod proposal_processed; +mod edit_published; mod space_created; mod subspace_added; mod subspace_removed; diff --git a/sink/src/events/proposal_executed.rs b/sink/src/events/proposal_executed.rs index 3428660..1690147 100644 --- a/sink/src/events/proposal_executed.rs +++ b/sink/src/events/proposal_executed.rs @@ -1,6 +1,4 @@ -use sdk::{models, pb::geo, system_ids}; - -use crate::kg::mapping::Node; +use sdk::{models, pb::geo}; use super::{handler::HandlerError, EventHandler}; @@ -20,11 +18,11 @@ impl EventHandler { .map_err(|e| HandlerError::Other(format!("{e:?}").into()))?; if let Some(mut proposal) = proposal { - proposal.status = models::ProposalStatus::Executed; + proposal.attributes_mut().status = models::ProposalStatus::Executed; self.kg .upsert_node( block, - Node::new(&proposal.id, system_ids::INDEXER_SPACE_ID, proposal.clone()), + proposal, ) .await .map_err(|e| HandlerError::Other(format!("{e:?}").into()))?; diff --git a/sink/src/events/space_created.rs b/sink/src/events/space_created.rs index db04d55..bab0423 100644 --- a/sink/src/events/space_created.rs +++ b/sink/src/events/space_created.rs @@ -1,9 +1,9 @@ use std::collections::HashMap; -use crate::kg::mapping::Node; use futures::{stream, StreamExt, TryStreamExt}; use sdk::{ ids, + mapping::Node, models::{self, GeoAccount, Space, SpaceType}, network_ids, pb::{geo, grc20}, @@ -21,14 +21,14 @@ impl EventHandler { pub async fn handle_spaces_created( &self, spaces_created: &[geo::GeoSpaceCreated], - proposals_processed: &[geo::ProposalProcessed], + edits_published: &[geo::EditPublished], block: &models::BlockMetadata, ) -> Result, HandlerError> { // Match the space creation events with their corresponding initial proposal (if any) let initial_proposals = spaces_created .iter() .filter_map(|event| { - proposals_processed + edits_published .iter() .find(|proposal| { checksum_address(&proposal.plugin_address, None) @@ -81,7 +81,6 @@ impl EventHandler { &space_id, system_ids::INDEXER_SPACE_ID, Space { - id: space_id.to_string(), network: network_ids::GEO.to_string(), dao_contract_address: checksum_address(&event.dao_address, None), space_plugin_address: Some(checksum_address( @@ -121,7 +120,7 @@ impl EventHandler { .upsert_node( block, Node::new( - &space.id, + space.id(), system_ids::INDEXER_SPACE_ID, Space { r#type: SpaceType::Personal, @@ -129,7 +128,7 @@ impl EventHandler { &personal_space_created.personal_admin_address, None, )), - ..space.clone() + ..space.attributes().clone() }, ) .with_type(system_ids::INDEXED_SPACE), @@ -141,7 +140,7 @@ impl EventHandler { let editor = GeoAccount::new(personal_space_created.initial_editor.clone()); self.kg - .add_editor(&space.id, &editor, &models::SpaceEditor, block) + .add_editor(space.id(), &editor, &models::SpaceEditor, block) .await .map_err(|e| HandlerError::Other(format!("{e:?}").into()))?; // TODO: Convert anyhow::Error to HandlerError properly @@ -149,7 +148,7 @@ impl EventHandler { "Block #{} ({}): Creating personal admin space plugin for space {} with initial editor {}", block.block_number, block.timestamp, - space.id, + space.id(), editor.id, ); } else { @@ -173,21 +172,21 @@ impl EventHandler { .kg .get_space_by_dao_address(&governance_plugin_created.dao_address) .await - .map_err(|e| HandlerError::Other(format!("{e:?}").into()))?; // TODO: Convert anyhow::Error to HandlerError properly + .map_err(|e| HandlerError::Other(format!("Error fetching space with dao address = {}: {e:?}", checksum_address(&governance_plugin_created.dao_address, None)).into()))?; // TODO: Convert anyhow::Error to HandlerError properly if let Some(space) = space { tracing::info!( "Block #{} ({}): Creating governance plugin for space {}", block.block_number, block.timestamp, - space.id + space.id() ); self.kg .upsert_node( block, Node::new( - &space.id.clone(), + space.id(), system_ids::INDEXER_SPACE_ID, Space { voting_plugin_address: Some(checksum_address( @@ -198,13 +197,13 @@ impl EventHandler { &governance_plugin_created.member_access_address, None, )), - ..space + ..space.attributes().clone() }, ) .with_type(system_ids::INDEXED_SPACE), ) .await - .map_err(|e| HandlerError::Other(format!("{e:?}").into()))?; // TODO: Convert anyhow::Error to HandlerError properly + .map_err(|e| HandlerError::Other(format!("Error updating space: {e:?}").into()))?; // TODO: Convert anyhow::Error to HandlerError properly } else { tracing::warn!( "Block #{} ({}): Could not create governance plugin for unknown space with dao_address = {}", diff --git a/sink/src/events/subspace_added.rs b/sink/src/events/subspace_added.rs index ed7d451..9d3b9cf 100644 --- a/sink/src/events/subspace_added.rs +++ b/sink/src/events/subspace_added.rs @@ -16,7 +16,7 @@ impl EventHandler { ) { (Ok(Some(parent_space)), Ok(Some(subspace))) => { self.kg - .add_subspace(block, &parent_space.id, &subspace.id) + .add_subspace(block, &parent_space.id(), &subspace.id()) .await .map_err(|e| HandlerError::Other(format!("{e:?}").into()))?; // TODO: Convert anyhow::Error to HandlerError properly diff --git a/sink/src/events/subspace_removed.rs b/sink/src/events/subspace_removed.rs index be500f0..ba3c9f0 100644 --- a/sink/src/events/subspace_removed.rs +++ b/sink/src/events/subspace_removed.rs @@ -19,7 +19,7 @@ impl EventHandler { .run(neo4rs::query(&format!( "MATCH (subspace:`{INDEXED_SPACE}` {{parent_space: $space_id}}) DELETE subspace", INDEXED_SPACE = system_ids::INDEXED_SPACE, - )).param("space_id", space.id.clone())) + )).param("space_id", space.id())) .await .map_err(|e| HandlerError::Other(format!("{e:?}").into()))?; // TODO: Convert anyhow::Error to HandlerError properly @@ -28,7 +28,7 @@ impl EventHandler { block.block_number, block.timestamp, subspace_removed.subspace, - space.id.clone() + space.id() ); } else { tracing::warn!( diff --git a/sink/src/events/vote_cast.rs b/sink/src/events/vote_cast.rs index f5af4cd..90033f9 100644 --- a/sink/src/events/vote_cast.rs +++ b/sink/src/events/vote_cast.rs @@ -3,11 +3,10 @@ use sdk::{ ids, models, pb::geo, system_ids::{self, INDEXER_SPACE_ID}, + mapping::Relation, }; use web3_utils::checksum_address; -use crate::kg::mapping::Relation; - use super::{handler::HandlerError, EventHandler}; impl EventHandler { @@ -32,7 +31,7 @@ impl EventHandler { INDEXED_SPACE = system_ids::INDEXED_SPACE, )) .param("onchain_proposal_id", vote.onchain_proposal_id.clone()) - .param("space_id", space.id)) + .param("space_id", space.id())) .await .map_err(|e| HandlerError::Other(format!("{e:?}").into()))?; diff --git a/sink/src/kg/client.rs b/sink/src/kg/client.rs index f04ce31..0a149a2 100644 --- a/sink/src/kg/client.rs +++ b/sink/src/kg/client.rs @@ -9,13 +9,12 @@ use crate::{ use web3_utils::checksum_address; use sdk::{ - ids, + ids::{self, id}, models::{self, EditProposal, Proposal, Space}, system_ids, + mapping::{Node, Relation}, }; -use super::mapping::{Node, Relation}; - #[derive(Clone)] pub struct Client { pub neo4j: neo4rs::Graph, @@ -69,12 +68,11 @@ impl Client { pub async fn add_space( &self, block: &models::BlockMetadata, - space: Space, + space: Node, ) -> Result<(), DatabaseError> { self.upsert_node( block, - Node::new(&space.id, system_ids::INDEXER_SPACE_ID, space.clone()) - .with_type(system_ids::INDEXED_SPACE), + space, ) .await } @@ -82,23 +80,21 @@ impl Client { pub async fn get_space_by_dao_address( &self, dao_address: &str, - ) -> Result, DatabaseError> { + ) -> Result>, DatabaseError> { let query = neo4rs::query(&format!( "MATCH (n:`{INDEXED_SPACE}` {{dao_contract_address: $dao_contract_address}}) RETURN n", INDEXED_SPACE = system_ids::INDEXED_SPACE, )) .param("dao_contract_address", checksum_address(dao_address, None)); - - Ok(self - .find_node::(query) - .await? - .map(|node| node.attributes.attributes)) + + self.find_node::(query) + .await } pub async fn get_space_by_space_plugin_address( &self, plugin_address: &str, - ) -> Result, DatabaseError> { + ) -> Result>, DatabaseError> { let query = neo4rs::query(&format!( "MATCH (n:`{INDEXED_SPACE}` {{space_plugin_address: $space_plugin_address}}) RETURN n", INDEXED_SPACE = system_ids::INDEXED_SPACE, @@ -108,16 +104,15 @@ impl Client { checksum_address(plugin_address, None), ); - Ok(self + self .find_node::(query) - .await? - .map(|node| node.attributes.attributes)) + .await } pub async fn get_space_by_voting_plugin_address( &self, voting_plugin_address: &str, - ) -> Result, DatabaseError> { + ) -> Result>, DatabaseError> { let query = neo4rs::query(&format!( "MATCH (n:`{INDEXED_SPACE}` {{voting_plugin_address: $voting_plugin_address}}) RETURN n", INDEXED_SPACE = system_ids::INDEXED_SPACE, @@ -127,16 +122,15 @@ impl Client { checksum_address(voting_plugin_address, None), ); - Ok(self + self .find_node::(query) - .await? - .map(|node| node.attributes.attributes)) + .await } pub async fn get_space_by_member_access_plugin( &self, member_access_plugin: &str, - ) -> Result, DatabaseError> { + ) -> Result>, DatabaseError> { let query = neo4rs::query(&format!( "MATCH (n:`{INDEXED_SPACE}` {{member_access_plugin: $member_access_plugin}}) RETURN n", INDEXED_SPACE = system_ids::INDEXED_SPACE, @@ -146,16 +140,15 @@ impl Client { checksum_address(member_access_plugin, None), ); - Ok(self + self .find_node::(query) - .await? - .map(|node| node.attributes.attributes)) + .await } pub async fn get_space_by_personal_plugin_address( &self, personal_space_admin_plugin: &str, - ) -> Result, DatabaseError> { + ) -> Result>, DatabaseError> { let query = neo4rs::query(&format!( "MATCH (n:`{INDEXED_SPACE}` {{personal_space_admin_plugin: $personal_space_admin_plugin}}) RETURN n", INDEXED_SPACE = system_ids::INDEXED_SPACE, @@ -165,17 +158,16 @@ impl Client { checksum_address(personal_space_admin_plugin, None), ); - Ok(self + self .find_node::(query) - .await? - .map(|node| node.attributes.attributes)) + .await } pub async fn get_proposal_by_id_and_address( &self, proposal_id: &str, plugin_address: &str, - ) -> Result, DatabaseError> { + ) -> Result>, DatabaseError> { let query = neo4rs::query(&format!( "MATCH (n:`{PROPOSAL_TYPE}` {{onchain_proposal_id: $proposal_id, plugin_address: $plugin_address}}) RETURN n", PROPOSAL_TYPE = system_ids::PROPOSAL_TYPE, @@ -183,10 +175,9 @@ impl Client { .param("proposal_id", proposal_id) .param("plugin_address", plugin_address); - Ok(self + self .find_node::(query) - .await? - .map(|node| node.attributes.attributes)) + .await } pub async fn add_subspace( @@ -194,7 +185,7 @@ impl Client { block: &models::BlockMetadata, space_id: &str, subspace_id: &str, - ) -> anyhow::Result<()> { + ) -> Result<(), DatabaseError> { self.upsert_relation( block, Relation::new( @@ -206,9 +197,7 @@ impl Client { models::ParentSpace, ), ) - .await?; - - Ok(()) + .await } /// Add an editor to a space @@ -347,7 +336,7 @@ impl Client { member_id: &str, space_id: &str, block: &models::BlockMetadata, - ) -> anyhow::Result<()> { + ) -> Result<(), DatabaseError> { const REMOVE_MEMBER_QUERY: &str = const_format::formatcp!( r#" MATCH (m:`{GEO_ACCOUNT}` {{id: $member_id}}) -[r:`{MEMBER_RELATION}`]-> (s:`{INDEXED_SPACE}` {{id: $space_id}}) @@ -439,7 +428,7 @@ impl Client { &self, block: &models::BlockMetadata, relation: Relation, - ) -> anyhow::Result<()> { + ) -> Result<(), DatabaseError> { let query_string = format!( r#" MERGE (from {{id: $from_id}}) -[r:`{relation_type}` {{id: $id}}]-> (to {{id: $to_id}}) @@ -448,14 +437,12 @@ impl Client { `{CREATED_AT_BLOCK}`: $created_at_block }} SET r += {{ - `{SPACE}`: $space_id, `{UPDATED_AT}`: datetime($updated_at), `{UPDATED_AT_BLOCK}`: $updated_at_block }} SET r += $data "#, relation_type = relation.relation_type, - SPACE = system_ids::SPACE, CREATED_AT = system_ids::CREATED_AT_TIMESTAMP, CREATED_AT_BLOCK = system_ids::CREATED_AT_BLOCK, UPDATED_AT = system_ids::UPDATED_AT_TIMESTAMP, @@ -497,27 +484,28 @@ impl Client { }} SET n:$($labels) SET n += {{ - `{SPACE}`: $space_id, `{UPDATED_AT}`: datetime($updated_at), `{UPDATED_AT_BLOCK}`: $updated_at_block }} SET n += $data "#, - SPACE = system_ids::SPACE, + // SPACE = system_ids::SPACE, CREATED_AT = system_ids::CREATED_AT_TIMESTAMP, CREATED_AT_BLOCK = system_ids::CREATED_AT_BLOCK, UPDATED_AT = system_ids::UPDATED_AT_TIMESTAMP, UPDATED_AT_BLOCK = system_ids::UPDATED_AT_BLOCK, ); - let bolt_data = match serde_value_to_bolt(serde_json::to_value(node.attributes())?) { + let id = node.id().to_string(); + + let bolt_data = match serde_value_to_bolt(serde_json::to_value(node.attributes)?) { neo4rs::BoltType::Map(map) => neo4rs::BoltType::Map(map), _ => neo4rs::BoltType::Map(Default::default()), }; let query = neo4rs::query(UPSERT_NODE_QUERY) - .param("id", node.id()) - .param("space_id", node.space_id()) + .param("id", id) + // .param("space_id", node.space_id()) .param("created_at", block.timestamp.to_rfc3339()) .param("created_at_block", block.block_number.to_string()) .param("updated_at", block.timestamp.to_rfc3339()) @@ -548,7 +536,7 @@ impl Client { .next() .await? .map(|row| { - tracing::info!("Row: {:?}", row.to::()); + // tracing::info!("Row: {:?}", row); Ok::<_, DatabaseError>(Node::::try_from(row.to::()?)?) }) .transpose() @@ -671,10 +659,11 @@ impl Client { pub async fn get_name(&self, entity_id: &str) -> anyhow::Result> { #[derive(Debug, Deserialize)] struct Named { + #[serde(default)] name: Option, } - let query = neo4rs::query("MATCH (n { id: $id }) RETURN n.name").param("id", entity_id); + let query = neo4rs::query("MATCH (n { id: $id }) RETURN n").param("id", entity_id); match self .find_node::(query) diff --git a/sink/src/kg/mod.rs b/sink/src/kg/mod.rs index 1be1fad..be467d5 100644 --- a/sink/src/kg/mod.rs +++ b/sink/src/kg/mod.rs @@ -1,4 +1,3 @@ pub mod client; -pub mod mapping; pub use client::Client; diff --git a/sink/src/main.rs b/sink/src/main.rs index 6c19a27..16aa9d3 100644 --- a/sink/src/main.rs +++ b/sink/src/main.rs @@ -10,7 +10,7 @@ use tracing_subscriber::util::SubscriberInitExt; const PKG_FILE: &str = "geo-substream.spkg"; const MODULE_NAME: &str = "geo_out"; -const START_BLOCK: i64 = 25327; +const START_BLOCK: i64 = 28410; const STOP_BLOCK: u64 = 0; #[tokio::main] diff --git a/sink/src/ops/delete_triple.rs b/sink/src/ops/delete_triple.rs index 1c26429..1e6de26 100644 --- a/sink/src/ops/delete_triple.rs +++ b/sink/src/ops/delete_triple.rs @@ -1,4 +1,4 @@ -use crate::kg::mapping::DefaultAttributes; +use sdk::mapping::DefaultAttributes; use crate::ops::KgOp; pub struct DeleteTriple { diff --git a/sink/src/ops/set_triple.rs b/sink/src/ops/set_triple.rs index 05c77fb..2264579 100644 --- a/sink/src/ops/set_triple.rs +++ b/sink/src/ops/set_triple.rs @@ -1,9 +1,6 @@ -use sdk::system_ids; +use sdk::{mapping::DefaultAttributes, system_ids}; -use crate::{ - kg::mapping::DefaultAttributes, - ops::{KgOp, Value}, -}; +use crate::ops::{KgOp, Value}; pub struct SetTriple { pub entity_id: String,