signer_provider.rs (22086B)
1 use crate::RadrootsSdkError; 2 #[cfg(feature = "local-signer")] 3 use radroots_authority::RadrootsLocalEventSigner; 4 use radroots_authority::{ 5 RadrootsActorContext, RadrootsEventSigner, RadrootsSignerError, authorize_actor_for_draft, 6 authorize_signer_for_draft, sign_authorized_draft, validate_signed_event_matches_draft, 7 }; 8 use radroots_events::draft::{RadrootsFrozenEventDraft, RadrootsSignedNostrEvent}; 9 use radroots_events::ids::RadrootsPublicKey; 10 use radroots_events::kinds::{ 11 KIND_FARM, KIND_LISTING, KIND_ORDER_CANCELLATION, KIND_ORDER_DECISION, KIND_ORDER_REQUEST, 12 KIND_ORDER_REVISION_DECISION, KIND_ORDER_REVISION_PROPOSAL, 13 }; 14 use radroots_nostr::prelude::{RadrootsNostrEvent, RadrootsNostrKeys, radroots_event_from_nostr}; 15 use radroots_nostr_connect::prelude::{ 16 RadrootsNostrConnectClientRequest, RadrootsNostrConnectClientTarget, 17 RadrootsNostrConnectClientTransport, RadrootsNostrConnectClientTransportFuture, 18 RadrootsNostrConnectError, RadrootsNostrConnectMethod, RadrootsNostrConnectPermission, 19 RadrootsNostrConnectPermissions, RadrootsNostrConnectRequest, RadrootsNostrConnectResponse, 20 execute_request_with_transport, 21 }; 22 use serde_json::json; 23 use std::sync::Arc; 24 use std::time::Duration; 25 use tokio::time::timeout; 26 use uuid::Uuid; 27 28 pub type RadrootsSdkNip46TransportFuture<'a, T> = RadrootsNostrConnectClientTransportFuture<'a, T>; 29 30 pub const RADROOTS_SDK_MYC_NIP46_PRODUCT_SIGN_EVENT_KINDS: [u32; 7] = [ 31 KIND_FARM, 32 KIND_LISTING, 33 KIND_ORDER_REQUEST, 34 KIND_ORDER_DECISION, 35 KIND_ORDER_REVISION_PROPOSAL, 36 KIND_ORDER_REVISION_DECISION, 37 KIND_ORDER_CANCELLATION, 38 ]; 39 pub const RADROOTS_SDK_MYC_NIP46_DEFAULT_REQUEST_TIMEOUT_MS: u64 = 30_000; 40 41 #[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize)] 42 #[serde(rename_all = "snake_case")] 43 #[non_exhaustive] 44 pub enum RadrootsSdkSignerMode { 45 #[cfg(feature = "local-signer")] 46 LocalKey, 47 MycNip46, 48 } 49 50 impl RadrootsSdkSignerMode { 51 pub fn as_str(self) -> &'static str { 52 match self { 53 #[cfg(feature = "local-signer")] 54 Self::LocalKey => "local_key", 55 Self::MycNip46 => "myc_nip46", 56 } 57 } 58 } 59 60 #[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize)] 61 #[serde(rename_all = "snake_case")] 62 #[non_exhaustive] 63 pub enum RadrootsSdkSignerState { 64 Ready, 65 } 66 67 #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)] 68 pub struct RadrootsSdkSignerStatus { 69 pub mode: RadrootsSdkSignerMode, 70 pub state: RadrootsSdkSignerState, 71 pub signer_pubkey: String, 72 pub remote_signer_pubkey: Option<String>, 73 pub relay_count: usize, 74 } 75 76 #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)] 77 pub struct RadrootsSdkSignerCapability { 78 pub mode: RadrootsSdkSignerMode, 79 pub signer_pubkey: String, 80 pub remote_signer_pubkey: Option<String>, 81 pub relays: Vec<String>, 82 pub can_sign_events: bool, 83 pub nip46_permissions: Vec<String>, 84 } 85 86 #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)] 87 #[serde(rename_all = "snake_case", tag = "kind")] 88 pub enum RadrootsSdkSignerProgress { 89 RequestStarted { 90 mode: RadrootsSdkSignerMode, 91 }, 92 AuthChallenge { 93 mode: RadrootsSdkSignerMode, 94 url: String, 95 }, 96 RequestCompleted { 97 mode: RadrootsSdkSignerMode, 98 }, 99 } 100 101 pub trait RadrootsSdkSignerProgressSink { 102 fn on_signer_progress( 103 &mut self, 104 progress: RadrootsSdkSignerProgress, 105 ) -> Result<(), RadrootsSdkError>; 106 } 107 108 impl<F> RadrootsSdkSignerProgressSink for F 109 where 110 F: FnMut(RadrootsSdkSignerProgress) -> Result<(), RadrootsSdkError>, 111 { 112 fn on_signer_progress( 113 &mut self, 114 progress: RadrootsSdkSignerProgress, 115 ) -> Result<(), RadrootsSdkError> { 116 self(progress) 117 } 118 } 119 120 pub struct RadrootsSdkSignRequest<'a> { 121 pub operation_kind: &'a str, 122 pub actor: &'a RadrootsActorContext, 123 pub frozen_draft: &'a RadrootsFrozenEventDraft, 124 progress_sink: Option<&'a mut dyn RadrootsSdkSignerProgressSink>, 125 } 126 127 impl<'a> RadrootsSdkSignRequest<'a> { 128 pub fn new( 129 operation_kind: &'a str, 130 actor: &'a RadrootsActorContext, 131 frozen_draft: &'a RadrootsFrozenEventDraft, 132 ) -> Self { 133 Self { 134 operation_kind, 135 actor, 136 frozen_draft, 137 progress_sink: None, 138 } 139 } 140 141 pub fn with_progress_sink( 142 mut self, 143 progress_sink: &'a mut dyn RadrootsSdkSignerProgressSink, 144 ) -> Self { 145 self.progress_sink = Some(progress_sink); 146 self 147 } 148 149 fn emit_progress( 150 &mut self, 151 progress: RadrootsSdkSignerProgress, 152 ) -> Result<(), RadrootsSdkError> { 153 match self.progress_sink.as_deref_mut() { 154 Some(progress_sink) => progress_sink.on_signer_progress(progress), 155 None => Ok(()), 156 } 157 } 158 } 159 160 #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)] 161 pub struct RadrootsSdkSignReceipt { 162 pub operation_kind: String, 163 pub mode: RadrootsSdkSignerMode, 164 pub signer_pubkey: String, 165 pub remote_signer_pubkey: Option<String>, 166 pub signed_event_id: String, 167 pub signed_event: RadrootsSignedNostrEvent, 168 } 169 170 #[derive(Clone)] 171 pub enum RadrootsSdkSignerProvider { 172 #[cfg(feature = "local-signer")] 173 LocalKey(RadrootsSdkLocalKeySigner), 174 MycNip46(RadrootsSdkMycNip46Signer), 175 } 176 177 impl RadrootsSdkSignerProvider { 178 pub fn mode(&self) -> RadrootsSdkSignerMode { 179 match self { 180 #[cfg(feature = "local-signer")] 181 Self::LocalKey(_) => RadrootsSdkSignerMode::LocalKey, 182 Self::MycNip46(_) => RadrootsSdkSignerMode::MycNip46, 183 } 184 } 185 186 pub fn status(&self) -> RadrootsSdkSignerStatus { 187 match self { 188 #[cfg(feature = "local-signer")] 189 Self::LocalKey(signer) => signer.status(), 190 Self::MycNip46(signer) => signer.status(), 191 } 192 } 193 194 pub fn capability(&self) -> RadrootsSdkSignerCapability { 195 match self { 196 #[cfg(feature = "local-signer")] 197 Self::LocalKey(signer) => signer.capability(), 198 Self::MycNip46(signer) => signer.capability(), 199 } 200 } 201 202 pub async fn sign( 203 &self, 204 request: RadrootsSdkSignRequest<'_>, 205 ) -> Result<RadrootsSdkSignReceipt, RadrootsSdkError> { 206 match self { 207 #[cfg(feature = "local-signer")] 208 Self::LocalKey(signer) => signer.sign(request).await, 209 Self::MycNip46(signer) => signer.sign(request).await, 210 } 211 } 212 } 213 214 #[cfg(feature = "local-signer")] 215 #[derive(Clone)] 216 pub struct RadrootsSdkLocalKeySigner { 217 signer: Arc<RadrootsLocalEventSigner>, 218 signer_pubkey: String, 219 } 220 221 #[cfg(feature = "local-signer")] 222 impl RadrootsSdkLocalKeySigner { 223 pub fn new(keys: RadrootsNostrKeys) -> Result<Self, RadrootsSdkError> { 224 let signer = RadrootsLocalEventSigner::new(keys)?; 225 let signer_pubkey = signer.pubkey().as_str().to_owned(); 226 Ok(Self { 227 signer: Arc::new(signer), 228 signer_pubkey, 229 }) 230 } 231 232 pub fn status(&self) -> RadrootsSdkSignerStatus { 233 RadrootsSdkSignerStatus { 234 mode: RadrootsSdkSignerMode::LocalKey, 235 state: RadrootsSdkSignerState::Ready, 236 signer_pubkey: self.signer_pubkey.clone(), 237 remote_signer_pubkey: None, 238 relay_count: 0, 239 } 240 } 241 242 pub fn capability(&self) -> RadrootsSdkSignerCapability { 243 RadrootsSdkSignerCapability { 244 mode: RadrootsSdkSignerMode::LocalKey, 245 signer_pubkey: self.signer_pubkey.clone(), 246 remote_signer_pubkey: None, 247 relays: Vec::new(), 248 can_sign_events: true, 249 nip46_permissions: Vec::new(), 250 } 251 } 252 253 pub async fn sign( 254 &self, 255 mut request: RadrootsSdkSignRequest<'_>, 256 ) -> Result<RadrootsSdkSignReceipt, RadrootsSdkError> { 257 request.emit_progress(RadrootsSdkSignerProgress::RequestStarted { 258 mode: RadrootsSdkSignerMode::LocalKey, 259 })?; 260 let signed_event = 261 sign_authorized_draft(request.actor, self.signer.as_ref(), request.frozen_draft)?; 262 request.emit_progress(RadrootsSdkSignerProgress::RequestCompleted { 263 mode: RadrootsSdkSignerMode::LocalKey, 264 })?; 265 Ok(sign_receipt( 266 request.operation_kind, 267 RadrootsSdkSignerMode::LocalKey, 268 self.signer_pubkey.clone(), 269 None, 270 signed_event, 271 )) 272 } 273 } 274 275 pub trait RadrootsSdkNip46Transport: Send + Sync { 276 fn publish_request_event<'a>( 277 &'a self, 278 event: RadrootsNostrEvent, 279 ) -> RadrootsSdkNip46TransportFuture<'a, ()>; 280 281 fn next_response_event<'a>(&'a self) 282 -> RadrootsSdkNip46TransportFuture<'a, RadrootsNostrEvent>; 283 } 284 285 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 286 pub struct RadrootsSdkMycNip46RequestPolicy { 287 request_timeout: Duration, 288 } 289 290 impl RadrootsSdkMycNip46RequestPolicy { 291 pub fn new(request_timeout: Duration) -> Result<Self, RadrootsSdkError> { 292 if request_timeout.is_zero() { 293 return Err(RadrootsSdkError::SignerUnavailable { 294 mode: RadrootsSdkSignerMode::MycNip46.as_str().to_owned(), 295 reason: "myc_nip46 request timeout must be greater than zero".to_owned(), 296 }); 297 } 298 Ok(Self { request_timeout }) 299 } 300 301 pub fn request_timeout(self) -> Duration { 302 self.request_timeout 303 } 304 } 305 306 impl Default for RadrootsSdkMycNip46RequestPolicy { 307 fn default() -> Self { 308 Self { 309 request_timeout: Duration::from_millis( 310 RADROOTS_SDK_MYC_NIP46_DEFAULT_REQUEST_TIMEOUT_MS, 311 ), 312 } 313 } 314 } 315 316 #[derive(Clone)] 317 pub struct RadrootsSdkMycNip46Signer { 318 client_keys: RadrootsNostrKeys, 319 target: RadrootsNostrConnectClientTarget, 320 user_pubkey: RadrootsPublicKey, 321 transport: Arc<dyn RadrootsSdkNip46Transport>, 322 request_policy: RadrootsSdkMycNip46RequestPolicy, 323 request_id_generator: Arc<dyn RadrootsSdkMycNip46RequestIdGenerator>, 324 } 325 326 impl RadrootsSdkMycNip46Signer { 327 pub fn new( 328 client_keys: RadrootsNostrKeys, 329 target: RadrootsNostrConnectClientTarget, 330 user_pubkey: impl AsRef<str>, 331 transport: Arc<dyn RadrootsSdkNip46Transport>, 332 ) -> Result<Self, RadrootsSdkError> { 333 Self::new_with_request_policy( 334 client_keys, 335 target, 336 user_pubkey, 337 transport, 338 RadrootsSdkMycNip46RequestPolicy::default(), 339 ) 340 } 341 342 pub fn new_with_request_policy( 343 client_keys: RadrootsNostrKeys, 344 target: RadrootsNostrConnectClientTarget, 345 user_pubkey: impl AsRef<str>, 346 transport: Arc<dyn RadrootsSdkNip46Transport>, 347 request_policy: RadrootsSdkMycNip46RequestPolicy, 348 ) -> Result<Self, RadrootsSdkError> { 349 Self::new_with_request_id_generator( 350 client_keys, 351 target, 352 user_pubkey, 353 transport, 354 request_policy, 355 Arc::new(RadrootsSdkUuidNip46RequestIdGenerator), 356 ) 357 } 358 359 fn new_with_request_id_generator( 360 client_keys: RadrootsNostrKeys, 361 target: RadrootsNostrConnectClientTarget, 362 user_pubkey: impl AsRef<str>, 363 transport: Arc<dyn RadrootsSdkNip46Transport>, 364 request_policy: RadrootsSdkMycNip46RequestPolicy, 365 request_id_generator: Arc<dyn RadrootsSdkMycNip46RequestIdGenerator>, 366 ) -> Result<Self, RadrootsSdkError> { 367 RadrootsSdkMycNip46RequestPolicy::new(request_policy.request_timeout())?; 368 let user_pubkey = RadrootsPublicKey::parse(user_pubkey.as_ref()).map_err(|error| { 369 RadrootsSdkError::InvalidRequest { 370 message: format!("myc_nip46 user pubkey is invalid: {error}"), 371 } 372 })?; 373 Ok(Self { 374 client_keys, 375 target, 376 user_pubkey, 377 transport, 378 request_policy, 379 request_id_generator, 380 }) 381 } 382 383 pub fn status(&self) -> RadrootsSdkSignerStatus { 384 RadrootsSdkSignerStatus { 385 mode: RadrootsSdkSignerMode::MycNip46, 386 state: RadrootsSdkSignerState::Ready, 387 signer_pubkey: self.user_pubkey.as_str().to_owned(), 388 remote_signer_pubkey: Some(self.target.remote_signer_public_key.to_hex()), 389 relay_count: self.target.relays.len(), 390 } 391 } 392 393 pub fn capability(&self) -> RadrootsSdkSignerCapability { 394 RadrootsSdkSignerCapability { 395 mode: RadrootsSdkSignerMode::MycNip46, 396 signer_pubkey: self.user_pubkey.as_str().to_owned(), 397 remote_signer_pubkey: Some(self.target.remote_signer_public_key.to_hex()), 398 relays: self.target.relays.iter().map(ToString::to_string).collect(), 399 can_sign_events: true, 400 nip46_permissions: radroots_sdk_myc_nip46_product_permission_strings(), 401 } 402 } 403 404 pub async fn sign( 405 &self, 406 mut request: RadrootsSdkSignRequest<'_>, 407 ) -> Result<RadrootsSdkSignReceipt, RadrootsSdkError> { 408 request.emit_progress(RadrootsSdkSignerProgress::RequestStarted { 409 mode: RadrootsSdkSignerMode::MycNip46, 410 })?; 411 authorize_actor_for_draft(request.actor, request.frozen_draft)?; 412 let signer_identity = RadrootsSdkSignerIdentityOnly { 413 pubkey: self.user_pubkey.clone(), 414 }; 415 authorize_signer_for_draft(&signer_identity, request.frozen_draft)?; 416 let sign_event_request = sign_event_request_from_frozen_draft(request.frozen_draft)?; 417 let request_id = self.next_request_id(); 418 let mut adapter = RadrootsSdkNip46TransportAdapter { 419 transport: self.transport.as_ref(), 420 }; 421 let mut progress_error = None; 422 let request_future = execute_request_with_transport( 423 &self.client_keys, 424 &self.target, 425 RadrootsNostrConnectClientRequest::new(request_id, sign_event_request), 426 &mut adapter, 427 |progress| { 428 let sdk_progress = match progress { 429 radroots_nostr_connect::prelude::RadrootsNostrConnectClientProgress::AuthChallenge { 430 url, 431 } => RadrootsSdkSignerProgress::AuthChallenge { 432 mode: RadrootsSdkSignerMode::MycNip46, 433 url, 434 }, 435 }; 436 if let Err(error) = request.emit_progress(sdk_progress) { 437 progress_error = Some(error); 438 return Err(RadrootsNostrConnectError::Transport { 439 reason: "SDK signer progress sink failed".to_owned(), 440 }); 441 } 442 Ok(()) 443 }, 444 ); 445 let response = timeout(self.request_policy.request_timeout(), request_future) 446 .await 447 .map_err(|_| RadrootsNostrConnectError::RequestTimedOut) 448 .and_then(|response| response); 449 if let Some(error) = progress_error { 450 return Err(error); 451 } 452 let response = response.map_err(sdk_error_from_nip46_error)?; 453 let signed_event = signed_event_from_nip46_response(request.operation_kind, response)?; 454 validate_signed_event_matches_draft(&signed_event, request.frozen_draft).map_err( 455 |error| RadrootsSdkError::SignerReturnedEventDrift { 456 operation: request.operation_kind.to_owned(), 457 reason: error.to_string(), 458 }, 459 )?; 460 request.emit_progress(RadrootsSdkSignerProgress::RequestCompleted { 461 mode: RadrootsSdkSignerMode::MycNip46, 462 })?; 463 Ok(sign_receipt( 464 request.operation_kind, 465 RadrootsSdkSignerMode::MycNip46, 466 self.user_pubkey.as_str().to_owned(), 467 Some(self.target.remote_signer_public_key.to_hex()), 468 signed_event, 469 )) 470 } 471 472 fn next_request_id(&self) -> String { 473 self.request_id_generator.next_request_id() 474 } 475 } 476 477 trait RadrootsSdkMycNip46RequestIdGenerator: Send + Sync { 478 fn next_request_id(&self) -> String; 479 } 480 481 struct RadrootsSdkUuidNip46RequestIdGenerator; 482 483 impl RadrootsSdkMycNip46RequestIdGenerator for RadrootsSdkUuidNip46RequestIdGenerator { 484 fn next_request_id(&self) -> String { 485 format!("radroots-sdk-myc-nip46-sign-{}", Uuid::new_v4()) 486 } 487 } 488 489 pub fn radroots_sdk_myc_nip46_product_permissions() -> RadrootsNostrConnectPermissions { 490 RADROOTS_SDK_MYC_NIP46_PRODUCT_SIGN_EVENT_KINDS 491 .iter() 492 .map(|kind| { 493 RadrootsNostrConnectPermission::with_parameter( 494 RadrootsNostrConnectMethod::SignEvent, 495 kind.to_string(), 496 ) 497 }) 498 .collect::<Vec<_>>() 499 .into() 500 } 501 502 pub fn radroots_sdk_myc_nip46_product_permission_strings() -> Vec<String> { 503 radroots_sdk_myc_nip46_product_permissions() 504 .as_slice() 505 .iter() 506 .map(ToString::to_string) 507 .collect() 508 } 509 510 struct RadrootsSdkSignerIdentityOnly { 511 pubkey: RadrootsPublicKey, 512 } 513 514 impl RadrootsEventSigner for RadrootsSdkSignerIdentityOnly { 515 fn pubkey(&self) -> &RadrootsPublicKey { 516 &self.pubkey 517 } 518 519 fn sign_frozen_draft( 520 &self, 521 _draft: &RadrootsFrozenEventDraft, 522 ) -> Result<RadrootsSignedNostrEvent, RadrootsSignerError> { 523 Err(RadrootsSignerError::Unavailable) 524 } 525 } 526 527 struct RadrootsSdkNip46TransportAdapter<'a> { 528 transport: &'a dyn RadrootsSdkNip46Transport, 529 } 530 531 impl RadrootsNostrConnectClientTransport for RadrootsSdkNip46TransportAdapter<'_> { 532 fn publish_request_event<'a>( 533 &'a mut self, 534 event: RadrootsNostrEvent, 535 ) -> RadrootsNostrConnectClientTransportFuture<'a, ()> { 536 self.transport.publish_request_event(event) 537 } 538 539 fn next_response_event<'a>( 540 &'a mut self, 541 ) -> RadrootsNostrConnectClientTransportFuture<'a, RadrootsNostrEvent> { 542 self.transport.next_response_event() 543 } 544 } 545 546 fn sign_event_request_from_frozen_draft( 547 draft: &RadrootsFrozenEventDraft, 548 ) -> Result<RadrootsNostrConnectRequest, RadrootsSdkError> { 549 let unsigned_event = serde_json::from_value(json!({ 550 "pubkey": draft.expected_pubkey, 551 "created_at": draft.created_at, 552 "kind": draft.kind, 553 "tags": draft.tags, 554 "content": draft.content, 555 })) 556 .map_err(|error| RadrootsSdkError::SignerProtocol { 557 mode: RadrootsSdkSignerMode::MycNip46.as_str().to_owned(), 558 reason: format!("failed to convert frozen draft to NIP-46 unsigned event: {error}"), 559 })?; 560 Ok(RadrootsNostrConnectRequest::SignEvent(unsigned_event)) 561 } 562 563 fn signed_event_from_nip46_response( 564 operation_kind: &str, 565 response: RadrootsNostrConnectResponse, 566 ) -> Result<RadrootsSignedNostrEvent, RadrootsSdkError> { 567 match response { 568 RadrootsNostrConnectResponse::SignedEvent(event) => { 569 let raw_json = serde_json::to_string(&event).map_err(|error| { 570 RadrootsSdkError::SignerProtocol { 571 mode: RadrootsSdkSignerMode::MycNip46.as_str().to_owned(), 572 reason: format!("failed to serialize remote signed event: {error}"), 573 } 574 })?; 575 RadrootsSignedNostrEvent::from_event(radroots_event_from_nostr(&event), raw_json) 576 .map_err(|error| RadrootsSdkError::SignerProtocol { 577 mode: RadrootsSdkSignerMode::MycNip46.as_str().to_owned(), 578 reason: format!("remote signed event is invalid: {error}"), 579 }) 580 } 581 RadrootsNostrConnectResponse::Error { error, .. } => { 582 Err(RadrootsSdkError::SignerRequestRejected { 583 mode: RadrootsSdkSignerMode::MycNip46.as_str().to_owned(), 584 reason: error, 585 }) 586 } 587 RadrootsNostrConnectResponse::PendingConnection => { 588 Err(RadrootsSdkError::SignerAuthChallengePending { 589 mode: RadrootsSdkSignerMode::MycNip46.as_str().to_owned(), 590 auth_url: None, 591 }) 592 } 593 other => Err(RadrootsSdkError::SignerProtocol { 594 mode: RadrootsSdkSignerMode::MycNip46.as_str().to_owned(), 595 reason: format!("unexpected NIP-46 response for {operation_kind}: {other:?}"), 596 }), 597 } 598 } 599 600 fn sdk_error_from_nip46_error(error: RadrootsNostrConnectError) -> RadrootsSdkError { 601 match error { 602 RadrootsNostrConnectError::RequestTimedOut => RadrootsSdkError::SignerRequestTimedOut { 603 mode: RadrootsSdkSignerMode::MycNip46.as_str().to_owned(), 604 }, 605 RadrootsNostrConnectError::Transport { reason } => RadrootsSdkError::SignerTransport { 606 mode: RadrootsSdkSignerMode::MycNip46.as_str().to_owned(), 607 reason, 608 }, 609 RadrootsNostrConnectError::Encrypt { reason } 610 | RadrootsNostrConnectError::Decrypt { reason } 611 | RadrootsNostrConnectError::Sign { reason } 612 | RadrootsNostrConnectError::Json(reason) 613 | RadrootsNostrConnectError::InvalidRequestPayload { reason, .. } 614 | RadrootsNostrConnectError::InvalidResponsePayload { reason, .. } => { 615 RadrootsSdkError::SignerProtocol { 616 mode: RadrootsSdkSignerMode::MycNip46.as_str().to_owned(), 617 reason, 618 } 619 } 620 error => RadrootsSdkError::SignerProtocol { 621 mode: RadrootsSdkSignerMode::MycNip46.as_str().to_owned(), 622 reason: error.to_string(), 623 }, 624 } 625 } 626 627 fn sign_receipt( 628 operation_kind: &str, 629 mode: RadrootsSdkSignerMode, 630 signer_pubkey: String, 631 remote_signer_pubkey: Option<String>, 632 signed_event: RadrootsSignedNostrEvent, 633 ) -> RadrootsSdkSignReceipt { 634 RadrootsSdkSignReceipt { 635 operation_kind: operation_kind.to_owned(), 636 mode, 637 signer_pubkey, 638 remote_signer_pubkey, 639 signed_event_id: signed_event.id.clone(), 640 signed_event, 641 } 642 } 643 644 #[cfg(test)] 645 #[path = "../tests/unit/signer_provider_tests.rs"] 646 mod tests;