|
|
|
@ -6,13 +6,10 @@ import { |
|
|
|
import { hexPubkeysEqual, normalizeHexPubkey } from '@/lib/pubkey' |
|
|
|
import { hexPubkeysEqual, normalizeHexPubkey } from '@/lib/pubkey' |
|
|
|
import { |
|
|
|
import { |
|
|
|
hydrateAttestationsForAuthor, |
|
|
|
hydrateAttestationsForAuthor, |
|
|
|
isLocallyMarkedAttested, |
|
|
|
|
|
|
|
loadPaymentAttestationLocal, |
|
|
|
loadPaymentAttestationLocal, |
|
|
|
peekCachedPaymentAttestation, |
|
|
|
peekCachedPaymentAttestation, |
|
|
|
readKnownAttestedPaymentTargetsSync, |
|
|
|
|
|
|
|
refreshPaymentAttestationFromRelays, |
|
|
|
refreshPaymentAttestationFromRelays, |
|
|
|
rememberPaymentAttestationFromPublish, |
|
|
|
rememberPaymentAttestationFromPublish |
|
|
|
resolveAttestedPaymentIdSet |
|
|
|
|
|
|
|
} from '@/lib/payment-attestation-cache' |
|
|
|
} from '@/lib/payment-attestation-cache' |
|
|
|
import client from '@/services/client.service' |
|
|
|
import client from '@/services/client.service' |
|
|
|
import { Event as NostrEvent } from 'nostr-tools' |
|
|
|
import { Event as NostrEvent } from 'nostr-tools' |
|
|
|
@ -38,6 +35,7 @@ export function isPaymentAttestationForTarget( |
|
|
|
return Boolean(attestedId && attestedId.toLowerCase() === targetEventId.trim().toLowerCase()) |
|
|
|
return Boolean(attestedId && attestedId.toLowerCase() === targetEventId.trim().toLowerCase()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Sync read: only true when a verified attestation is already in the in-memory cache. */ |
|
|
|
export function readAttestedFromLocalSources( |
|
|
|
export function readAttestedFromLocalSources( |
|
|
|
targetEventId: string | undefined, |
|
|
|
targetEventId: string | undefined, |
|
|
|
recipientPubkey: string | null |
|
|
|
recipientPubkey: string | null |
|
|
|
@ -45,25 +43,11 @@ export function readAttestedFromLocalSources( |
|
|
|
if (!targetEventId || !recipientPubkey) { |
|
|
|
if (!targetEventId || !recipientPubkey) { |
|
|
|
return { attested: false, attestationEvent: null } |
|
|
|
return { attested: false, attestationEvent: null } |
|
|
|
} |
|
|
|
} |
|
|
|
const targetLower = targetEventId.trim().toLowerCase() |
|
|
|
|
|
|
|
const hit = peekCachedPaymentAttestation(targetEventId, recipientPubkey) |
|
|
|
const hit = peekCachedPaymentAttestation(targetEventId, recipientPubkey) |
|
|
|
if (hit) { |
|
|
|
if (!hit || !isPaymentAttestationForTarget(hit, targetEventId, recipientPubkey)) { |
|
|
|
return { attested: true, attestationEvent: hit } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if ( |
|
|
|
|
|
|
|
isLocallyMarkedAttested(recipientPubkey, targetEventId) || |
|
|
|
|
|
|
|
readKnownAttestedPaymentTargetsSync(recipientPubkey).has(targetLower) |
|
|
|
|
|
|
|
) { |
|
|
|
|
|
|
|
return { attested: true, attestationEvent: null } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return { attested: false, attestationEvent: null } |
|
|
|
return { attested: false, attestationEvent: null } |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return { attested: true, attestationEvent: hit } |
|
|
|
function isTargetInAttestedSet( |
|
|
|
|
|
|
|
attestedIds: ReadonlySet<string>, |
|
|
|
|
|
|
|
targetEventId: string |
|
|
|
|
|
|
|
): boolean { |
|
|
|
|
|
|
|
return attestedIds.has(targetEventId.trim().toLowerCase()) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
export function usePaymentAttestationStatus( |
|
|
|
export function usePaymentAttestationStatus( |
|
|
|
@ -100,10 +84,11 @@ export function usePaymentAttestationStatus( |
|
|
|
|
|
|
|
|
|
|
|
const applyMatch = useCallback( |
|
|
|
const applyMatch = useCallback( |
|
|
|
(match: NostrEvent | undefined) => { |
|
|
|
(match: NostrEvent | undefined) => { |
|
|
|
if (!match || !targetEvent?.id || !recipientPubkey) return |
|
|
|
if (!match || !targetEvent?.id || !recipientPubkey) return false |
|
|
|
if (!isPaymentAttestationForTarget(match, targetEvent.id, recipientPubkey)) return |
|
|
|
if (!isPaymentAttestationForTarget(match, targetEvent.id, recipientPubkey)) return false |
|
|
|
setAttestationEvent(match) |
|
|
|
setAttestationEvent(match) |
|
|
|
setAttested(true) |
|
|
|
setAttested(true) |
|
|
|
|
|
|
|
return true |
|
|
|
}, |
|
|
|
}, |
|
|
|
[recipientPubkey, targetEvent?.id] |
|
|
|
[recipientPubkey, targetEvent?.id] |
|
|
|
) |
|
|
|
) |
|
|
|
@ -129,22 +114,6 @@ export function usePaymentAttestationStatus( |
|
|
|
setAttested(next.attested) |
|
|
|
setAttested(next.attested) |
|
|
|
}, [recipientPubkey, targetEvent?.id, targetId]) |
|
|
|
}, [recipientPubkey, targetEvent?.id, targetId]) |
|
|
|
|
|
|
|
|
|
|
|
const applyResolvedAttestation = useCallback( |
|
|
|
|
|
|
|
(attestedIds: ReadonlySet<string>) => { |
|
|
|
|
|
|
|
if (!targetEvent?.id || !recipientPubkey) return false |
|
|
|
|
|
|
|
if (!isTargetInAttestedSet(attestedIds, targetEvent.id)) return false |
|
|
|
|
|
|
|
const cached = peekCachedPaymentAttestation(targetEvent.id, recipientPubkey) |
|
|
|
|
|
|
|
if (cached) { |
|
|
|
|
|
|
|
applyMatch(cached) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
setAttestationEvent(null) |
|
|
|
|
|
|
|
setAttested(true) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return true |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
[applyMatch, recipientPubkey, targetEvent?.id] |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
useEffect(() => { |
|
|
|
if (!recipientPubkey || !targetEvent?.id) return |
|
|
|
if (!recipientPubkey || !targetEvent?.id) return |
|
|
|
|
|
|
|
|
|
|
|
@ -152,14 +121,8 @@ export function usePaymentAttestationStatus( |
|
|
|
void (async () => { |
|
|
|
void (async () => { |
|
|
|
await hydrateAttestationsForAuthor(recipientPubkey) |
|
|
|
await hydrateAttestationsForAuthor(recipientPubkey) |
|
|
|
if (cancelled) return |
|
|
|
if (cancelled) return |
|
|
|
const next = readAttestedFromLocalSources(targetEvent.id, recipientPubkey) |
|
|
|
const cached = peekCachedPaymentAttestation(targetEvent.id, recipientPubkey) |
|
|
|
if (!next.attested) return |
|
|
|
if (cached && applyMatch(cached)) return |
|
|
|
if (next.attestationEvent) { |
|
|
|
|
|
|
|
applyMatch(next.attestationEvent) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
setAttestationEvent(null) |
|
|
|
|
|
|
|
setAttested(true) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
})() |
|
|
|
})() |
|
|
|
|
|
|
|
|
|
|
|
return () => { |
|
|
|
return () => { |
|
|
|
@ -177,14 +140,7 @@ export function usePaymentAttestationStatus( |
|
|
|
try { |
|
|
|
try { |
|
|
|
const local = await loadPaymentAttestationLocal(targetEvent.id, recipientPubkey, filter) |
|
|
|
const local = await loadPaymentAttestationLocal(targetEvent.id, recipientPubkey, filter) |
|
|
|
if (cancelled) return |
|
|
|
if (cancelled) return |
|
|
|
if (local) { |
|
|
|
if (local && applyMatch(local)) return |
|
|
|
applyMatch(local) |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const attestedIds = await resolveAttestedPaymentIdSet(recipientPubkey) |
|
|
|
|
|
|
|
if (cancelled) return |
|
|
|
|
|
|
|
if (applyResolvedAttestation(attestedIds)) return |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const relay = await refreshPaymentAttestationFromRelays( |
|
|
|
const relay = await refreshPaymentAttestationFromRelays( |
|
|
|
targetEvent.id, |
|
|
|
targetEvent.id, |
|
|
|
@ -192,16 +148,9 @@ export function usePaymentAttestationStatus( |
|
|
|
filter |
|
|
|
filter |
|
|
|
) |
|
|
|
) |
|
|
|
if (cancelled) return |
|
|
|
if (cancelled) return |
|
|
|
if (relay) { |
|
|
|
if (relay && applyMatch(relay)) return |
|
|
|
applyMatch(relay) |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const afterRelay = await resolveAttestedPaymentIdSet(recipientPubkey) |
|
|
|
|
|
|
|
if (cancelled) return |
|
|
|
|
|
|
|
if (!applyResolvedAttestation(afterRelay)) { |
|
|
|
|
|
|
|
clearAttested() |
|
|
|
clearAttested() |
|
|
|
} |
|
|
|
|
|
|
|
} catch { |
|
|
|
} catch { |
|
|
|
/* optional */ |
|
|
|
/* optional */ |
|
|
|
} finally { |
|
|
|
} finally { |
|
|
|
@ -212,15 +161,7 @@ export function usePaymentAttestationStatus( |
|
|
|
return () => { |
|
|
|
return () => { |
|
|
|
cancelled = true |
|
|
|
cancelled = true |
|
|
|
} |
|
|
|
} |
|
|
|
}, [ |
|
|
|
}, [applyMatch, clearAttested, filter, recipientPubkey, targetEvent?.id, targetId]) |
|
|
|
applyMatch, |
|
|
|
|
|
|
|
applyResolvedAttestation, |
|
|
|
|
|
|
|
clearAttested, |
|
|
|
|
|
|
|
filter, |
|
|
|
|
|
|
|
recipientPubkey, |
|
|
|
|
|
|
|
targetEvent?.id, |
|
|
|
|
|
|
|
targetId |
|
|
|
|
|
|
|
]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
useEffect(() => { |
|
|
|
if (!targetEvent?.id || !recipientPubkey) return |
|
|
|
if (!targetEvent?.id || !recipientPubkey) return |
|
|
|
|