@sip-protocol/react 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,3 +8,64 @@ export {
8
8
  type SwapResult,
9
9
  } from './use-private-swap'
10
10
  export { useViewingKey } from './use-viewing-key'
11
+
12
+ // Solana same-chain privacy hooks
13
+ export {
14
+ useStealthTransfer,
15
+ type TransferStatus,
16
+ type UseStealthTransferParams,
17
+ type TransferParams,
18
+ type UseStealthTransferReturn,
19
+ } from './use-stealth-transfer'
20
+
21
+ export {
22
+ useScanPayments,
23
+ type ScanStatus,
24
+ type UseScanPaymentsParams,
25
+ type PaymentWithStatus,
26
+ type UseScanPaymentsReturn,
27
+ type ClaimParams,
28
+ type ClaimAllParams,
29
+ type ClaimAllResult,
30
+ type MintResolver,
31
+ } from './use-scan-payments'
32
+
33
+ // Privacy Advisor hook (LangChain-powered)
34
+ export {
35
+ usePrivacyAdvisor,
36
+ type UsePrivacyAdvisorParams,
37
+ type UsePrivacyAdvisorReturn,
38
+ } from './use-privacy-advisor'
39
+
40
+ // NEAR Transaction History (M17-NEAR-20)
41
+ export {
42
+ useTransactionHistory,
43
+ type HistoryStatus,
44
+ type UseTransactionHistoryParams,
45
+ type HistoryFilters,
46
+ type TransactionSummary,
47
+ type UseTransactionHistoryReturn,
48
+ } from './use-transaction-history'
49
+
50
+ // Proof Composition Hooks (M20-17)
51
+ export {
52
+ // Main hooks
53
+ useProofComposer,
54
+ useProofVerification,
55
+ useComposedProof,
56
+ useProofCache,
57
+ useSystemCompatibility,
58
+ // Types
59
+ type ProofOperationStatus,
60
+ type UseProofComposerConfig,
61
+ type UseProofComposerReturn,
62
+ type UseProofVerificationConfig,
63
+ type UseProofVerificationReturn,
64
+ type UseComposedProofConfig,
65
+ type UseComposedProofReturn,
66
+ type UseProofCacheConfig,
67
+ type UseProofCacheReturn,
68
+ type UseSystemCompatibilityReturn,
69
+ } from './use-proof-composition'
70
+
71
+ // Note: useProofGeneration and useProofQueue will be added after M20-14 merges
@@ -0,0 +1,371 @@
1
+ import { useState, useCallback, useRef, useMemo } from 'react'
2
+ import {
3
+ PrivacyAdvisorAgent,
4
+ createPrivacyAdvisor,
5
+ createSurveillanceAnalyzer,
6
+ } from '@sip-protocol/sdk'
7
+ import type {
8
+ PrivacyAdvisorConfig,
9
+ AdvisoryContext,
10
+ AdvisorResponse,
11
+ PrivacyAdvisoryReport,
12
+ AdvisorMessage,
13
+ AdvisorStatus,
14
+ FullAnalysisResult,
15
+ } from '@sip-protocol/sdk'
16
+
17
+ /**
18
+ * Parameters for usePrivacyAdvisor hook
19
+ */
20
+ export interface UsePrivacyAdvisorParams {
21
+ /** OpenAI API key for the advisor */
22
+ openaiApiKey: string
23
+ /** Helius API key for wallet analysis */
24
+ heliusApiKey: string
25
+ /** Model to use (default: gpt-4o-mini for cost efficiency) */
26
+ model?: PrivacyAdvisorConfig['model']
27
+ /** Temperature for responses (0-1, default: 0.3) */
28
+ temperature?: number
29
+ /** Enable streaming responses */
30
+ enableStreaming?: boolean
31
+ /** Solana cluster */
32
+ cluster?: 'mainnet-beta' | 'devnet'
33
+ }
34
+
35
+ /**
36
+ * Return type for usePrivacyAdvisor hook
37
+ */
38
+ export interface UsePrivacyAdvisorReturn {
39
+ /** Current advisor status */
40
+ status: AdvisorStatus
41
+ /** Whether the advisor is processing */
42
+ isLoading: boolean
43
+ /** Error message if operation failed */
44
+ error: Error | null
45
+ /** Conversation messages */
46
+ messages: AdvisorMessage[]
47
+ /** Current privacy report (if generated) */
48
+ report: PrivacyAdvisoryReport | null
49
+ /** Current analysis result (if analyzed) */
50
+ analysisResult: FullAnalysisResult | null
51
+ /** Suggested follow-up questions */
52
+ suggestedQuestions: string[]
53
+ /** Total cost of API calls in this session */
54
+ totalCost: number
55
+ /** Analyze a wallet and get recommendations */
56
+ analyzeWallet: (walletAddress: string, query?: string) => Promise<AdvisorResponse | null>
57
+ /** Send a chat message (follow-up question) */
58
+ chat: (message: string) => Promise<AdvisorResponse | null>
59
+ /** Clear conversation history and reset */
60
+ reset: () => void
61
+ /** Clear error */
62
+ clearError: () => void
63
+ }
64
+
65
+ /**
66
+ * usePrivacyAdvisor - AI-powered privacy recommendations for Solana wallets
67
+ *
68
+ * @remarks
69
+ * This hook provides a React-friendly interface for the Privacy Advisor Agent.
70
+ * It combines wallet surveillance analysis with LangChain-powered AI recommendations.
71
+ *
72
+ * Features:
73
+ * - Analyze any Solana wallet's privacy exposure
74
+ * - Get AI-generated recommendations in plain English
75
+ * - Chat for follow-up questions
76
+ * - Track API costs
77
+ * - Streaming support for real-time responses
78
+ *
79
+ * @param params - Hook configuration parameters
80
+ *
81
+ * @example
82
+ * ```tsx
83
+ * import { usePrivacyAdvisor } from '@sip-protocol/react'
84
+ *
85
+ * function PrivacyDashboard() {
86
+ * const {
87
+ * status,
88
+ * messages,
89
+ * report,
90
+ * suggestedQuestions,
91
+ * analyzeWallet,
92
+ * chat,
93
+ * } = usePrivacyAdvisor({
94
+ * openaiApiKey: process.env.NEXT_PUBLIC_OPENAI_API_KEY!,
95
+ * heliusApiKey: process.env.NEXT_PUBLIC_HELIUS_API_KEY!,
96
+ * })
97
+ *
98
+ * const handleAnalyze = async () => {
99
+ * await analyzeWallet('7xK9abc123...', 'What should I fix first?')
100
+ * }
101
+ *
102
+ * return (
103
+ * <div>
104
+ * <button onClick={handleAnalyze} disabled={status !== 'idle'}>
105
+ * Analyze My Wallet
106
+ * </button>
107
+ *
108
+ * {report && (
109
+ * <div>
110
+ * <h2>Privacy Score: {report.currentScore}/100</h2>
111
+ * <p>{report.summary}</p>
112
+ *
113
+ * <h3>Recommendations</h3>
114
+ * {report.recommendations.map((rec) => (
115
+ * <div key={rec.id}>
116
+ * <h4>{rec.title}</h4>
117
+ * <p>{rec.explanation}</p>
118
+ * <ul>
119
+ * {rec.actions.map((action, i) => (
120
+ * <li key={i}>{action}</li>
121
+ * ))}
122
+ * </ul>
123
+ * </div>
124
+ * ))}
125
+ * </div>
126
+ * )}
127
+ *
128
+ * <h3>Follow-up Questions</h3>
129
+ * {suggestedQuestions.map((q, i) => (
130
+ * <button key={i} onClick={() => chat(q)}>
131
+ * {q}
132
+ * </button>
133
+ * ))}
134
+ *
135
+ * <h3>Conversation</h3>
136
+ * {messages.map((msg, i) => (
137
+ * <div key={i} className={msg.role}>
138
+ * {msg.content}
139
+ * </div>
140
+ * ))}
141
+ * </div>
142
+ * )
143
+ * }
144
+ * ```
145
+ */
146
+ export function usePrivacyAdvisor(
147
+ params: UsePrivacyAdvisorParams
148
+ ): UsePrivacyAdvisorReturn {
149
+ const {
150
+ openaiApiKey,
151
+ heliusApiKey,
152
+ model = 'gpt-4o-mini',
153
+ temperature = 0.3,
154
+ enableStreaming = false,
155
+ cluster = 'mainnet-beta',
156
+ } = params
157
+
158
+ const [status, setStatus] = useState<AdvisorStatus>('idle')
159
+ const [error, setError] = useState<Error | null>(null)
160
+ const [messages, setMessages] = useState<AdvisorMessage[]>([])
161
+ const [report, setReport] = useState<PrivacyAdvisoryReport | null>(null)
162
+ const [analysisResult, setAnalysisResult] = useState<FullAnalysisResult | null>(null)
163
+ const [suggestedQuestions, setSuggestedQuestions] = useState<string[]>([])
164
+ const [totalCost, setTotalCost] = useState(0)
165
+
166
+ // Memoize agent instances
167
+ const advisor = useMemo(
168
+ () =>
169
+ createPrivacyAdvisor({
170
+ openaiApiKey,
171
+ model,
172
+ temperature,
173
+ }),
174
+ [openaiApiKey, model, temperature]
175
+ )
176
+
177
+ const analyzer = useMemo(
178
+ () =>
179
+ createSurveillanceAnalyzer({
180
+ heliusApiKey,
181
+ cluster,
182
+ }),
183
+ [heliusApiKey, cluster]
184
+ )
185
+
186
+ // Keep reference to latest analysis for chat context
187
+ const analysisRef = useRef<FullAnalysisResult | null>(null)
188
+
189
+ const isLoading = status === 'analyzing' || status === 'thinking' || status === 'responding'
190
+
191
+ /**
192
+ * Analyze a wallet and get recommendations
193
+ */
194
+ const analyzeWallet = useCallback(
195
+ async (
196
+ walletAddress: string,
197
+ query?: string
198
+ ): Promise<AdvisorResponse | null> => {
199
+ setStatus('analyzing')
200
+ setError(null)
201
+
202
+ try {
203
+ // First, run surveillance analysis
204
+ const analysis = await analyzer.analyze(walletAddress)
205
+ setAnalysisResult(analysis)
206
+ analysisRef.current = analysis
207
+
208
+ setStatus('thinking')
209
+
210
+ // Build context for advisor
211
+ const context: AdvisoryContext = {
212
+ analysisResult: analysis,
213
+ userQuery: query,
214
+ }
215
+
216
+ let response: AdvisorResponse
217
+
218
+ if (enableStreaming) {
219
+ // Stream response
220
+ setStatus('responding')
221
+ let streamedContent = ''
222
+
223
+ response = await advisor.stream(context, (chunk) => {
224
+ streamedContent += chunk
225
+ // Update messages with partial content
226
+ setMessages((prev) => {
227
+ const filtered = prev.filter((m) => m.role !== 'assistant' || m.content !== streamedContent.slice(0, -chunk.length))
228
+ return [
229
+ ...filtered,
230
+ {
231
+ role: 'assistant' as const,
232
+ content: streamedContent,
233
+ timestamp: Date.now(),
234
+ },
235
+ ]
236
+ })
237
+ })
238
+ } else {
239
+ // Regular response
240
+ setStatus('responding')
241
+ response = await advisor.analyze(context)
242
+ }
243
+
244
+ // Update state
245
+ if (response.report) {
246
+ setReport(response.report)
247
+ }
248
+
249
+ if (response.suggestedQuestions) {
250
+ setSuggestedQuestions(response.suggestedQuestions)
251
+ }
252
+
253
+ if (response.usage) {
254
+ setTotalCost((prev) => prev + response.usage!.estimatedCost)
255
+ }
256
+
257
+ // Add messages
258
+ setMessages((prev) => [
259
+ ...prev,
260
+ {
261
+ role: 'user' as const,
262
+ content: query || `Analyze wallet ${walletAddress}`,
263
+ timestamp: Date.now(),
264
+ },
265
+ {
266
+ role: 'assistant' as const,
267
+ content: response.message,
268
+ timestamp: Date.now(),
269
+ },
270
+ ])
271
+
272
+ setStatus('idle')
273
+ return response
274
+ } catch (err) {
275
+ const error = err instanceof Error ? err : new Error('Analysis failed')
276
+ setError(error)
277
+ setStatus('error')
278
+ return null
279
+ }
280
+ },
281
+ [advisor, analyzer, enableStreaming]
282
+ )
283
+
284
+ /**
285
+ * Send a chat message (follow-up question)
286
+ */
287
+ const chat = useCallback(
288
+ async (message: string): Promise<AdvisorResponse | null> => {
289
+ setStatus('thinking')
290
+ setError(null)
291
+
292
+ try {
293
+ // Build context with latest analysis if available
294
+ const context: AdvisoryContext | undefined = analysisRef.current
295
+ ? { analysisResult: analysisRef.current }
296
+ : undefined
297
+
298
+ setStatus('responding')
299
+ const response = await advisor.chat(message, context)
300
+
301
+ if (response.usage) {
302
+ setTotalCost((prev) => prev + response.usage!.estimatedCost)
303
+ }
304
+
305
+ // Add messages
306
+ setMessages((prev) => [
307
+ ...prev,
308
+ {
309
+ role: 'user' as const,
310
+ content: message,
311
+ timestamp: Date.now(),
312
+ },
313
+ {
314
+ role: 'assistant' as const,
315
+ content: response.message,
316
+ timestamp: Date.now(),
317
+ },
318
+ ])
319
+
320
+ setStatus('idle')
321
+ return response
322
+ } catch (err) {
323
+ const error = err instanceof Error ? err : new Error('Chat failed')
324
+ setError(error)
325
+ setStatus('error')
326
+ return null
327
+ }
328
+ },
329
+ [advisor]
330
+ )
331
+
332
+ /**
333
+ * Reset all state
334
+ */
335
+ const reset = useCallback(() => {
336
+ setStatus('idle')
337
+ setError(null)
338
+ setMessages([])
339
+ setReport(null)
340
+ setAnalysisResult(null)
341
+ setSuggestedQuestions([])
342
+ setTotalCost(0)
343
+ analysisRef.current = null
344
+ advisor.clearHistory()
345
+ }, [advisor])
346
+
347
+ /**
348
+ * Clear error state
349
+ */
350
+ const clearError = useCallback(() => {
351
+ setError(null)
352
+ if (status === 'error') {
353
+ setStatus('idle')
354
+ }
355
+ }, [status])
356
+
357
+ return {
358
+ status,
359
+ isLoading,
360
+ error,
361
+ messages,
362
+ report,
363
+ analysisResult,
364
+ suggestedQuestions,
365
+ totalCost,
366
+ analyzeWallet,
367
+ chat,
368
+ reset,
369
+ clearError,
370
+ }
371
+ }
@@ -1,6 +1,6 @@
1
1
  import { useState, useCallback } from 'react'
