From 37239245615ff144db45f6fb90a765281f31227c Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Mon, 5 May 2025 16:56:20 -0300 Subject: [PATCH] nip61: perhaps simplify the function signature and support specific source mints. --- nip61/nip61.go | 47 ++++++++++++++++++++++++++++--------------- sdk/helpers.go | 21 ------------------- sdk/metadata.go | 1 + sdk/specific_event.go | 10 ++++----- utils.go | 13 ++++++++++++ 5 files changed, 50 insertions(+), 42 deletions(-) delete mode 100644 sdk/helpers.go diff --git a/nip61/nip61.go b/nip61/nip61.go index c7c931f..8d52392 100644 --- a/nip61/nip61.go +++ b/nip61/nip61.go @@ -16,21 +16,34 @@ import ( var NutzapsNotAccepted = errors.New("user doesn't accept nutzaps") +type NutzapOptions struct { + // Optionally specify the event we'll reference in the nutzap, + // if not specified we'll just send money to the receiver + EventID nostr.ID + + // string message to include in the nutzap + Message string + + // We'll send the nutzap to these relays besides any relay found in the kind:10019 + SendToRelays []string + + // Send specifically from this mint + SpecificSourceMint string +} + func SendNutzap( ctx context.Context, kr nostr.Keyer, w *nip60.Wallet, pool *nostr.Pool, - targetUserPublickey nostr.PubKey, - getUserReadRelays func(context.Context, nostr.PubKey, int) []string, - relays []string, - eventId nostr.ID, // can be "" if not targeting a specific event amount uint64, - message string, + targetUser nostr.PubKey, + targetUserRelays []string, + opts NutzapOptions, ) (chan nostr.PublishResult, error) { - ie := pool.QuerySingle(ctx, relays, nostr.Filter{ + ie := pool.QuerySingle(ctx, targetUserRelays, nostr.Filter{ Kinds: []nostr.Kind{10019}, - Authors: []nostr.PubKey{targetUserPublickey}, + Authors: []nostr.PubKey{targetUser}, }, nostr.SubscriptionOptions{Label: "pre-nutzap"}) if ie == nil { @@ -46,12 +59,9 @@ func SendNutzap( return nil, NutzapsNotAccepted } - targetRelays := info.Relays + targetRelays := nostr.AppendUnique(info.Relays, opts.SendToRelays...) if len(targetRelays) == 0 { - targetRelays = getUserReadRelays(ctx, targetUserPublickey, 3) - if len(targetRelays) == 0 { - return nil, fmt.Errorf("no relays found for sending the nutzap") - } + return nil, fmt.Errorf("no relays found for sending the nutzap") } nutzap := nostr.Event{ @@ -60,9 +70,9 @@ func SendNutzap( Tags: make(nostr.Tags, 0, 8), } - nutzap.Tags = append(nutzap.Tags, nostr.Tag{"p", targetUserPublickey.Hex()}) - if eventId != nostr.ZeroID { - nutzap.Tags = append(nutzap.Tags, nostr.Tag{"e", eventId.Hex()}) + nutzap.Tags = append(nutzap.Tags, nostr.Tag{"p", targetUser.Hex()}) + if opts.EventID != nostr.ZeroID { + nutzap.Tags = append(nutzap.Tags, nostr.Tag{"e", opts.EventID.Hex()}) } p2pk, err := btcec.ParsePubKey(append([]byte{2}, info.PublicKey[:]...)) @@ -72,6 +82,10 @@ func SendNutzap( // check if we have enough tokens in any of these mints for mint := range getEligibleTokensWeHave(info.Mints, w.Tokens, amount) { + if opts.SpecificSourceMint != "" && opts.SpecificSourceMint != mint { + continue + } + proofs, _, err := w.Send(ctx, amount, nip60.SendOptions{ P2PK: p2pk, SpecificSourceMint: mint, @@ -97,7 +111,8 @@ func SendNutzap( // we don't have tokens at the desired target mint, so we first have to create some for _, mint := range info.Mints { proofs, err := w.SendExternal(ctx, mint, amount, nip60.SendOptions{ - P2PK: p2pk, + P2PK: p2pk, + SpecificSourceMint: opts.SpecificSourceMint, }) if err != nil { if strings.Contains(err.Error(), "generate mint quote") { diff --git a/sdk/helpers.go b/sdk/helpers.go deleted file mode 100644 index 9a49e1b..0000000 --- a/sdk/helpers.go +++ /dev/null @@ -1,21 +0,0 @@ -package sdk - -import ( - "slices" - - jsoniter "github.com/json-iterator/go" -) - -var json = jsoniter.ConfigFastest - -// appendUnique adds items to an array only if they don't already exist in the array. -// Returns the modified array. -func appendUnique[I comparable](arr []I, item ...I) []I { - for _, item := range item { - if slices.Contains(arr, item) { - return arr - } - arr = append(arr, item) - } - return arr -} diff --git a/sdk/metadata.go b/sdk/metadata.go index b772e18..75722ba 100644 --- a/sdk/metadata.go +++ b/sdk/metadata.go @@ -2,6 +2,7 @@ package sdk import ( "context" + "encoding/json" "fmt" "time" diff --git a/sdk/specific_event.go b/sdk/specific_event.go index 8ccb1d6..3fe907b 100644 --- a/sdk/specific_event.go +++ b/sdk/specific_event.go @@ -76,9 +76,9 @@ func (sys *System) FetchSpecificEvent( author = v.Author filter.IDs = []nostr.ID{v.ID} relays = append(relays, v.Relays...) - relays = appendUnique(relays, sys.FallbackRelays.Next()) + relays = nostr.AppendUnique(relays, sys.FallbackRelays.Next()) fallback = append(fallback, sys.JustIDRelays.URLs...) - fallback = appendUnique(fallback, sys.FallbackRelays.Next()) + fallback = nostr.AppendUnique(fallback, sys.FallbackRelays.Next()) priorityRelays = append(priorityRelays, v.Relays...) case nostr.EntityPointer: author = v.PublicKey @@ -86,7 +86,7 @@ func (sys *System) FetchSpecificEvent( filter.Tags = nostr.TagMap{"d": []string{v.Identifier}} filter.Kinds = []nostr.Kind{v.Kind} relays = append(relays, v.Relays...) - relays = appendUnique(relays, sys.FallbackRelays.Next()) + relays = nostr.AppendUnique(relays, sys.FallbackRelays.Next()) fallback = append(fallback, sys.FallbackRelays.Next(), sys.FallbackRelays.Next()) priorityRelays = append(priorityRelays, v.Relays...) } @@ -110,8 +110,8 @@ func (sys *System) FetchSpecificEvent( } // arrange these - relays = appendUnique(relays, authorRelays...) - priorityRelays = appendUnique(priorityRelays, authorRelays...) + relays = nostr.AppendUnique(relays, authorRelays...) + priorityRelays = nostr.AppendUnique(priorityRelays, authorRelays...) } var result *nostr.Event diff --git a/utils.go b/utils.go index 0f577ae..0a63417 100644 --- a/utils.go +++ b/utils.go @@ -5,6 +5,7 @@ import ( "cmp" "encoding/hex" "net/url" + "slices" ) // IsValidRelayURL checks if a URL is a valid relay URL (ws:// or wss://). @@ -46,3 +47,15 @@ func CompareEventReverse(b, a Event) int { } return cmp.Compare(a.CreatedAt, b.CreatedAt) } + +// AppendUnique adds items to an array only if they don't already exist in the array. +// Returns the modified array. +func AppendUnique[I comparable](arr []I, item ...I) []I { + for _, item := range item { + if slices.Contains(arr, item) { + return arr + } + arr = append(arr, item) + } + return arr +}