@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.
@@ -0,0 +1,302 @@
1
+ /**
2
+ * Ethereum Transaction Tracker
3
+ *
4
+ * Preset configuration for tracking Ethereum privacy transactions.
5
+ *
6
+ * @module components/ethereum/transaction-tracker
7
+ */
8
+
9
+ import React, { useMemo } from 'react'
10
+ import {
11
+ TransactionTracker,
12
+ useTransactionTracker,
13
+ type TransactionTrackerProps,
14
+ type PrivacyTransaction,
15
+ type TransactionStatus,
16
+ } from '../transaction-tracker'
17
+
18
+ /**
19
+ * Ethereum network configuration
20
+ */
21
+ export interface EthereumNetwork {
22
+ name: string
23
+ chainId: number
24
+ explorerUrl: string
25
+ /** Average block time in seconds */
26
+ blockTime: number
27
+ /** Confirmations required for finality */
28
+ requiredConfirmations: number
29
+ }
30
+
31
+ /**
32
+ * Predefined Ethereum networks
33
+ */
34
+ export const ETHEREUM_NETWORKS: Record<string, EthereumNetwork> = {
35
+ mainnet: {
36
+ name: 'Ethereum',
37
+ chainId: 1,
38
+ explorerUrl: 'https://etherscan.io',
39
+ blockTime: 12,
40
+ requiredConfirmations: 12,
41
+ },
42
+ sepolia: {
43
+ name: 'Sepolia',
44
+ chainId: 11155111,
45
+ explorerUrl: 'https://sepolia.etherscan.io',
46
+ blockTime: 12,
47
+ requiredConfirmations: 6,
48
+ },
49
+ goerli: {
50
+ name: 'Goerli',
51
+ chainId: 5,
52
+ explorerUrl: 'https://goerli.etherscan.io',
53
+ blockTime: 12,
54
+ requiredConfirmations: 6,
55
+ },
56
+ arbitrum: {
57
+ name: 'Arbitrum One',
58
+ chainId: 42161,
59
+ explorerUrl: 'https://arbiscan.io',
60
+ blockTime: 0.3,
61
+ requiredConfirmations: 1,
62
+ },
63
+ arbitrumSepolia: {
64
+ name: 'Arbitrum Sepolia',
65
+ chainId: 421614,
66
+ explorerUrl: 'https://sepolia.arbiscan.io',
67
+ blockTime: 0.3,
68
+ requiredConfirmations: 1,
69
+ },
70
+ optimism: {
71
+ name: 'Optimism',
72
+ chainId: 10,
73
+ explorerUrl: 'https://optimistic.etherscan.io',
74
+ blockTime: 2,
75
+ requiredConfirmations: 1,
76
+ },
77
+ optimismSepolia: {
78
+ name: 'Optimism Sepolia',
79
+ chainId: 11155420,
80
+ explorerUrl: 'https://sepolia-optimism.etherscan.io',
81
+ blockTime: 2,
82
+ requiredConfirmations: 1,
83
+ },
84
+ base: {
85
+ name: 'Base',
86
+ chainId: 8453,
87
+ explorerUrl: 'https://basescan.org',
88
+ blockTime: 2,
89
+ requiredConfirmations: 1,
90
+ },
91
+ baseSepolia: {
92
+ name: 'Base Sepolia',
93
+ chainId: 84532,
94
+ explorerUrl: 'https://sepolia.basescan.org',
95
+ blockTime: 2,
96
+ requiredConfirmations: 1,
97
+ },
98
+ polygon: {
99
+ name: 'Polygon',
100
+ chainId: 137,
101
+ explorerUrl: 'https://polygonscan.com',
102
+ blockTime: 2,
103
+ requiredConfirmations: 128,
104
+ },
105
+ polygonMumbai: {
106
+ name: 'Polygon Mumbai',
107
+ chainId: 80001,
108
+ explorerUrl: 'https://mumbai.polygonscan.com',
109
+ blockTime: 2,
110
+ requiredConfirmations: 32,
111
+ },
112
+ }
113
+
114
+ /**
115
+ * Get network by chain ID
116
+ */
117
+ export function getNetworkByChainId(chainId: number): EthereumNetwork | undefined {
118
+ return Object.values(ETHEREUM_NETWORKS).find((n) => n.chainId === chainId)
119
+ }
120
+
121
+ /**
122
+ * EthereumTransactionTracker props
123
+ */
124
+ export interface EthereumTransactionTrackerProps
125
+ extends Omit<TransactionTrackerProps, 'networkName' | 'explorerUrlTemplate'> {
126
+ /** Network name or chain ID */
127
+ network?: string | number
128
+ /** Custom network configuration */
129
+ customNetwork?: EthereumNetwork
130
+ }
131
+
132
+ /**
133
+ * EthereumTransactionTracker - Ethereum-configured transaction tracker
134
+ *
135
+ * @example Basic usage
136
+ * ```tsx
137
+ * import { EthereumTransactionTracker } from '@sip-protocol/react'
138
+ *
139
+ * function TransactionView({ tx }) {
140
+ * return (
141
+ * <EthereumTransactionTracker
142
+ * transaction={tx}
143
+ * network="mainnet"
144
+ * />
145
+ * )
146
+ * }
147
+ * ```
148
+ *
149
+ * @example With L2 network
150
+ * ```tsx
151
+ * <EthereumTransactionTracker
152
+ * transaction={tx}
153
+ * network="arbitrum"
154
+ * showPrivacyStatus
155
+ * />
156
+ * ```
157
+ */
158
+ export function EthereumTransactionTracker({
159
+ network = 'mainnet',
160
+ customNetwork,
161
+ transaction,
162
+ ...props
163
+ }: EthereumTransactionTrackerProps) {
164
+ // Resolve network configuration
165
+ const networkConfig = useMemo(() => {
166
+ if (customNetwork) return customNetwork
167
+
168
+ if (typeof network === 'number') {
169
+ return getNetworkByChainId(network) ?? ETHEREUM_NETWORKS.mainnet
170
+ }
171
+
172
+ return ETHEREUM_NETWORKS[network] ?? ETHEREUM_NETWORKS.mainnet
173
+ }, [network, customNetwork])
174
+
175
+ // Build explorer URL template
176
+ const explorerUrlTemplate = useMemo(() => {
177
+ return `${networkConfig.explorerUrl}/tx/{hash}`
178
+ }, [networkConfig])
179
+
180
+ // Adjust required confirmations if not set
181
+ const adjustedTransaction = useMemo(() => {
182
+ if (transaction.requiredConfirmations > 0) {
183
+ return transaction
184
+ }
185
+ return {
186
+ ...transaction,
187
+ requiredConfirmations: networkConfig.requiredConfirmations,
188
+ }
189
+ }, [transaction, networkConfig])
190
+
191
+ return (
192
+ <TransactionTracker
193
+ transaction={adjustedTransaction}
194
+ networkName={networkConfig.name}
195
+ explorerUrlTemplate={explorerUrlTemplate}
196
+ {...props}
197
+ />
198
+ )
199
+ }
200
+
201
+ /**
202
+ * Hook for managing Ethereum transaction tracking
203
+ *
204
+ * @example
205
+ * ```tsx
206
+ * const {
207
+ * transaction,
208
+ * updateTransaction,
209
+ * startPolling,
210
+ * stopPolling,
211
+ * estimatedTimeToFinality,
212
+ * } = useEthereumTransactionTracker(tx, {
213
+ * network: 'mainnet',
214
+ * pollingInterval: 3000,
215
+ * onConfirmed: (tx) => console.log('Confirmed!', tx),
216
+ * })
217
+ * ```
218
+ */
219
+ export function useEthereumTransactionTracker(
220
+ initialTransaction?: PrivacyTransaction,
221
+ options: {
222
+ network?: string | number
223
+ pollingInterval?: number
224
+ onStatusChange?: (status: TransactionStatus) => void
225
+ onConfirmed?: (tx: PrivacyTransaction) => void
226
+ onFinalized?: (tx: PrivacyTransaction) => void
227
+ onFailed?: (tx: PrivacyTransaction) => void
228
+ } = {}
229
+ ) {
230
+ const {
231
+ network = 'mainnet',
232
+ pollingInterval = 3000,
233
+ onStatusChange,
234
+ onConfirmed,
235
+ onFinalized,
236
+ onFailed,
237
+ } = options
238
+
239
+ // Get base hook
240
+ const baseHook = useTransactionTracker(initialTransaction, {
241
+ pollingInterval,
242
+ onStatusChange: (status) => {
243
+ onStatusChange?.(status)
244
+
245
+ // Check for specific status callbacks
246
+ if (baseHook.transaction) {
247
+ if (status === 'confirmed') {
248
+ onConfirmed?.(baseHook.transaction)
249
+ } else if (status === 'finalized') {
250
+ onFinalized?.(baseHook.transaction)
251
+ } else if (status === 'failed') {
252
+ onFailed?.(baseHook.transaction)
253
+ }
254
+ }
255
+ },
256
+ })
257
+
258
+ // Get network config
259
+ const networkConfig = useMemo(() => {
260
+ if (typeof network === 'number') {
261
+ return getNetworkByChainId(network) ?? ETHEREUM_NETWORKS.mainnet
262
+ }
263
+ return ETHEREUM_NETWORKS[network] ?? ETHEREUM_NETWORKS.mainnet
264
+ }, [network])
265
+
266
+ // Calculate estimated time to finality
267
+ const estimatedTimeToFinality = useMemo(() => {
268
+ if (!baseHook.transaction) return null
269
+ if (baseHook.isFinal) return 0
270
+
271
+ const remaining =
272
+ networkConfig.requiredConfirmations - baseHook.transaction.confirmations
273
+ return Math.max(remaining, 0) * networkConfig.blockTime
274
+ }, [baseHook.transaction, baseHook.isFinal, networkConfig])
275
+
276
+ // Format time
277
+ const formattedTimeToFinality = useMemo(() => {
278
+ if (estimatedTimeToFinality === null) return null
279
+ if (estimatedTimeToFinality === 0) return 'Finalized'
280
+
281
+ if (estimatedTimeToFinality < 60) {
282
+ return `~${Math.ceil(estimatedTimeToFinality)}s`
283
+ }
284
+ return `~${Math.ceil(estimatedTimeToFinality / 60)}m`
285
+ }, [estimatedTimeToFinality])
286
+
287
+ // Get explorer URL
288
+ const explorerUrl = useMemo(() => {
289
+ if (!baseHook.transaction) return null
290
+ return `${networkConfig.explorerUrl}/tx/${baseHook.transaction.hash}`
291
+ }, [baseHook.transaction, networkConfig])
292
+
293
+ return {
294
+ ...baseHook,
295
+ networkConfig,
296
+ estimatedTimeToFinality,
297
+ formattedTimeToFinality,
298
+ explorerUrl,
299
+ }
300
+ }
301
+
302
+ export default EthereumTransactionTracker
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Ethereum Viewing Key Manager
3
+ *
4
+ * Preset configuration for managing Ethereum viewing keys.
5
+ *
6
+ * @module components/ethereum/viewing-key-manager
7
+ */
8
+
9
+ import React, { useCallback } from 'react'
10
+ import {
11
+ ViewingKeyManager,
12
+ useViewingKeyManager,
13
+ type ViewingKeyManagerProps,
14
+ type ViewingKey,
15
+ type KeyExportFormat,
16
+ type KeyImportSource,
17
+ } from '../viewing-key-manager'
18
+
19
+ /**
20
+ * Ethereum-specific viewing key data
21
+ */
22
+ export interface EthereumViewingKey extends ViewingKey {
23
+ /** Chain ID the key is associated with */
24
+ chainId?: number
25
+ /** Stealth meta-address associated with this key */
26
+ stealthMetaAddress?: string
27
+ }
28
+
29
+ /**
30
+ * EthereumViewingKeyManager props
31
+ */
32
+ export interface EthereumViewingKeyManagerProps
33
+ extends Omit<ViewingKeyManagerProps, 'keys' | 'onGenerateKey' | 'onExportKey' | 'onImportKey' | 'onShareKey' | 'onRevokeKey'> {
34
+ /** List of Ethereum viewing keys */
35
+ keys: EthereumViewingKey[]
36
+ /** Callback to generate a new key */
37
+ onGenerateKey?: (label?: string, chainId?: number) => Promise<EthereumViewingKey>
38
+ /** Callback to export a key */
39
+ onExportKey?: (keyId: string, format: KeyExportFormat, password?: string) => Promise<string | Blob>
40
+ /** Callback to import a key */
41
+ onImportKey?: (source: KeyImportSource, data: string | File) => Promise<EthereumViewingKey>
42
+ /** Callback to share a key */
43
+ onShareKey?: (keyId: string, recipient: string) => Promise<void>
44
+ /** Callback to revoke a key */
45
+ onRevokeKey?: (keyId: string) => Promise<void>
46
+ /** Default chain ID for new keys */
47
+ defaultChainId?: number
48
+ }
49
+
50
+ /**
51
+ * EthereumViewingKeyManager - Ethereum-configured viewing key manager
52
+ *
53
+ * @example Basic usage
54
+ * ```tsx
55
+ * import { EthereumViewingKeyManager } from '@sip-protocol/react'
56
+ *
57
+ * function KeyManagement() {
58
+ * const [keys, setKeys] = useState<EthereumViewingKey[]>([])
59
+ *
60
+ * return (
61
+ * <EthereumViewingKeyManager
62
+ * keys={keys}
63
+ * onGenerateKey={async (label, chainId) => {
64
+ * const key = await generateEthereumViewingKey(label, chainId)
65
+ * setKeys([...keys, key])
66
+ * return key
67
+ * }}
68
+ * />
69
+ * )
70
+ * }
71
+ * ```
72
+ */
73
+ export function EthereumViewingKeyManager({
74
+ keys,
75
+ onGenerateKey,
76
+ onExportKey,
77
+ onImportKey,
78
+ onShareKey,
79
+ onRevokeKey,
80
+ defaultChainId = 1,
81
+ ...props
82
+ }: EthereumViewingKeyManagerProps) {
83
+ // Wrap the generate callback to include chain ID
84
+ const handleGenerateKey = useCallback(
85
+ async (label?: string) => {
86
+ if (!onGenerateKey) {
87
+ throw new Error('onGenerateKey not provided')
88
+ }
89
+ return onGenerateKey(label, defaultChainId)
90
+ },
91
+ [onGenerateKey, defaultChainId]
92
+ )
93
+
94
+ // Cast handlers to match base interface
95
+ const handleExportKey = useCallback(
96
+ async (keyId: string, format: KeyExportFormat, password?: string) => {
97
+ if (!onExportKey) {
98
+ throw new Error('onExportKey not provided')
99
+ }
100
+ return onExportKey(keyId, format, password)
101
+ },
102
+ [onExportKey]
103
+ )
104
+
105
+ const handleImportKey = useCallback(
106
+ async (source: KeyImportSource, data: string | File) => {
107
+ if (!onImportKey) {
108
+ throw new Error('onImportKey not provided')
109
+ }
110
+ return onImportKey(source, data)
111
+ },
112
+ [onImportKey]
113
+ )
114
+
115
+ return (
116
+ <ViewingKeyManager
117
+ keys={keys}
118
+ onGenerateKey={onGenerateKey ? handleGenerateKey : undefined}
119
+ onExportKey={onExportKey ? handleExportKey : undefined}
120
+ onImportKey={onImportKey ? handleImportKey : undefined}
121
+ onShareKey={onShareKey}
122
+ onRevokeKey={onRevokeKey}
123
+ {...props}
124
+ />
125
+ )
126
+ }
127
+
128
+ /**
129
+ * Hook for managing Ethereum viewing keys
130
+ *
131
+ * @example
132
+ * ```tsx
133
+ * const {
134
+ * keys,
135
+ * activeKeys,
136
+ * generateKey,
137
+ * exportKey,
138
+ * revokeKey,
139
+ * } = useEthereumViewingKey({
140
+ * chainId: 1,
141
+ * onKeyGenerated: (key) => console.log('Generated:', key),
142
+ * })
143
+ * ```
144
+ */
145
+ export function useEthereumViewingKey(options: {
146
+ chainId?: number
147
+ initialKeys?: EthereumViewingKey[]
148
+ onKeyGenerated?: (key: EthereumViewingKey) => void
149
+ onKeyRevoked?: (keyId: string) => void
150
+ } = {}) {
151
+ const { chainId = 1, initialKeys = [], onKeyGenerated, onKeyRevoked } = options
152
+
153
+ // Use base hook
154
+ const baseHook = useViewingKeyManager(initialKeys)
155
+
156
+ // Generate Ethereum-specific key (mock implementation - real would use SDK)
157
+ const generateKey = useCallback(
158
+ async (label?: string): Promise<EthereumViewingKey> => {
159
+ // Generate a mock key - in real usage, this would call the SDK
160
+ const id = `vk_${Date.now()}_${Math.random().toString(36).slice(2)}`
161
+ const publicKey = `0x${Array(64)
162
+ .fill(0)
163
+ .map(() => Math.floor(Math.random() * 16).toString(16))
164
+ .join('')}`
165
+ const privateKey = `0x${Array(64)
166
+ .fill(0)
167
+ .map(() => Math.floor(Math.random() * 16).toString(16))
168
+ .join('')}`
169
+
170
+ const key: EthereumViewingKey = {
171
+ id,
172
+ publicKey,
173
+ privateKey,
174
+ label: label || `Ethereum Key ${baseHook.keys.length + 1}`,
175
+ status: 'active',
176
+ createdAt: Date.now(),
177
+ usageHistory: [{ timestamp: Date.now(), action: 'created' }],
178
+ chainId,
179
+ }
180
+
181
+ baseHook.addKey(key)
182
+ onKeyGenerated?.(key)
183
+
184
+ return key
185
+ },
186
+ [baseHook, chainId, onKeyGenerated]
187
+ )
188
+
189
+ // Revoke key with callback
190
+ const revokeKey = useCallback(
191
+ (keyId: string) => {
192
+ baseHook.revokeKey(keyId)
193
+ onKeyRevoked?.(keyId)
194
+ },
195
+ [baseHook, onKeyRevoked]
196
+ )
197
+
198
+ // Get keys for specific chain
199
+ const keysForChain = useCallback(
200
+ (targetChainId: number) => {
201
+ return (baseHook.keys as EthereumViewingKey[]).filter(
202
+ (k) => k.chainId === targetChainId || !k.chainId
203
+ )
204
+ },
205
+ [baseHook.keys]
206
+ )
207
+
208
+ // Format viewing key for display
209
+ const formatViewingKeyAddress = useCallback((key: EthereumViewingKey) => {
210
+ const pk = key.publicKey
211
+ if (pk.length <= 16) return pk
212
+ return `${pk.slice(0, 10)}...${pk.slice(-8)}`
213
+ }, [])
214
+
215
+ return {
216
+ ...baseHook,
217
+ keys: baseHook.keys as EthereumViewingKey[],
218
+ activeKeys: baseHook.activeKeys as EthereumViewingKey[],
219
+ revokedKeys: baseHook.revokedKeys as EthereumViewingKey[],
220
+ generateKey,
221
+ revokeKey,
222
+ keysForChain,
223
+ formatViewingKeyAddress,
224
+ currentChainId: chainId,
225
+ }
226
+ }
227
+
228
+ export default EthereumViewingKeyManager
@@ -0,0 +1,107 @@
1
+ /**
2
+ * SIP Protocol React Components
3
+ *
4
+ * UI components for privacy-enabled transactions.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+
9
+ export {
10
+ PrivacyToggle,
11
+ usePrivacyToggle,
12
+ type PrivacyLevel,
13
+ type PrivacyToggleProps,
14
+ type GasEstimate,
15
+ type PrivacyLevelInfo,
16
+ } from './privacy-toggle'
17
+
18
+ export {
19
+ StealthAddressDisplay,
20
+ useStealthAddressDisplay,
21
+ isValidStealthAddress,
22
+ truncateAddress,
23
+ NEAR_NETWORKS,
24
+ type StealthAddressDisplayProps,
25
+ type OwnershipStatus,
26
+ type NetworkConfig,
27
+ } from './stealth-address-display'
28
+
29
+ export {
30
+ TransactionTracker,
31
+ useTransactionTracker,
32
+ type TransactionTrackerProps,
33
+ type TransactionStatus,
34
+ type PrivacyVerificationStatus,
35
+ type TransactionActionType,
36
+ type TransactionAction,
37
+ type PrivacyVerification,
38
+ type PrivacyTransaction,
39
+ } from './transaction-tracker'
40
+
41
+ export {
42
+ ViewingKeyManager,
43
+ useViewingKeyManager,
44
+ type ViewingKeyManagerProps,
45
+ type ViewingKey,
46
+ type ViewingKeyStatus,
47
+ type ViewingKeyUsage,
48
+ type KeyExportFormat,
49
+ type KeyImportSource,
50
+ } from './viewing-key-manager'
51
+
52
+ // Ethereum-specific components
53
+ export {
54
+ EthereumPrivacyToggle,
55
+ useEthereumPrivacyToggle,
56
+ type EthereumPrivacyToggleProps,
57
+ type EthereumPrivacyLevel,
58
+ type EthereumNetworkId,
59
+ type EthereumGasEstimate,
60
+ type EthereumPrivacyLevelInfo,
61
+ type NetworkGasConfig,
62
+ } from './ethereum/privacy-toggle'
63
+
64
+ export {
65
+ EthereumTransactionTracker,
66
+ useEthereumTransactionTracker,
67
+ ETHEREUM_NETWORKS,
68
+ getNetworkByChainId,
69
+ type EthereumTransactionTrackerProps,
70
+ type EthereumNetwork,
71
+ } from './ethereum/transaction-tracker'
72
+
73
+ export {
74
+ EthereumViewingKeyManager,
75
+ useEthereumViewingKey,
76
+ type EthereumViewingKeyManagerProps,
77
+ type EthereumViewingKey,
78
+ } from './ethereum/viewing-key-manager'
79
+
80
+ export {
81
+ EthereumStealthAddressDisplay,
82
+ useEthereumStealthAddressDisplay,
83
+ ETHEREUM_STEALTH_NETWORKS,
84
+ isValidEthereumAddress,
85
+ isValidEthereumStealthAddress,
86
+ isValidEphemeralPublicKey,
87
+ truncateEthereumAddress,
88
+ type EthereumStealthAddressDisplayProps,
89
+ type EthereumOwnershipStatus,
90
+ type EthereumStealthNetworkId,
91
+ type EthereumStealthNetworkConfig,
92
+ } from './ethereum/stealth-address-display'
93
+
94
+ export {
95
+ TransactionHistory,
96
+ useTransactionHistory as useEthereumTransactionHistory,
97
+ type TransactionHistoryProps,
98
+ type PrivacyTransactionHistoryItem,
99
+ type TransactionHistoryFilter,
100
+ type TransactionHistorySort,
101
+ } from './ethereum/transaction-history'
102
+
103
+ // NEAR Transaction History (M17-NEAR-20)
104
+ export {
105
+ TransactionHistoryView as NEARTransactionHistoryView,
106
+ type TransactionHistoryViewProps as NEARTransactionHistoryViewProps,
107
+ } from './transaction-history'