1- import { Injectable } from '@angular/core' ;
2- import BigNumber from 'bignumber.js' ;
3- import { NanoNym , StealthAccount , NanoNymNotification } from '../types/nanonym.types' ;
4- import { NanoNymStorageService } from './nanonym-storage.service' ;
5- import { NanoNymCryptoService } from './nanonym-crypto.service' ;
6- import { NostrNotificationService } from './nostr-notification.service' ;
7- import { ApiService } from './api.service' ;
8- import { WalletService } from './wallet.service' ;
1+ import { Injectable } from "@angular/core" ;
2+ import BigNumber from "bignumber.js" ;
3+ import {
4+ NanoNym ,
5+ StealthAccount ,
6+ NanoNymNotification ,
7+ } from "../types/nanonym.types" ;
8+ import { NanoNymStorageService } from "./nanonym-storage.service" ;
9+ import { NanoNymCryptoService } from "./nanonym-crypto.service" ;
10+ import { NostrNotificationService } from "./nostr-notification.service" ;
11+ import { ApiService } from "./api.service" ;
12+ import { WalletService } from "./wallet.service" ;
13+ import { Subscription } from "rxjs" ;
914
1015@Injectable ( {
11- providedIn : ' root'
16+ providedIn : " root" ,
1217} )
1318export class NanoNymManagerService {
19+ private notificationSubscription : Subscription | null = null ;
1420
1521 constructor (
1622 private storage : NanoNymStorageService ,
1723 private crypto : NanoNymCryptoService ,
1824 private nostr : NostrNotificationService ,
1925 private api : ApiService ,
20- private wallet : WalletService
21- ) { }
26+ private wallet : WalletService ,
27+ ) {
28+ // Subscribe to incoming Nostr notifications
29+ this . setupNotificationListener ( ) ;
30+ }
2231
2332 /**
2433 * Create a new NanoNym
@@ -27,7 +36,7 @@ export class NanoNymManagerService {
2736 // Get wallet seed
2837 const seed = this . wallet . wallet . seed ;
2938 if ( ! seed ) {
30- throw new Error ( ' Wallet seed not available' ) ;
39+ throw new Error ( " Wallet seed not available" ) ;
3140 }
3241
3342 // Get next index
@@ -40,7 +49,7 @@ export class NanoNymManagerService {
4049 const nnymAddress = this . crypto . encodeNanoNymAddress (
4150 keys . spendPublic ,
4251 keys . viewPublic ,
43- keys . nostrPublic
52+ keys . nostrPublic ,
4453 ) ;
4554
4655 // Get fallback address
@@ -52,7 +61,7 @@ export class NanoNymManagerService {
5261 label : label || `NanoNym ${ index } ` ,
5362 nnymAddress,
5463 fallbackAddress,
55- status : ' active' ,
64+ status : " active" ,
5665 createdAt : Date . now ( ) ,
5766 keys : {
5867 spendPublic : keys . spendPublic ,
@@ -64,7 +73,7 @@ export class NanoNymManagerService {
6473 } ,
6574 balance : new BigNumber ( 0 ) ,
6675 paymentCount : 0 ,
67- stealthAccounts : [ ]
76+ stealthAccounts : [ ] ,
6877 } ;
6978
7079 // Save to storage
@@ -89,7 +98,7 @@ export class NanoNymManagerService {
8998 await this . stopMonitoring ( nanoNym ) ;
9099
91100 // Update status
92- this . storage . updateNanoNym ( index , { status : ' archived' } ) ;
101+ this . storage . updateNanoNym ( index , { status : " archived" } ) ;
93102 }
94103
95104 /**
@@ -102,7 +111,7 @@ export class NanoNymManagerService {
102111 }
103112
104113 // Update status
105- this . storage . updateNanoNym ( index , { status : ' active' } ) ;
114+ this . storage . updateNanoNym ( index , { status : " active" } ) ;
106115
107116 // Start monitoring
108117 await this . startMonitoring ( nanoNym ) ;
@@ -115,11 +124,16 @@ export class NanoNymManagerService {
115124 try {
116125 await this . nostr . subscribeToNotifications (
117126 nanoNym . keys . nostrPublic ,
118- nanoNym . keys . nostrPrivate
127+ nanoNym . keys . nostrPrivate ,
128+ ) ;
129+ console . log (
130+ `Started monitoring NanoNym ${ nanoNym . index } : ${ nanoNym . label } ` ,
119131 ) ;
120- console . log ( `Started monitoring NanoNym ${ nanoNym . index } : ${ nanoNym . label } ` ) ;
121132 } catch ( error ) {
122- console . error ( `Failed to start monitoring for NanoNym ${ nanoNym . index } :` , error ) ;
133+ console . error (
134+ `Failed to start monitoring for NanoNym ${ nanoNym . index } :` ,
135+ error ,
136+ ) ;
123137 }
124138 }
125139
@@ -129,9 +143,14 @@ export class NanoNymManagerService {
129143 private async stopMonitoring ( nanoNym : NanoNym ) : Promise < void > {
130144 try {
131145 await this . nostr . unsubscribeFromNotifications ( nanoNym . keys . nostrPublic ) ;
132- console . log ( `Stopped monitoring NanoNym ${ nanoNym . index } : ${ nanoNym . label } ` ) ;
146+ console . log (
147+ `Stopped monitoring NanoNym ${ nanoNym . index } : ${ nanoNym . label } ` ,
148+ ) ;
133149 } catch ( error ) {
134- console . error ( `Failed to stop monitoring for NanoNym ${ nanoNym . index } :` , error ) ;
150+ console . error (
151+ `Failed to stop monitoring for NanoNym ${ nanoNym . index } :` ,
152+ error ,
153+ ) ;
135154 }
136155 }
137156
@@ -151,7 +170,7 @@ export class NanoNymManagerService {
151170 async stopMonitoringAll ( ) : Promise < void > {
152171 const allNanoNyms = this . storage . getAllNanoNyms ( ) ;
153172 for ( const nanoNym of allNanoNyms ) {
154- if ( nanoNym . status === ' active' ) {
173+ if ( nanoNym . status === " active" ) {
155174 await this . stopMonitoring ( nanoNym ) ;
156175 }
157176 }
@@ -162,7 +181,7 @@ export class NanoNymManagerService {
162181 */
163182 async processNotification (
164183 notification : NanoNymNotification ,
165- nanoNymIndex : number
184+ nanoNymIndex : number ,
166185 ) : Promise < StealthAccount | null > {
167186 try {
168187 const nanoNym = this . storage . getNanoNym ( nanoNymIndex ) ;
@@ -177,20 +196,22 @@ export class NanoNymManagerService {
177196 // 2. Generate shared secret using view key
178197 const sharedSecret = this . crypto . generateSharedSecret (
179198 nanoNym . keys . viewPrivate ,
180- R
199+ R ,
181200 ) ;
182201
183202 // 3. Derive expected stealth address
184203 const stealth = this . crypto . deriveStealthAddress (
185204 sharedSecret ,
186205 R ,
187- nanoNym . keys . spendPublic
206+ nanoNym . keys . spendPublic ,
188207 ) ;
189208
190209 // 4. Verify transaction exists on blockchain
191210 const accountInfo = await this . api . accountInfo ( stealth . address ) ;
192211 if ( accountInfo . error ) {
193- console . error ( `Stealth address not found on blockchain: ${ stealth . address } ` ) ;
212+ console . error (
213+ `Stealth address not found on blockchain: ${ stealth . address } ` ,
214+ ) ;
194215 return null ;
195216 }
196217
@@ -199,7 +220,7 @@ export class NanoNymManagerService {
199220 nanoNym . keys . spendPrivate ,
200221 sharedSecret ,
201222 R ,
202- nanoNym . keys . spendPublic
223+ nanoNym . keys . spendPublic ,
203224 ) ;
204225
205226 // 6. Create stealth account object
@@ -209,11 +230,11 @@ export class NanoNymManagerService {
209230 privateKey : privateKey ,
210231 ephemeralPublicKey : R ,
211232 txHash : notification . tx_hash ,
212- amountRaw : notification . amount_raw || '0' ,
233+ amountRaw : notification . amount_raw || "0" ,
213234 memo : notification . memo ,
214235 receivedAt : Date . now ( ) ,
215236 parentNanoNymIndex : nanoNymIndex ,
216- balance : new BigNumber ( accountInfo . balance || 0 )
237+ balance : new BigNumber ( accountInfo . balance || 0 ) ,
217238 } ;
218239
219240 // 7. Store stealth account
@@ -222,26 +243,31 @@ export class NanoNymManagerService {
222243 // 8. Import into wallet for spending capability
223244 await this . importStealthAccountToWallet ( stealthAccount ) ;
224245
225- console . log ( `Processed notification for NanoNym ${ nanoNymIndex } , stealth address: ${ stealth . address } ` ) ;
246+ console . log (
247+ `Processed notification for NanoNym ${ nanoNymIndex } , stealth address: ${ stealth . address } ` ,
248+ ) ;
226249 return stealthAccount ;
227-
228250 } catch ( error ) {
229- console . error ( ' Failed to process notification:' , error ) ;
251+ console . error ( " Failed to process notification:" , error ) ;
230252 return null ;
231253 }
232254 }
233255
234256 /**
235257 * Import stealth account into wallet for spending
236258 */
237- private async importStealthAccountToWallet ( stealthAccount : StealthAccount ) : Promise < void > {
259+ private async importStealthAccountToWallet (
260+ stealthAccount : StealthAccount ,
261+ ) : Promise < void > {
238262 try {
239263 // TODO: Add stealth account to WalletService
240264 // This will require modifying WalletService to support imported accounts
241265 // For now, we'll just log it
242- console . log ( `TODO: Import stealth account ${ stealthAccount . address } to wallet` ) ;
266+ console . log (
267+ `TODO: Import stealth account ${ stealthAccount . address } to wallet` ,
268+ ) ;
243269 } catch ( error ) {
244- console . error ( ' Failed to import stealth account to wallet:' , error ) ;
270+ console . error ( " Failed to import stealth account to wallet:" , error ) ;
245271 }
246272 }
247273
@@ -256,9 +282,16 @@ export class NanoNymManagerService {
256282 try {
257283 const accountInfo = await this . api . accountInfo ( stealthAccount . address ) ;
258284 const balance = new BigNumber ( accountInfo . balance || 0 ) ;
259- this . storage . updateStealthAccountBalance ( nanoNymIndex , stealthAccount . address , balance ) ;
285+ this . storage . updateStealthAccountBalance (
286+ nanoNymIndex ,
287+ stealthAccount . address ,
288+ balance ,
289+ ) ;
260290 } catch ( error ) {
261- console . error ( `Failed to refresh balance for ${ stealthAccount . address } :` , error ) ;
291+ console . error (
292+ `Failed to refresh balance for ${ stealthAccount . address } :` ,
293+ error ,
294+ ) ;
262295 }
263296 }
264297 }
@@ -292,4 +325,48 @@ export class NanoNymManagerService {
292325 }
293326 return bytes ;
294327 }
328+
329+ /**
330+ * Set up listener for incoming Nostr notifications
331+ */
332+ private setupNotificationListener ( ) : void {
333+ this . notificationSubscription = this . nostr . incomingNotifications$ . subscribe (
334+ async ( incoming ) => {
335+ console . log ( "Received Nostr notification:" , incoming . notification ) ;
336+
337+ // Find which NanoNym this notification belongs to
338+ const allNanoNyms = this . storage . getAllNanoNyms ( ) ;
339+ for ( const nanoNym of allNanoNyms ) {
340+ // Compare nostr public keys
341+ const nostrPublicHex = Array . from ( nanoNym . keys . nostrPublic )
342+ . map ( ( b ) => b . toString ( 16 ) . padStart ( 2 , "0" ) )
343+ . join ( "" ) ;
344+
345+ const receiverPublicHex = Array . from ( incoming . receiverNostrPrivate )
346+ . map ( ( b ) => b . toString ( 16 ) . padStart ( 2 , "0" ) )
347+ . join ( "" ) ;
348+
349+ // Note: We're comparing with private key bytes here, but we should compare public keys
350+ // This is a simplification - in production we'd derive public from private or store mapping
351+
352+ // For now, process notification for all active NanoNyms and let verification handle it
353+ if ( nanoNym . status === "active" ) {
354+ await this . processNotification (
355+ incoming . notification ,
356+ nanoNym . index ,
357+ ) ;
358+ }
359+ }
360+ } ,
361+ ) ;
362+ }
363+
364+ /**
365+ * Clean up subscriptions
366+ */
367+ ngOnDestroy ( ) : void {
368+ if ( this . notificationSubscription ) {
369+ this . notificationSubscription . unsubscribe ( ) ;
370+ }
371+ }
295372}
0 commit comments