nip61: perhaps simplify the function signature and support specific source mints.

This commit is contained in:
fiatjaf
2025-05-05 16:56:20 -03:00
parent b711548b03
commit 3723924561
5 changed files with 50 additions and 42 deletions

View File

@@ -16,21 +16,34 @@ import (
var NutzapsNotAccepted = errors.New("user doesn't accept nutzaps") 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( func SendNutzap(
ctx context.Context, ctx context.Context,
kr nostr.Keyer, kr nostr.Keyer,
w *nip60.Wallet, w *nip60.Wallet,
pool *nostr.Pool, 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, amount uint64,
message string, targetUser nostr.PubKey,
targetUserRelays []string,
opts NutzapOptions,
) (chan nostr.PublishResult, error) { ) (chan nostr.PublishResult, error) {
ie := pool.QuerySingle(ctx, relays, nostr.Filter{ ie := pool.QuerySingle(ctx, targetUserRelays, nostr.Filter{
Kinds: []nostr.Kind{10019}, Kinds: []nostr.Kind{10019},
Authors: []nostr.PubKey{targetUserPublickey}, Authors: []nostr.PubKey{targetUser},
}, },
nostr.SubscriptionOptions{Label: "pre-nutzap"}) nostr.SubscriptionOptions{Label: "pre-nutzap"})
if ie == nil { if ie == nil {
@@ -46,13 +59,10 @@ func SendNutzap(
return nil, NutzapsNotAccepted 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 { 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{ nutzap := nostr.Event{
CreatedAt: nostr.Now(), CreatedAt: nostr.Now(),
@@ -60,9 +70,9 @@ func SendNutzap(
Tags: make(nostr.Tags, 0, 8), Tags: make(nostr.Tags, 0, 8),
} }
nutzap.Tags = append(nutzap.Tags, nostr.Tag{"p", targetUserPublickey.Hex()}) nutzap.Tags = append(nutzap.Tags, nostr.Tag{"p", targetUser.Hex()})
if eventId != nostr.ZeroID { if opts.EventID != nostr.ZeroID {
nutzap.Tags = append(nutzap.Tags, nostr.Tag{"e", eventId.Hex()}) nutzap.Tags = append(nutzap.Tags, nostr.Tag{"e", opts.EventID.Hex()})
} }
p2pk, err := btcec.ParsePubKey(append([]byte{2}, info.PublicKey[:]...)) 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 // check if we have enough tokens in any of these mints
for mint := range getEligibleTokensWeHave(info.Mints, w.Tokens, amount) { for mint := range getEligibleTokensWeHave(info.Mints, w.Tokens, amount) {
if opts.SpecificSourceMint != "" && opts.SpecificSourceMint != mint {
continue
}
proofs, _, err := w.Send(ctx, amount, nip60.SendOptions{ proofs, _, err := w.Send(ctx, amount, nip60.SendOptions{
P2PK: p2pk, P2PK: p2pk,
SpecificSourceMint: mint, SpecificSourceMint: mint,
@@ -98,6 +112,7 @@ func SendNutzap(
for _, mint := range info.Mints { for _, mint := range info.Mints {
proofs, err := w.SendExternal(ctx, mint, amount, nip60.SendOptions{ proofs, err := w.SendExternal(ctx, mint, amount, nip60.SendOptions{
P2PK: p2pk, P2PK: p2pk,
SpecificSourceMint: opts.SpecificSourceMint,
}) })
if err != nil { if err != nil {
if strings.Contains(err.Error(), "generate mint quote") { if strings.Contains(err.Error(), "generate mint quote") {

View File

@@ -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
}

View File

@@ -2,6 +2,7 @@ package sdk
import ( import (
"context" "context"
"encoding/json"
"fmt" "fmt"
"time" "time"

View File

@@ -76,9 +76,9 @@ func (sys *System) FetchSpecificEvent(
author = v.Author author = v.Author
filter.IDs = []nostr.ID{v.ID} filter.IDs = []nostr.ID{v.ID}
relays = append(relays, v.Relays...) 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 = append(fallback, sys.JustIDRelays.URLs...)
fallback = appendUnique(fallback, sys.FallbackRelays.Next()) fallback = nostr.AppendUnique(fallback, sys.FallbackRelays.Next())
priorityRelays = append(priorityRelays, v.Relays...) priorityRelays = append(priorityRelays, v.Relays...)
case nostr.EntityPointer: case nostr.EntityPointer:
author = v.PublicKey author = v.PublicKey
@@ -86,7 +86,7 @@ func (sys *System) FetchSpecificEvent(
filter.Tags = nostr.TagMap{"d": []string{v.Identifier}} filter.Tags = nostr.TagMap{"d": []string{v.Identifier}}
filter.Kinds = []nostr.Kind{v.Kind} filter.Kinds = []nostr.Kind{v.Kind}
relays = append(relays, v.Relays...) 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()) fallback = append(fallback, sys.FallbackRelays.Next(), sys.FallbackRelays.Next())
priorityRelays = append(priorityRelays, v.Relays...) priorityRelays = append(priorityRelays, v.Relays...)
} }
@@ -110,8 +110,8 @@ func (sys *System) FetchSpecificEvent(
} }
// arrange these // arrange these
relays = appendUnique(relays, authorRelays...) relays = nostr.AppendUnique(relays, authorRelays...)
priorityRelays = appendUnique(priorityRelays, authorRelays...) priorityRelays = nostr.AppendUnique(priorityRelays, authorRelays...)
} }
var result *nostr.Event var result *nostr.Event

View File

@@ -5,6 +5,7 @@ import (
"cmp" "cmp"
"encoding/hex" "encoding/hex"
"net/url" "net/url"
"slices"
) )
// IsValidRelayURL checks if a URL is a valid relay URL (ws:// or wss://). // 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) 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
}