From 2017526d5ca49e956692616bfd5bf052c98b83c5 Mon Sep 17 00:00:00 2001 From: jakubuid Date: Tue, 23 Sep 2025 10:57:29 +0200 Subject: [PATCH 1/5] add session emit --- crates/rust-sample-wallet/src/app.rs | 4 +- crates/yttrium/src/sign/client.rs | 60 +++++++++++++++++-- crates/yttrium/src/sign/client_errors.rs | 17 ++++++ crates/yttrium/src/sign/incoming.rs | 17 +++++- crates/yttrium/src/sign/protocol_types.rs | 23 +++++++ crates/yttrium/src/sign/relay.rs | 2 +- .../yttrium/src/uniffi_compat/sign/client.rs | 36 +++++++---- 7 files changed, 137 insertions(+), 22 deletions(-) diff --git a/crates/rust-sample-wallet/src/app.rs b/crates/rust-sample-wallet/src/app.rs index a6490c5a..438623ad 100644 --- a/crates/rust-sample-wallet/src/app.rs +++ b/crates/rust-sample-wallet/src/app.rs @@ -574,9 +574,9 @@ pub fn App() -> impl IntoView { "session delete on topic: {id}: {topic}", ); } - IncomingSessionMessage::SessionEvent(id, topic, params) => { + IncomingSessionMessage::SessionEvent(topic, name, data, chain_id) => { tracing::info!( - "session event on topic: {id}: {topic}: {params:?}", + "session event on topic: {topic}: name={name}, chainId={chain_id}, data={data}", ); } IncomingSessionMessage::SessionUpdate(id, topic, params) => { diff --git a/crates/yttrium/src/sign/client.rs b/crates/yttrium/src/sign/client.rs index de77ebf7..7b1adcd9 100644 --- a/crates/yttrium/src/sign/client.rs +++ b/crates/yttrium/src/sign/client.rs @@ -1,8 +1,9 @@ use { crate::sign::{ client_errors::{ - ApproveError, ConnectError, DisconnectError, ExtendError, - PairError, RejectError, RequestError, RespondError, UpdateError, + ApproveError, ConnectError, DisconnectError, EmitError, + ExtendError, PairError, RejectError, RequestError, RespondError, + UpdateError, }, client_types::{ ConnectParams, ConnectResult, PairingInfo, RejectionReason, @@ -804,10 +805,57 @@ impl Client { unimplemented!() } - pub async fn _emit(&self) { - // TODO implement - // https://github.com/WalletConnect/walletconnect-monorepo/blob/5bef698dcf0ae910548481959a6a5d87eaf7aaa5/packages/sign-client/src/controllers/engine.ts#L764 - unimplemented!() + pub async fn emit( + &mut self, + topic: Topic, + name: String, + data: serde_json::Value, + chain_id: String, + ) -> Result<(), EmitError> { + let shared_secret = self + .session_store + .get_session(topic.clone()) + .map_err(EmitError::Storage)? + .map(|s| s.session_sym_key) + .ok_or(EmitError::SessionNotFound)?; + + let id = generate_rpc_id(); + let message = serialize_and_encrypt_message_type0_envelope( + shared_secret, + &crate::sign::protocol_types::SessionEventJsonRpc { + id, + jsonrpc: "2.0".to_string(), + method: "wc_sessionEmit".to_string(), + params: crate::sign::protocol_types::EventParams { + event: crate::sign::protocol_types::SessionEventVO { + name, + data, + }, + chain_id, + }, + }, + ) + .map_err(EmitError::ShouldNeverHappen)?; + + self.do_request::(relay_rpc::rpc::Params::Publish(Publish { + topic, + message, + attestation: None, + ttl_secs: 86400, + tag: 1110, + prompt: false, + analytics: Some(AnalyticsData { + correlation_id: Some(id.try_into().unwrap()), + chain_id: None, + rpc_methods: None, + tx_hashes: None, + contract_addresses: None, + }), + })) + .await + .map_err(EmitError::Request)?; + + Ok(()) } pub async fn disconnect( diff --git a/crates/yttrium/src/sign/client_errors.rs b/crates/yttrium/src/sign/client_errors.rs index 7f931080..cf7759ec 100644 --- a/crates/yttrium/src/sign/client_errors.rs +++ b/crates/yttrium/src/sign/client_errors.rs @@ -106,6 +106,23 @@ pub enum DisconnectError { Request(RequestError), } +#[derive(Debug, thiserror::Error)] +#[cfg_attr(feature = "uniffi", derive(uniffi_macros::Error))] +#[error("Sign emit error: {0}")] +pub enum EmitError { + #[error("Storage: {0}")] + Storage(StorageError), + + #[error("Session not found")] + SessionNotFound, + + #[error("Request: {0}")] + Request(RequestError), + + #[error("Should never happen: {0}")] + ShouldNeverHappen(String), +} + #[derive(Debug, thiserror::Error)] #[cfg_attr(feature = "uniffi", derive(uniffi_macros::Error))] #[error("Sign connect error: {0}")] diff --git a/crates/yttrium/src/sign/incoming.rs b/crates/yttrium/src/sign/incoming.rs index d9ac291d..e7e9de01 100644 --- a/crates/yttrium/src/sign/incoming.rs +++ b/crates/yttrium/src/sign/incoming.rs @@ -260,14 +260,25 @@ pub fn handle( Ok(()) } else if method.as_str() == Some("wc_sessionEmit") { // TODO dedup events based on JSON RPC history - // TODO emit event callback (blocking?) + // Parse wc_sessionEmit params + let params = serde_json::from_value::< + crate::sign::protocol_types::EventParams, + >(value.get("params").cloned().ok_or_else(|| HandleError::Client("params not found".to_string()))?) + .map_err(|e| HandleError::Client(format!("parse event params: {e}")))?; + + let name = params.event.name; + let data_str = serde_json::to_string(¶ms.event.data) + .map_err(|e| HandleError::Client(format!("serialize event data: {e}")))?; + let chain_id = params.chain_id; + session_request_tx .send(( sub_msg.data.topic.clone(), IncomingSessionMessage::SessionEvent( - 0, // TODO sub_msg.data.topic, - false, // TODO + name, + data_str, + chain_id, ), )) .map_err(|e| { diff --git a/crates/yttrium/src/sign/protocol_types.rs b/crates/yttrium/src/sign/protocol_types.rs index b751ff19..a4f1bb79 100644 --- a/crates/yttrium/src/sign/protocol_types.rs +++ b/crates/yttrium/src/sign/protocol_types.rs @@ -247,3 +247,26 @@ pub struct SessionExtendJsonRpc { pub method: String, pub params: SessionExtend, } + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct SessionEventVO { + pub name: String, + pub data: serde_json::Value, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct EventParams { + pub event: SessionEventVO, + pub chain_id: String, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct SessionEventJsonRpc { + pub id: u64, + pub jsonrpc: String, + pub method: String, + pub params: EventParams, +} diff --git a/crates/yttrium/src/sign/relay.rs b/crates/yttrium/src/sign/relay.rs index f09b978d..99cb2f0f 100644 --- a/crates/yttrium/src/sign/relay.rs +++ b/crates/yttrium/src/sign/relay.rs @@ -597,7 +597,7 @@ enum ConnectionState { pub enum IncomingSessionMessage { SessionRequest(SessionRequestJsonRpc), Disconnect(u64, Topic), - SessionEvent(u64, Topic, bool), + SessionEvent(Topic, String, String, String), SessionUpdate(u64, Topic, crate::sign::protocol_types::SettleNamespaces), SessionExtend(u64, Topic), SessionConnect(u64, Topic), diff --git a/crates/yttrium/src/uniffi_compat/sign/client.rs b/crates/yttrium/src/uniffi_compat/sign/client.rs index f7c3044e..0463448e 100644 --- a/crates/yttrium/src/uniffi_compat/sign/client.rs +++ b/crates/yttrium/src/uniffi_compat/sign/client.rs @@ -3,8 +3,8 @@ use { sign::{ client::{generate_client_id_key, Client}, client_errors::{ - ApproveError, ConnectError, DisconnectError, ExtendError, - PairError, RejectError, RequestError, RespondError, + ApproveError, ConnectError, DisconnectError, EmitError, + ExtendError, PairError, RejectError, RequestError, RespondError, UpdateError, }, client_types::{ConnectParams, SessionProposal}, @@ -33,7 +33,13 @@ pub trait SignListener: Send + Sync { ); fn on_session_disconnect(&self, id: u64, topic: String); - fn on_session_event(&self, id: u64, topic: String, params: bool); + fn on_session_event( + &self, + topic: String, + name: String, + data: String, + chain_id: String, + ); fn on_session_extend(&self, id: u64, topic: String); fn on_session_update( &self, @@ -120,15 +126,12 @@ impl SignClient { listener .on_session_disconnect(id, topic.to_string()); } - IncomingSessionMessage::SessionEvent( - id, - topic, - params, - ) => { + IncomingSessionMessage::SessionEvent(topic, name, data, chain_id) => { listener.on_session_event( - id, topic.to_string(), - params, + name, + data, + chain_id, ); } IncomingSessionMessage::SessionUpdate( @@ -249,6 +252,19 @@ impl SignClient { Ok(topic) } + pub async fn emit( + &self, + topic: String, + name: String, + data: String, + chain_id: String, + ) -> Result<(), EmitError> { + let mut client = self.client.lock().await; + let data_value = serde_json::from_str::(&data) + .map_err(|e| EmitError::ShouldNeverHappen(e.to_string()))?; + client.emit(topic.into(), name, data_value, chain_id).await + } + pub async fn disconnect( &self, topic: String, From bf8a9ec9d8e0d4f5cb5d120a74c0473d68628d08 Mon Sep 17 00:00:00 2001 From: jakubuid Date: Tue, 23 Sep 2025 11:47:55 +0200 Subject: [PATCH 2/5] fix parsing --- crates/yttrium/src/sign/client.rs | 2 +- crates/yttrium/src/sign/incoming.rs | 4 ++-- crates/yttrium/src/uniffi_compat/sign/client.rs | 6 ++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/crates/yttrium/src/sign/client.rs b/crates/yttrium/src/sign/client.rs index 7b1adcd9..c5cef886 100644 --- a/crates/yttrium/src/sign/client.rs +++ b/crates/yttrium/src/sign/client.rs @@ -825,7 +825,7 @@ impl Client { &crate::sign::protocol_types::SessionEventJsonRpc { id, jsonrpc: "2.0".to_string(), - method: "wc_sessionEmit".to_string(), + method: "wc_sessionEvent".to_string(), params: crate::sign::protocol_types::EventParams { event: crate::sign::protocol_types::SessionEventVO { name, diff --git a/crates/yttrium/src/sign/incoming.rs b/crates/yttrium/src/sign/incoming.rs index e7e9de01..8c711096 100644 --- a/crates/yttrium/src/sign/incoming.rs +++ b/crates/yttrium/src/sign/incoming.rs @@ -258,9 +258,9 @@ pub fn handle( ); } Ok(()) - } else if method.as_str() == Some("wc_sessionEmit") { + } else if method.as_str() == Some("wc_sessionEvent") { // TODO dedup events based on JSON RPC history - // Parse wc_sessionEmit params + // Parse wc_sessionEvent params let params = serde_json::from_value::< crate::sign::protocol_types::EventParams, >(value.get("params").cloned().ok_or_else(|| HandleError::Client("params not found".to_string()))?) diff --git a/crates/yttrium/src/uniffi_compat/sign/client.rs b/crates/yttrium/src/uniffi_compat/sign/client.rs index 0463448e..f88c9371 100644 --- a/crates/yttrium/src/uniffi_compat/sign/client.rs +++ b/crates/yttrium/src/uniffi_compat/sign/client.rs @@ -260,8 +260,10 @@ impl SignClient { chain_id: String, ) -> Result<(), EmitError> { let mut client = self.client.lock().await; - let data_value = serde_json::from_str::(&data) - .map_err(|e| EmitError::ShouldNeverHappen(e.to_string()))?; + let data_value = match serde_json::from_str::(&data) { + Ok(v) => v, + Err(_) => serde_json::Value::String(data.clone()), + }; client.emit(topic.into(), name, data_value, chain_id).await } From 69a178316ec3f319cbbbdbc824516294d69cad68 Mon Sep 17 00:00:00 2001 From: jakubuid Date: Tue, 23 Sep 2025 12:25:01 +0200 Subject: [PATCH 3/5] formatting --- crates/yttrium/src/sign/incoming.rs | 19 +++++++++++++------ .../yttrium/src/uniffi_compat/sign/client.rs | 14 ++++++++++---- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/crates/yttrium/src/sign/incoming.rs b/crates/yttrium/src/sign/incoming.rs index 8c711096..fdead36e 100644 --- a/crates/yttrium/src/sign/incoming.rs +++ b/crates/yttrium/src/sign/incoming.rs @@ -261,14 +261,21 @@ pub fn handle( } else if method.as_str() == Some("wc_sessionEvent") { // TODO dedup events based on JSON RPC history // Parse wc_sessionEvent params - let params = serde_json::from_value::< - crate::sign::protocol_types::EventParams, - >(value.get("params").cloned().ok_or_else(|| HandleError::Client("params not found".to_string()))?) - .map_err(|e| HandleError::Client(format!("parse event params: {e}")))?; + let params = + serde_json::from_value::< + crate::sign::protocol_types::EventParams, + >(value.get("params").cloned().ok_or_else( + || HandleError::Client("params not found".to_string()), + )?) + .map_err(|e| { + HandleError::Client(format!("parse event params: {e}")) + })?; let name = params.event.name; - let data_str = serde_json::to_string(¶ms.event.data) - .map_err(|e| HandleError::Client(format!("serialize event data: {e}")))?; + let data_str = + serde_json::to_string(¶ms.event.data).map_err(|e| { + HandleError::Client(format!("serialize event data: {e}")) + })?; let chain_id = params.chain_id; session_request_tx diff --git a/crates/yttrium/src/uniffi_compat/sign/client.rs b/crates/yttrium/src/uniffi_compat/sign/client.rs index f88c9371..d2b63f0a 100644 --- a/crates/yttrium/src/uniffi_compat/sign/client.rs +++ b/crates/yttrium/src/uniffi_compat/sign/client.rs @@ -4,8 +4,8 @@ use { client::{generate_client_id_key, Client}, client_errors::{ ApproveError, ConnectError, DisconnectError, EmitError, - ExtendError, PairError, RejectError, RequestError, RespondError, - UpdateError, + ExtendError, PairError, RejectError, RequestError, + RespondError, UpdateError, }, client_types::{ConnectParams, SessionProposal}, protocol_types::{Metadata, SessionRequest, SettleNamespace}, @@ -126,7 +126,12 @@ impl SignClient { listener .on_session_disconnect(id, topic.to_string()); } - IncomingSessionMessage::SessionEvent(topic, name, data, chain_id) => { + IncomingSessionMessage::SessionEvent( + topic, + name, + data, + chain_id, + ) => { listener.on_session_event( topic.to_string(), name, @@ -260,7 +265,8 @@ impl SignClient { chain_id: String, ) -> Result<(), EmitError> { let mut client = self.client.lock().await; - let data_value = match serde_json::from_str::(&data) { + let data_value = match serde_json::from_str::(&data) + { Ok(v) => v, Err(_) => serde_json::Value::String(data.clone()), }; From 937566e688cad4aa3e87baa1d953c66073c61c63 Mon Sep 17 00:00:00 2001 From: jakubuid Date: Wed, 24 Sep 2025 11:13:45 +0200 Subject: [PATCH 4/5] address pr comment --- crates/rust-sample-wallet/src/app.rs | 3 ++- crates/yttrium/src/sign/incoming.rs | 7 ++----- crates/yttrium/src/sign/relay.rs | 2 +- crates/yttrium/src/uniffi_compat/sign/client.rs | 9 ++------- 4 files changed, 7 insertions(+), 14 deletions(-) diff --git a/crates/rust-sample-wallet/src/app.rs b/crates/rust-sample-wallet/src/app.rs index 438623ad..dd0205ae 100644 --- a/crates/rust-sample-wallet/src/app.rs +++ b/crates/rust-sample-wallet/src/app.rs @@ -576,7 +576,8 @@ pub fn App() -> impl IntoView { } IncomingSessionMessage::SessionEvent(topic, name, data, chain_id) => { tracing::info!( - "session event on topic: {topic}: name={name}, chainId={chain_id}, data={data}", + "session event on topic: {topic}: name={name}, chainId={chain_id}, data={:?}", + data ); } IncomingSessionMessage::SessionUpdate(id, topic, params) => { diff --git a/crates/yttrium/src/sign/incoming.rs b/crates/yttrium/src/sign/incoming.rs index fdead36e..a5540dfd 100644 --- a/crates/yttrium/src/sign/incoming.rs +++ b/crates/yttrium/src/sign/incoming.rs @@ -272,10 +272,7 @@ pub fn handle( })?; let name = params.event.name; - let data_str = - serde_json::to_string(¶ms.event.data).map_err(|e| { - HandleError::Client(format!("serialize event data: {e}")) - })?; + let data_value = params.event.data; let chain_id = params.chain_id; session_request_tx @@ -284,7 +281,7 @@ pub fn handle( IncomingSessionMessage::SessionEvent( sub_msg.data.topic, name, - data_str, + data_value, chain_id, ), )) diff --git a/crates/yttrium/src/sign/relay.rs b/crates/yttrium/src/sign/relay.rs index e11e1e51..6b5c8134 100644 --- a/crates/yttrium/src/sign/relay.rs +++ b/crates/yttrium/src/sign/relay.rs @@ -597,7 +597,7 @@ enum ConnectionState { pub enum IncomingSessionMessage { SessionRequest(SessionRequestJsonRpc), Disconnect(u64, Topic), - SessionEvent(Topic, String, String, String), + SessionEvent(Topic, String, serde_json::Value, String), SessionUpdate(u64, Topic, crate::sign::protocol_types::SettleNamespaces), SessionExtend(u64, Topic), SessionConnect(u64, Topic), diff --git a/crates/yttrium/src/uniffi_compat/sign/client.rs b/crates/yttrium/src/uniffi_compat/sign/client.rs index d2b63f0a..16233a4a 100644 --- a/crates/yttrium/src/uniffi_compat/sign/client.rs +++ b/crates/yttrium/src/uniffi_compat/sign/client.rs @@ -126,16 +126,11 @@ impl SignClient { listener .on_session_disconnect(id, topic.to_string()); } - IncomingSessionMessage::SessionEvent( - topic, - name, - data, - chain_id, - ) => { + IncomingSessionMessage::SessionEvent(topic, name, data, chain_id) => { listener.on_session_event( topic.to_string(), name, - data, + serde_json::to_string(&data).unwrap_or_default(), chain_id, ); } From a36a941e5a87e9913056252ab28f93e8e1606a7d Mon Sep 17 00:00:00 2001 From: jakubuid Date: Wed, 24 Sep 2025 11:57:00 +0200 Subject: [PATCH 5/5] formatting --- crates/yttrium/src/uniffi_compat/sign/client.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/crates/yttrium/src/uniffi_compat/sign/client.rs b/crates/yttrium/src/uniffi_compat/sign/client.rs index 16233a4a..cf4f8b90 100644 --- a/crates/yttrium/src/uniffi_compat/sign/client.rs +++ b/crates/yttrium/src/uniffi_compat/sign/client.rs @@ -126,11 +126,17 @@ impl SignClient { listener .on_session_disconnect(id, topic.to_string()); } - IncomingSessionMessage::SessionEvent(topic, name, data, chain_id) => { + IncomingSessionMessage::SessionEvent( + topic, + name, + data, + chain_id, + ) => { listener.on_session_event( topic.to_string(), name, - serde_json::to_string(&data).unwrap_or_default(), + serde_json::to_string(&data) + .unwrap_or_default(), chain_id, ); }