- Intégration mempool.space pour vérification transactions Bitcoin : - Service MempoolSpaceService avec API mempool.space - Vérification sorties et montants pour sponsoring - Vérification confirmations - Attente confirmation avec polling - Récupération adresses Lightning depuis profils Nostr : - Service LightningAddressService - Support lud16 et lud06 (NIP-19) - Cache avec TTL 1 heure - Intégré dans paymentPolling et reviewReward - Mise à jour événements Nostr pour avis rémunérés : - Publication événement avec tags rewarded et reward_amount - Parsing tags dans parseReviewFromEvent - Vérification doublons - Tracking sponsoring sur Nostr : - Service SponsoringTrackingService - Événements avec commissions et confirmations - Intégration vérification mempool.space Toutes les fonctionnalités de split sont maintenant opérationnelles. Seuls les transferts Lightning réels nécessitent un nœud Lightning.
104 lines
2.6 KiB
TypeScript
104 lines
2.6 KiB
TypeScript
import { nostrService } from './nostr'
|
|
import type { NostrProfile } from '@/types/nostr'
|
|
|
|
/**
|
|
* Lightning address service
|
|
* Retrieves Lightning addresses from Nostr profiles
|
|
*
|
|
* Supports:
|
|
* - lud16: Lightning address format (user@domain.com)
|
|
* - lud06: LNURL format
|
|
*/
|
|
export class LightningAddressService {
|
|
private addressCache: Map<string, string | null> = new Map()
|
|
private readonly CACHE_TTL = 3600000 // 1 hour
|
|
|
|
/**
|
|
* Get Lightning address from Nostr profile
|
|
* Checks lud16 first, then lud06
|
|
*/
|
|
async getLightningAddress(pubkey: string): Promise<string | null> {
|
|
// Check cache first
|
|
const cached = this.addressCache.get(pubkey)
|
|
if (cached !== undefined) {
|
|
return cached
|
|
}
|
|
|
|
try {
|
|
const profile = await nostrService.getProfile(pubkey)
|
|
if (!profile) {
|
|
this.addressCache.set(pubkey, null)
|
|
return null
|
|
}
|
|
|
|
const address = this.extractLightningAddress(profile)
|
|
this.addressCache.set(pubkey, address)
|
|
return address
|
|
} catch (error) {
|
|
console.error('Error getting Lightning address', {
|
|
pubkey,
|
|
error: error instanceof Error ? error.message : 'Unknown error',
|
|
timestamp: new Date().toISOString(),
|
|
})
|
|
this.addressCache.set(pubkey, null)
|
|
return null
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Extract Lightning address from profile
|
|
* Checks lud16 first, then lud06
|
|
*/
|
|
private extractLightningAddress(profile: NostrProfile): string | null {
|
|
// Check if profile has extended fields (lud16, lud06)
|
|
const extendedProfile = profile as NostrProfile & {
|
|
lud16?: string
|
|
lud06?: string
|
|
}
|
|
|
|
// Prefer lud16 (Lightning address format)
|
|
if (extendedProfile.lud16) {
|
|
return extendedProfile.lud16
|
|
}
|
|
|
|
// Fallback to lud06 (LNURL format)
|
|
if (extendedProfile.lud06) {
|
|
return extendedProfile.lud06
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
/**
|
|
* Clear cache for a specific pubkey
|
|
*/
|
|
clearCache(pubkey: string): void {
|
|
this.addressCache.delete(pubkey)
|
|
}
|
|
|
|
/**
|
|
* Clear all cache
|
|
*/
|
|
clearAllCache(): void {
|
|
this.addressCache.clear()
|
|
}
|
|
|
|
/**
|
|
* Get Lightning addresses for multiple pubkeys
|
|
*/
|
|
async getLightningAddresses(pubkeys: string[]): Promise<Map<string, string | null>> {
|
|
const addresses = new Map<string, string | null>()
|
|
|
|
const promises = pubkeys.map(async (pubkey) => {
|
|
const address = await this.getLightningAddress(pubkey)
|
|
addresses.set(pubkey, address)
|
|
})
|
|
|
|
await Promise.all(promises)
|
|
return addresses
|
|
}
|
|
}
|
|
|
|
export const lightningAddressService = new LightningAddressService()
|
|
|