Skip to content
This repository was archived by the owner on Feb 3, 2025. It is now read-only.

Commit bb42fae

Browse files
committed
Create recommendation events
1 parent 5e8b085 commit bb42fae

File tree

2 files changed

+66
-9
lines changed

2 files changed

+66
-9
lines changed

Diff for: mutiny-core/src/nostr/mod.rs

+50-9
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ use lnurl::lnurl::LnUrl;
2626
use nostr::key::SecretKey;
2727
use nostr::nips::nip04::{decrypt, encrypt};
2828
use nostr::nips::nip47::*;
29-
use nostr::{Event, EventBuilder, EventId, Filter, JsonUtil, Keys, Kind, Metadata, Tag, Timestamp};
29+
use nostr::{
30+
Alphabet, Event, EventBuilder, EventId, Filter, JsonUtil, Keys, Kind, Metadata,
31+
SingleLetterTag, Tag, TagKind, Timestamp,
32+
};
3033
use nostr_sdk::{Client, NostrSigner, RelayPoolNotification};
3134
use serde::{Deserialize, Serialize};
3235
use std::collections::{HashMap, HashSet};
@@ -1239,6 +1242,39 @@ impl<S: MutinyStorage> NostrManager<S> {
12391242
Ok(event_id)
12401243
}
12411244

1245+
/// Creates a recommendation event for a federation
1246+
pub async fn recommend_federation(
1247+
&self,
1248+
invite_code: &InviteCode,
1249+
review: Option<&str>,
1250+
) -> Result<EventId, MutinyError> {
1251+
let kind = Kind::from(38000);
1252+
1253+
// properly tag the event as a federation with the federation id
1254+
let d_tag = Tag::Identifier(invite_code.federation_id().to_string());
1255+
let k_tag = Tag::Generic(
1256+
TagKind::SingleLetter(SingleLetterTag::lowercase(Alphabet::K)),
1257+
vec!["38173".to_string()],
1258+
);
1259+
1260+
// tag the federation invite code
1261+
let invite_code_tag = Tag::Generic(
1262+
TagKind::SingleLetter(SingleLetterTag::lowercase(Alphabet::U)),
1263+
vec![invite_code.to_string()],
1264+
);
1265+
1266+
// todo tag the federation announcement event, to do so we need to have the pubkey of the federation
1267+
1268+
let builder = EventBuilder::new(
1269+
kind,
1270+
review.unwrap_or_default(),
1271+
[d_tag, k_tag, invite_code_tag],
1272+
);
1273+
1274+
// send the event
1275+
Ok(self.client.send_event_builder(builder).await?)
1276+
}
1277+
12421278
/// Queries our relays for federation announcements
12431279
pub async fn discover_federations(&self) -> Result<Vec<NostrDiscoveredFedimint>, MutinyError> {
12441280
// get contacts by npub
@@ -1284,11 +1320,13 @@ impl<S: MutinyStorage> NostrManager<S> {
12841320
let mints = Filter::new().kind(Kind::from(38173));
12851321
// filter for finding federation recommendations from trusted people
12861322
let trusted_recommendations = Filter::new()
1287-
.kind(Kind::from(18173))
1323+
.kind(Kind::from(38000))
1324+
.custom_tag(SingleLetterTag::lowercase(Alphabet::K), ["38173"])
12881325
.authors(npubs.keys().copied());
12891326
// filter for finding federation recommendations from random people
12901327
let recommendations = Filter::new()
1291-
.kind(Kind::from(18173))
1328+
.kind(Kind::from(38000))
1329+
.custom_tag(SingleLetterTag::lowercase(Alphabet::K), ["38173"])
12921330
.limit(NUM_TRUSTED_USERS as usize);
12931331
// fetch events
12941332
let events = self
@@ -1353,10 +1391,16 @@ impl<S: MutinyStorage> NostrManager<S> {
13531391
// add on contact recommendations to mints
13541392
for event in events {
13551393
// only process federation recommendations
1356-
if event.kind != Kind::from(18173) {
1394+
if event.kind != Kind::from(38000)
1395+
&& event.tags.iter().any(|tag| {
1396+
tag.kind() == TagKind::Custom("k".to_string())
1397+
&& tag.as_vec().get(1).is_some_and(|x| x == "38173")
1398+
})
1399+
{
13571400
continue;
13581401
}
13591402

1403+
// if we don't have the contact, skip
13601404
let contact = match npubs.get(&event.pubkey) {
13611405
Some(contact) => contact.clone(),
13621406
None => continue,
@@ -1366,12 +1410,9 @@ impl<S: MutinyStorage> NostrManager<S> {
13661410
.tags
13671411
.iter()
13681412
.filter_map(|tag| {
1413+
// try to parse the invite code
13691414
let vec = tag.as_vec();
1370-
// if there's 3 elements, make sure the identifier is for a fedimint
1371-
// if there's 2 elements, just try to parse the invite code
1372-
if (vec.len() == 3 && vec[0] == "u" && vec[2] == "fedimint")
1373-
|| (vec.len() == 2 && vec[0] == "u")
1374-
{
1415+
if vec.len() == 2 && vec[0] == "u" {
13751416
InviteCode::from_str(&vec[1]).ok()
13761417
} else {
13771418
None

Diff for: mutiny-wasm/src/lib.rs

+16
Original file line numberDiff line numberDiff line change
@@ -1201,6 +1201,22 @@ impl MutinyWallet {
12011201
Ok(self.inner.recover_federation_backups().await?)
12021202
}
12031203

1204+
/// Creates a recommendation event for a federation
1205+
pub async fn recommend_federation(
1206+
&self,
1207+
invite_code: String,
1208+
review: Option<String>,
1209+
) -> Result<String, MutinyJsError> {
1210+
let invite_code =
1211+
InviteCode::from_str(&invite_code).map_err(|_| MutinyJsError::InvalidArgumentsError)?;
1212+
let event_id = self
1213+
.inner
1214+
.nostr
1215+
.recommend_federation(&invite_code, review.as_deref())
1216+
.await?;
1217+
Ok(event_id.to_hex())
1218+
}
1219+
12041220
/// Queries our relays for federation announcements
12051221
pub async fn discover_federations(
12061222
&self,

0 commit comments

Comments
 (0)