2
2
  import { useSIP } from './use-sip'
3
- import type { Quote, PrivacyLevel, CreateIntentParams, TrackedIntent, FulfillmentResult } from '@sip-protocol/types'
3
+ import type { Quote, PrivacyLevel, CreateIntentParams, TrackedIntent, FulfillmentResult, ChainId } from '@sip-protocol/types'
4
4
 
5
5
  /**
6
6
  * Status of the swap lifecycle
@@ -136,7 +136,7 @@ export function usePrivateSwap() {
136
136
  const intentParams: CreateIntentParams = {
137
137
  input: {
138
138
  asset: {
139
- chain: params.inputChain as any,
139
+ chain: params.inputChain as ChainId,
140
140
  symbol: params.inputToken,
141
141
  address: null,
142
142
  decimals: 9, // Default, should be configurable
@@ -145,7 +145,7 @@ export function usePrivateSwap() {
145
145
  },
146
146
  output: {
147
147
  asset: {
148
- chain: params.outputChain as any,
148
+ chain: params.outputChain as ChainId,
149
149
  symbol: params.outputToken,
150
150
  address: null,
151
151
  decimals: 18, // Default, should be configurable
@@ -192,7 +192,7 @@ export function usePrivateSwap() {
192
192
  const intentParams: CreateIntentParams = {
193
193
  input: {
194
194
  asset: {
195
- chain: params.input.chain as any,
195
+ chain: params.input.chain as ChainId,
196
196
  symbol: params.input.token,
197
197
  address: null,
198
198
  decimals: 9, // Default, should be configurable
@@ -201,7 +201,7 @@ export function usePrivateSwap() {
201
201
  },
202
202
  output: {
203
203
  asset: {
204
- chain: params.output.chain as any,
204
+ chain: params.output.chain as ChainId,
205
205
  symbol: params.output.token,
206
206
  address: null,
207
207
  decimals: 18, // Default, should be configurable