commit f548cdbf400ac1759bd2100f9a8576759d7f6e62
parent 8c98d750c8f11a9b8230a09ce51c38b66bd4a952
Author: triesap <tyson@radroots.org>
Date: Sun, 12 Apr 2026 04:21:43 +0000
bridge: consume shared trade workflow helpers
Diffstat:
4 files changed, 113 insertions(+), 274 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -1726,7 +1726,7 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
[[package]]
name = "radroots_core"
-version = "0.1.0-alpha.1"
+version = "0.1.0-alpha.2"
dependencies = [
"rust_decimal",
"rust_decimal_macros",
@@ -1736,7 +1736,7 @@ dependencies = [
[[package]]
name = "radroots_events"
-version = "0.1.0-alpha.1"
+version = "0.1.0-alpha.2"
dependencies = [
"radroots_core",
"serde",
@@ -1746,7 +1746,7 @@ dependencies = [
[[package]]
name = "radroots_events_codec"
-version = "0.1.0-alpha.1"
+version = "0.1.0-alpha.2"
dependencies = [
"nostr",
"radroots_core",
@@ -1757,7 +1757,7 @@ dependencies = [
[[package]]
name = "radroots_identity"
-version = "0.1.0-alpha.1"
+version = "0.1.0-alpha.2"
dependencies = [
"nostr",
"radroots_events",
@@ -1771,7 +1771,7 @@ dependencies = [
[[package]]
name = "radroots_log"
-version = "0.1.0-alpha.1"
+version = "0.1.0-alpha.2"
dependencies = [
"chrono",
"thiserror 1.0.69",
@@ -1782,7 +1782,7 @@ dependencies = [
[[package]]
name = "radroots_nostr"
-version = "0.1.0-alpha.1"
+version = "0.1.0-alpha.2"
dependencies = [
"nostr",
"nostr-sdk",
@@ -1797,7 +1797,7 @@ dependencies = [
[[package]]
name = "radroots_nostr_connect"
-version = "0.1.0-alpha.1"
+version = "0.1.0-alpha.2"
dependencies = [
"nostr",
"serde",
@@ -1808,7 +1808,7 @@ dependencies = [
[[package]]
name = "radroots_nostr_signer"
-version = "0.1.0-alpha.1"
+version = "0.1.0-alpha.2"
dependencies = [
"hex",
"nostr",
@@ -1825,7 +1825,7 @@ dependencies = [
[[package]]
name = "radroots_protected_store"
-version = "0.1.0-alpha.1"
+version = "0.1.0-alpha.2"
dependencies = [
"chacha20poly1305",
"getrandom 0.2.17",
@@ -1837,7 +1837,7 @@ dependencies = [
[[package]]
name = "radroots_runtime"
-version = "0.1.0-alpha.1"
+version = "0.1.0-alpha.2"
dependencies = [
"anyhow",
"chacha20poly1305",
@@ -1860,24 +1860,25 @@ dependencies = [
[[package]]
name = "radroots_runtime_paths"
-version = "0.1.0-alpha.1"
+version = "0.1.0-alpha.2"
dependencies = [
"thiserror 1.0.69",
]
[[package]]
name = "radroots_secret_vault"
-version = "0.1.0-alpha.1"
+version = "0.1.0-alpha.2"
[[package]]
name = "radroots_trade"
-version = "0.1.0-alpha.1"
+version = "0.1.0-alpha.2"
dependencies = [
"radroots_core",
"radroots_events",
"radroots_events_codec",
"serde",
"serde_json",
+ "thiserror 1.0.69",
"ts-rs",
]
diff --git a/src/transport/jsonrpc/methods/bridge/listing_publish.rs b/src/transport/jsonrpc/methods/bridge/listing_publish.rs
@@ -1,12 +1,13 @@
use anyhow::Result;
use jsonrpsee::server::RpcModule;
-use radroots_events::RadrootsNostrEvent;
-use radroots_events::kinds::{KIND_LISTING, KIND_LISTING_DRAFT, is_listing_kind};
use radroots_events::listing::RadrootsListing;
use radroots_events_codec::listing::encode::to_wire_parts_with_kind;
use radroots_events_codec::wire::WireEventParts;
use radroots_nostr::prelude::radroots_nostr_build_event;
-use radroots_trade::listing::validation::validate_listing_event;
+use radroots_trade::listing::publish::{
+ RadrootsTradeListingPublishError, canonicalize_listing_for_seller, resolve_listing_kind,
+ validate_listing_for_seller,
+};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
@@ -14,8 +15,8 @@ use crate::core::bridge::publish::{
BridgePublishSettings, connect_and_publish_event, failed_prepublish_execution,
};
use crate::core::bridge::store::new_listing_publish_job;
-use crate::transport::jsonrpc::auth::require_bridge_auth;
use crate::core::nip46::session::Nip46SessionAuthority;
+use crate::transport::jsonrpc::auth::require_bridge_auth;
use crate::transport::jsonrpc::methods::bridge::shared::{
BridgePublishResponse, ensure_bridge_enabled, fingerprint_bridge_request,
normalize_idempotency_key, reserve_bridge_job, resolve_actor_bridge_signer,
@@ -64,7 +65,7 @@ async fn publish_listing(
) -> Result<BridgePublishResponse, RpcError> {
ensure_bridge_enabled(&ctx)?;
let idempotency_key = normalize_idempotency_key(params.idempotency_key)?;
- let kind = resolve_listing_kind(params.kind)?;
+ let kind = resolve_listing_kind(params.kind).map_err(map_listing_publish_error)?;
let signer = resolve_actor_bridge_signer(
&ctx,
params.signer_session_id.as_deref(),
@@ -74,7 +75,7 @@ async fn publish_listing(
)
.await?;
let signer_pubkey = signer.signer_pubkey_hex();
- let listing = canonicalize_listing_for_signer(params.listing, signer_pubkey.as_str());
+ let listing = canonicalize_listing_for_seller(params.listing, signer_pubkey.as_str());
let canonical = CanonicalBridgeListingPublishRequest { kind, listing };
let request_fingerprint =
fingerprint_bridge_request("bridge.listing.publish", &signer, &canonical)?;
@@ -145,46 +146,21 @@ async fn publish_listing(
})
}
-fn resolve_listing_kind(kind: Option<u32>) -> Result<u32, RpcError> {
- let kind = kind.unwrap_or(KIND_LISTING);
- if !is_listing_kind(kind) {
- return Err(RpcError::InvalidParams(format!(
- "listing kind must be {KIND_LISTING} or {KIND_LISTING_DRAFT}"
- )));
- }
- Ok(kind)
-}
-
-fn canonicalize_listing_for_signer(
- mut listing: RadrootsListing,
- signer_pubkey: &str,
-) -> RadrootsListing {
- if listing.farm.pubkey.trim().is_empty() {
- listing.farm.pubkey = signer_pubkey.to_string();
- }
- listing
-}
-
fn validate_canonical_listing_contract_for_signer(
listing: &RadrootsListing,
signer_pubkey: &str,
parts: &WireEventParts,
) -> Result<radroots_trade::listing::validation::RadrootsTradeListing, RpcError> {
- let canonical = RadrootsNostrEvent {
- id: String::new(),
- author: signer_pubkey.to_string(),
- created_at: 0,
- kind: parts.kind,
- tags: parts.tags.clone(),
- content: parts.content.clone(),
- sig: String::new(),
- };
- let validated = validate_listing_event(&canonical)
- .map_err(|error| RpcError::InvalidParams(format!("invalid listing contract: {error}")))?;
+ let validated = validate_listing_for_seller(listing.clone(), signer_pubkey, parts.kind)
+ .map_err(map_listing_publish_error)?;
debug_assert_eq!(validated.listing.d_tag, listing.d_tag);
Ok(validated)
}
+fn map_listing_publish_error(error: RadrootsTradeListingPublishError) -> RpcError {
+ RpcError::InvalidParams(error.to_string())
+}
+
#[cfg(test)]
mod tests {
use radroots_core::{
@@ -208,21 +184,21 @@ mod tests {
use crate::core::Radrootsd;
use crate::core::nip46::session::Nip46Session;
use crate::transport::jsonrpc::{MethodRegistry, RpcContext};
+ use radroots_trade::listing::publish::canonicalize_listing_for_seller;
use super::{
- BridgeListingPublishParams, canonicalize_listing_for_signer, publish_listing,
- validate_canonical_listing_contract_for_signer,
+ BridgeListingPublishParams, publish_listing, validate_canonical_listing_contract_for_signer,
};
#[test]
fn canonicalize_listing_sets_missing_farm_pubkey() {
- let listing = canonicalize_listing_for_signer(base_listing(), "abc123");
+ let listing = canonicalize_listing_for_seller(base_listing(), "abc123");
assert_eq!(listing.farm.pubkey, "abc123");
}
#[test]
fn validate_canonical_listing_contract_rejects_mismatched_seller_before_sign() {
- let listing = canonicalize_listing_for_signer(base_listing(), "abc123");
+ let listing = canonicalize_listing_for_seller(base_listing(), "abc123");
let mut invalid = listing.clone();
invalid.farm.pubkey = "other".to_string();
let parts = to_wire_parts_with_kind(&invalid, KIND_LISTING).expect("wire parts");
@@ -398,25 +374,28 @@ mod tests {
let client = RadrootsNostrClient::new(signer_keys.clone());
let client_keys = signer_keys.clone();
let client_pubkey = client_keys.public_key();
- ctx.state.nip46_sessions.insert(Nip46Session {
- id: session_id.to_string(),
- client,
- client_keys,
- client_pubkey,
- remote_signer_pubkey,
- user_pubkey: None,
- relays: Vec::new(),
- perms: vec!["sign_event".to_string()],
- name: None,
- url: None,
- image: None,
- expires_at: Some(Instant::now() + std::time::Duration::from_secs(60)),
- auth_required: false,
- authorized: true,
- auth_url: None,
- pending_request: None,
- signer_authority: None,
- }).await;
+ ctx.state
+ .nip46_sessions
+ .insert(Nip46Session {
+ id: session_id.to_string(),
+ client,
+ client_keys,
+ client_pubkey,
+ remote_signer_pubkey,
+ user_pubkey: None,
+ relays: Vec::new(),
+ perms: vec!["sign_event".to_string()],
+ name: None,
+ url: None,
+ image: None,
+ expires_at: Some(Instant::now() + std::time::Duration::from_secs(60)),
+ auth_required: false,
+ authorized: true,
+ auth_url: None,
+ pending_request: None,
+ signer_authority: None,
+ })
+ .await;
session_id.to_string()
}
diff --git a/src/transport/jsonrpc/methods/bridge/order_request.rs b/src/transport/jsonrpc/methods/bridge/order_request.rs
@@ -15,6 +15,7 @@ use radroots_nostr::prelude::{
RadrootsNostrFilter, RadrootsNostrKind, radroots_event_ptr_from_nostr,
radroots_nostr_build_event, radroots_nostr_filter_tag, radroots_nostr_parse_pubkey,
};
+use radroots_trade::order::canonicalize_order_request_for_signer;
use serde::Deserialize;
use std::time::Duration;
use uuid::Uuid;
@@ -75,7 +76,13 @@ async fn publish_order_request(
)
.await?;
let signer_pubkey = signer.signer_pubkey_hex();
- let order = canonicalize_order_request_for_signer(params.order, signer_pubkey.as_str())?;
+ let order = canonicalize_order_request_for_signer(params.order, signer_pubkey.as_str())
+ .map_err(|error| RpcError::InvalidParams(error.to_string()))?;
+ radroots_nostr_parse_pubkey(&order.buyer_pubkey)
+ .map_err(|error| RpcError::InvalidParams(format!("invalid order.buyer_pubkey: {error}")))?;
+ radroots_nostr_parse_pubkey(&order.seller_pubkey).map_err(|error| {
+ RpcError::InvalidParams(format!("invalid order.seller_pubkey: {error}"))
+ })?;
let request_fingerprint = fingerprint_bridge_request("bridge.order.request", &signer, &order)?;
let envelope = TradeListingEnvelope::new(
TradeListingMessageType::OrderRequest,
@@ -202,90 +209,6 @@ fn synthetic_listing_snapshot(listing_addr: &TradeListingAddress) -> RadrootsNos
}
}
-fn canonicalize_order_request_for_signer(
- mut order: TradeOrder,
- signer_pubkey: &str,
-) -> Result<TradeOrder, RpcError> {
- let order_id =
- normalized_required_string(std::mem::take(&mut order.order_id), "order.order_id")?;
- let listing_addr_raw = normalized_required_string(
- std::mem::take(&mut order.listing_addr),
- "order.listing_addr",
- )?;
- let listing_addr = TradeListingAddress::parse(&listing_addr_raw)
- .map_err(|error| RpcError::InvalidParams(format!("invalid order.listing_addr: {error}")))?;
- if u32::from(listing_addr.kind) != KIND_LISTING {
- return Err(RpcError::InvalidParams(
- "order.listing_addr must reference a public NIP-99 listing".to_string(),
- ));
- }
-
- let buyer_pubkey = if order.buyer_pubkey.trim().is_empty() {
- signer_pubkey.to_string()
- } else {
- normalized_required_string(
- std::mem::take(&mut order.buyer_pubkey),
- "order.buyer_pubkey",
- )?
- };
- if buyer_pubkey != signer_pubkey {
- return Err(RpcError::InvalidParams(
- "order.buyer_pubkey must match the requested bridge signer identity".to_string(),
- ));
- }
-
- let seller_pubkey = if order.seller_pubkey.trim().is_empty() {
- listing_addr.seller_pubkey.clone()
- } else {
- normalized_required_string(
- std::mem::take(&mut order.seller_pubkey),
- "order.seller_pubkey",
- )?
- };
- if seller_pubkey != listing_addr.seller_pubkey {
- return Err(RpcError::InvalidParams(
- "order.seller_pubkey must match order.listing_addr seller".to_string(),
- ));
- }
-
- radroots_nostr_parse_pubkey(&buyer_pubkey)
- .map_err(|error| RpcError::InvalidParams(format!("invalid order.buyer_pubkey: {error}")))?;
- radroots_nostr_parse_pubkey(&seller_pubkey).map_err(|error| {
- RpcError::InvalidParams(format!("invalid order.seller_pubkey: {error}"))
- })?;
-
- if order.items.is_empty() {
- return Err(RpcError::InvalidParams(
- "order.items must contain at least one item".to_string(),
- ));
- }
- for (index, item) in order.items.iter_mut().enumerate() {
- item.bin_id = normalized_required_string(item.bin_id.clone(), "order.items[].bin_id")?;
- if item.bin_count == 0 {
- return Err(RpcError::InvalidParams(format!(
- "order.items[{index}].bin_count must be greater than zero"
- )));
- }
- }
-
- order.order_id = order_id;
- order.listing_addr = listing_addr.as_str();
- order.buyer_pubkey = buyer_pubkey;
- order.seller_pubkey = seller_pubkey;
- if order.discounts.as_ref().is_some_and(Vec::is_empty) {
- order.discounts = None;
- }
- Ok(order)
-}
-
-fn normalized_required_string(value: String, field: &str) -> Result<String, RpcError> {
- let value = value.trim().to_string();
- if value.is_empty() {
- return Err(RpcError::InvalidParams(format!("{field} cannot be empty")));
- }
- Ok(value)
-}
-
#[cfg(test)]
mod tests {
use radroots_core::RadrootsCoreDiscountValue;
@@ -302,10 +225,9 @@ mod tests {
use crate::core::Radrootsd;
use crate::core::nip46::session::Nip46Session;
use crate::transport::jsonrpc::{MethodRegistry, RpcContext};
+ use radroots_trade::order::canonicalize_order_request_for_signer;
- use super::{
- BridgeOrderRequestParams, canonicalize_order_request_for_signer, publish_order_request,
- };
+ use super::{BridgeOrderRequestParams, publish_order_request};
#[test]
fn canonicalize_order_request_sets_missing_buyer_and_seller_pubkeys() {
@@ -487,25 +409,28 @@ mod tests {
let client = RadrootsNostrClient::new(signer_keys.clone());
let client_keys = signer_keys.clone();
let client_pubkey = client_keys.public_key();
- ctx.state.nip46_sessions.insert(Nip46Session {
- id: session_id.to_string(),
- client,
- client_keys,
- client_pubkey,
- remote_signer_pubkey,
- user_pubkey: None,
- relays: Vec::new(),
- perms: vec!["sign_event".to_string()],
- name: None,
- url: None,
- image: None,
- expires_at: Some(Instant::now() + std::time::Duration::from_secs(60)),
- auth_required: false,
- authorized: true,
- auth_url: None,
- pending_request: None,
- signer_authority: None,
- }).await;
+ ctx.state
+ .nip46_sessions
+ .insert(Nip46Session {
+ id: session_id.to_string(),
+ client,
+ client_keys,
+ client_pubkey,
+ remote_signer_pubkey,
+ user_pubkey: None,
+ relays: Vec::new(),
+ perms: vec!["sign_event".to_string()],
+ name: None,
+ url: None,
+ image: None,
+ expires_at: Some(Instant::now() + std::time::Duration::from_secs(60)),
+ auth_required: false,
+ authorized: true,
+ auth_url: None,
+ pending_request: None,
+ signer_authority: None,
+ })
+ .await;
session_id.to_string()
}
diff --git a/src/transport/jsonrpc/methods/bridge/public_trade.rs b/src/transport/jsonrpc/methods/bridge/public_trade.rs
@@ -1,7 +1,6 @@
use anyhow::Result;
use jsonrpsee::server::RpcModule;
use radroots_events::RadrootsNostrEventPtr;
-use radroots_events::kinds::KIND_LISTING;
use radroots_events::trade::{
RadrootsTradeDiscountDecision as TradeDiscountDecision,
RadrootsTradeMessagePayload as TradeListingMessagePayload,
@@ -16,6 +15,7 @@ use radroots_nostr::prelude::{
radroots_nostr_parse_pubkey,
};
use radroots_trade::listing::validation::validate_listing_event;
+use radroots_trade::public_trade::canonicalize_public_trade_context;
use serde::{Deserialize, Serialize, de::DeserializeOwned};
use uuid::Uuid;
@@ -63,13 +63,6 @@ struct CanonicalBridgePublicTradeRequest<T> {
payload: T,
}
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-enum ExpectedPublicTradeAuthor {
- Buyer,
- Seller,
- Either,
-}
-
pub fn register(m: &mut RpcModule<RpcContext>, registry: &MethodRegistry) -> Result<()> {
register_public_trade_method(
m,
@@ -295,34 +288,19 @@ fn canonicalize_public_trade_params<T>(
signer_pubkey: &str,
message_type: TradeListingMessageType,
) -> Result<(CanonicalBridgePublicTradeRequest<T>, TradeListingAddress), RpcError> {
- let listing_addr = normalized_required_string(params.listing_addr, "listing_addr")?;
- let parsed_listing_addr = TradeListingAddress::parse(&listing_addr)
- .map_err(|error| RpcError::InvalidParams(format!("invalid listing_addr: {error}")))?;
- if u32::from(parsed_listing_addr.kind) != KIND_LISTING {
- return Err(RpcError::InvalidParams(
- "listing_addr must reference a public NIP-99 listing".to_string(),
- ));
- }
-
- let order_id = normalized_required_string(params.order_id, "order_id")?;
- let counterparty_pubkey =
- normalized_required_string(params.counterparty_pubkey, "counterparty_pubkey")?;
- radroots_nostr_parse_pubkey(&counterparty_pubkey).map_err(|error| {
+ let context = canonicalize_public_trade_context(
+ params.listing_addr,
+ params.order_id,
+ params.counterparty_pubkey,
+ signer_pubkey,
+ message_type,
+ )
+ .map_err(|error| RpcError::InvalidParams(error.to_string()))?;
+ radroots_nostr_parse_pubkey(&context.counterparty_pubkey).map_err(|error| {
RpcError::InvalidParams(format!("invalid counterparty_pubkey: {error}"))
})?;
-
- if counterparty_pubkey == signer_pubkey {
- return Err(RpcError::InvalidParams(
- "counterparty_pubkey must not match the requested bridge signer identity".to_string(),
- ));
- }
-
- validate_expected_author(
- &parsed_listing_addr,
- message_type,
- signer_pubkey,
- &counterparty_pubkey,
- )?;
+ let parsed_listing_addr = TradeListingAddress::parse(&context.listing_addr)
+ .map_err(|error| RpcError::InvalidParams(format!("invalid listing_addr: {error}")))?;
let listing_event = if message_type.requires_listing_snapshot() {
Some(normalize_listing_event_ptr(
@@ -353,9 +331,9 @@ fn canonicalize_public_trade_params<T>(
Ok((
CanonicalBridgePublicTradeRequest {
- listing_addr,
- order_id,
- counterparty_pubkey,
+ listing_addr: context.listing_addr,
+ order_id: context.order_id,
+ counterparty_pubkey: context.counterparty_pubkey,
listing_event,
root_event_id,
prev_event_id,
@@ -365,59 +343,6 @@ fn canonicalize_public_trade_params<T>(
))
}
-fn validate_expected_author(
- listing_addr: &TradeListingAddress,
- message_type: TradeListingMessageType,
- signer_pubkey: &str,
- counterparty_pubkey: &str,
-) -> Result<(), RpcError> {
- match expected_author(message_type) {
- ExpectedPublicTradeAuthor::Seller => {
- if signer_pubkey != listing_addr.seller_pubkey {
- return Err(RpcError::InvalidParams(format!(
- "{message_type:?} must be authored by the listing seller"
- )));
- }
- }
- ExpectedPublicTradeAuthor::Buyer => {
- if signer_pubkey == listing_addr.seller_pubkey {
- return Err(RpcError::InvalidParams(format!(
- "{message_type:?} must be authored by the buyer, not the listing seller"
- )));
- }
- if counterparty_pubkey != listing_addr.seller_pubkey {
- return Err(RpcError::InvalidParams(
- "counterparty_pubkey must match the listing seller for buyer-authored trade messages"
- .to_string(),
- ));
- }
- }
- ExpectedPublicTradeAuthor::Either => {}
- }
- Ok(())
-}
-
-fn expected_author(message_type: TradeListingMessageType) -> ExpectedPublicTradeAuthor {
- match message_type {
- TradeListingMessageType::OrderResponse
- | TradeListingMessageType::OrderRevision
- | TradeListingMessageType::Answer
- | TradeListingMessageType::DiscountOffer
- | TradeListingMessageType::FulfillmentUpdate => ExpectedPublicTradeAuthor::Seller,
- TradeListingMessageType::OrderRequest
- | TradeListingMessageType::OrderRevisionAccept
- | TradeListingMessageType::OrderRevisionDecline
- | TradeListingMessageType::Question
- | TradeListingMessageType::DiscountRequest
- | TradeListingMessageType::DiscountAccept
- | TradeListingMessageType::DiscountDecline
- | TradeListingMessageType::Receipt => ExpectedPublicTradeAuthor::Buyer,
- TradeListingMessageType::Cancel => ExpectedPublicTradeAuthor::Either,
- TradeListingMessageType::ListingValidateRequest
- | TradeListingMessageType::ListingValidateResult => ExpectedPublicTradeAuthor::Either,
- }
-}
-
fn normalize_listing_event_ptr(
ptr: RadrootsNostrEventPtr,
) -> Result<RadrootsNostrEventPtr, RpcError> {
@@ -532,6 +457,7 @@ fn normalized_required_string(value: String, field: &str) -> Result<String, RpcE
#[cfg(test)]
mod tests {
use radroots_core::{RadrootsCoreDecimal, RadrootsCoreDiscountValue, RadrootsCorePercent};
+ use radroots_events::kinds::KIND_LISTING;
use radroots_events::trade::{
RadrootsTradeDiscountRequest as TradeDiscountRequest,
RadrootsTradeOrderResponse as TradeOrderResponse,
@@ -731,15 +657,15 @@ mod tests {
#[tokio::test]
async fn publish_revision_accept_rejects_decline_payload() {
- let ctx = buyer_ctx().expect("ctx");
+ let (ctx, seller_pubkey) = signer_ctx().expect("ctx");
let err = publish_public_trade(
ctx,
"bridge.order.revision.accept",
TradeListingMessageType::OrderRevisionAccept,
BridgePublicTradeParams {
- listing_addr: base_listing_addr(base_seller_pubkey()),
+ listing_addr: base_listing_addr(&seller_pubkey),
order_id: "order-1".to_string(),
- counterparty_pubkey: base_seller_pubkey().to_string(),
+ counterparty_pubkey: base_buyer_pubkey().to_string(),
listing_event: None,
root_event_id: Some("root".to_string()),
prev_event_id: Some("prev".to_string()),
@@ -758,7 +684,12 @@ mod tests {
}
fn buyer_ctx() -> Result<RpcContext, RpcError> {
+ signer_ctx().map(|(ctx, _)| ctx)
+ }
+
+ fn signer_ctx() -> Result<(RpcContext, String), RpcError> {
let identity = RadrootsIdentity::generate();
+ let signer_pubkey = identity.public_key_hex();
let metadata: RadrootsNostrMetadata =
serde_json::from_str(r#"{"name":"radrootsd-test"}"#).expect("metadata");
let state = Radrootsd::new(
@@ -772,7 +703,10 @@ mod tests {
Nip46Config::default(),
)
.map_err(|error| RpcError::Other(format!("build state: {error}")))?;
- Ok(RpcContext::new(state, MethodRegistry::default()))
+ Ok((
+ RpcContext::new(state, MethodRegistry::default()),
+ signer_pubkey,
+ ))
}
fn base_seller_pubkey() -> &'static str {