@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.
- package/README.md +54 -14
- package/dist/index.d.mts +1224 -6
- package/dist/index.d.ts +1224 -6
- package/dist/index.js +5783 -10
- package/dist/index.mjs +5777 -9
- package/package.json +9 -8
- package/src/components/ethereum/index.ts +55 -0
- package/src/components/ethereum/privacy-toggle.tsx +822 -0
- package/src/components/ethereum/stealth-address-display.tsx +1050 -0
- package/src/components/ethereum/transaction-history.tsx +1187 -0
- package/src/components/ethereum/transaction-tracker.tsx +302 -0
- package/src/components/ethereum/viewing-key-manager.tsx +228 -0
- package/src/components/index.ts +107 -0
- package/src/components/privacy-toggle.tsx +548 -0
- package/src/components/stealth-address-display.tsx +770 -0
- package/src/components/transaction-history.tsx +651 -0
- package/src/components/transaction-tracker.tsx +1079 -0
- package/src/components/viewing-key-manager.tsx +1576 -0
- package/src/hooks/index.ts +61 -0
- package/src/hooks/use-privacy-advisor.ts +371 -0
- package/src/hooks/use-private-swap.ts +5 -5
- package/src/hooks/use-proof-composition.ts +654 -0
- package/src/hooks/use-scan-payments.ts +504 -0
- package/src/hooks/use-stealth-address.ts +23 -7
- package/src/hooks/use-stealth-transfer.ts +284 -0
- package/src/hooks/use-transaction-history.ts +435 -0
- package/src/index.ts +75 -0
|
@@ -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'
|