@sip-protocol/sdk 0.5.0 → 0.6.0
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/LICENSE +21 -0
- package/dist/TransportWebUSB-TQ7WZ4LE.mjs +3098 -0
- package/dist/browser.d.mts +1 -1
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +3216 -35
- package/dist/browser.mjs +2 -1
- package/dist/chunk-KBS3OMSZ.mjs +14737 -0
- package/dist/chunk-TK3FWQNC.mjs +14737 -0
- package/dist/chunk-UJCSKKID.mjs +30 -0
- package/dist/index-05W_S8A7.d.mts +9237 -0
- package/dist/index-C5ehlFhR.d.mts +9443 -0
- package/dist/index-CNzhx-WH.d.mts +9316 -0
- package/dist/index-CqSppS4i.d.ts +9237 -0
- package/dist/index-DBa_jiZF.d.mts +9606 -0
- package/dist/index-DLNdSQFQ.d.ts +9316 -0
- package/dist/index-Ink8HnKW.d.ts +9606 -0
- package/dist/index-h7B23m5b.d.ts +9443 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3209 -28
- package/dist/index.mjs +2 -1
- package/dist/proofs/noir.mjs +1 -0
- package/package.json +15 -15
- package/src/crypto.ts +79 -9
- package/src/intent.ts +82 -4
- package/src/privacy.ts +88 -2
- package/src/sip.ts +324 -25
- package/src/stealth.ts +120 -9
- package/src/wallet/hardware/ledger.ts +1 -2
package/src/sip.ts
CHANGED
|
@@ -32,50 +32,145 @@ import { isValidChainId } from './validation'
|
|
|
32
32
|
import { NEARIntentsAdapter, type NEARIntentsAdapterConfig, type SwapRequest } from './adapters'
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
|
-
* SIP SDK
|
|
35
|
+
* Configuration options for the SIP SDK client
|
|
36
|
+
*
|
|
37
|
+
* Controls network selection, privacy defaults, proof generation, and settlement backend.
|
|
38
|
+
*
|
|
39
|
+
* @example Basic configuration
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const sip = new SIP({
|
|
42
|
+
* network: 'testnet',
|
|
43
|
+
* defaultPrivacy: PrivacyLevel.SHIELDED
|
|
44
|
+
* })
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* @example Production configuration with NEAR Intents
|
|
48
|
+
* ```typescript
|
|
49
|
+
* const sip = new SIP({
|
|
50
|
+
* network: 'mainnet',
|
|
51
|
+
* mode: 'production',
|
|
52
|
+
* proofProvider: new MockProofProvider(),
|
|
53
|
+
* intentsAdapter: {
|
|
54
|
+
* jwtToken: process.env.NEAR_INTENTS_JWT
|
|
55
|
+
* }
|
|
56
|
+
* })
|
|
57
|
+
* ```
|
|
36
58
|
*/
|
|
37
59
|
export interface SIPConfig {
|
|
38
|
-
/**
|
|
60
|
+
/**
|
|
61
|
+
* Network to operate on
|
|
62
|
+
*
|
|
63
|
+
* - `'mainnet'`: Production network with real assets
|
|
64
|
+
* - `'testnet'`: Test network for development
|
|
65
|
+
*/
|
|
39
66
|
network: 'mainnet' | 'testnet'
|
|
67
|
+
|
|
40
68
|
/**
|
|
41
|
-
*
|
|
69
|
+
* Operating mode for quote fetching and execution
|
|
70
|
+
*
|
|
71
|
+
* - `'demo'`: Returns mock quotes for testing (default)
|
|
72
|
+
* - `'production'`: Uses real NEAR Intents 1Click API
|
|
73
|
+
*
|
|
42
74
|
* @default 'demo'
|
|
43
75
|
*/
|
|
44
76
|
mode?: 'demo' | 'production'
|
|
45
|
-
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Default privacy level for new intents
|
|
80
|
+
*
|
|
81
|
+
* Can be overridden per intent. See {@link PrivacyLevel} for options.
|
|
82
|
+
*
|
|
83
|
+
* @default PrivacyLevel.SHIELDED
|
|
84
|
+
*/
|
|
46
85
|
defaultPrivacy?: PrivacyLevel
|
|
47
|
-
|
|
48
|
-
rpcEndpoints?: Partial<Record<ChainId, string>>
|
|
86
|
+
|
|
49
87
|
/**
|
|
50
|
-
*
|
|
88
|
+
* Custom RPC endpoints for blockchain connections
|
|
51
89
|
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
90
|
+
* Maps chain IDs to RPC URLs. Used for direct blockchain interactions
|
|
91
|
+
* when not using settlement adapters.
|
|
54
92
|
*
|
|
55
93
|
* @example
|
|
56
94
|
* ```typescript
|
|
95
|
+
* {
|
|
96
|
+
* rpcEndpoints: {
|
|
97
|
+
* ethereum: 'https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY',
|
|
98
|
+
* solana: 'https://api.mainnet-beta.solana.com'
|
|
99
|
+
* }
|
|
100
|
+
* }
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
rpcEndpoints?: Partial<Record<ChainId, string>>
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Proof provider for zero-knowledge proof generation
|
|
107
|
+
*
|
|
108
|
+
* Required for SHIELDED and COMPLIANT privacy modes. If not provided,
|
|
109
|
+
* intents will be created without proofs (must be attached later).
|
|
110
|
+
*
|
|
111
|
+
* **Available providers:**
|
|
112
|
+
* - {@link MockProofProvider}: For testing and development
|
|
113
|
+
* - `NoirProofProvider`: For production (import from '@sip-protocol/sdk/proofs/noir')
|
|
114
|
+
* - `BrowserNoirProvider`: For browser environments (import from '@sip-protocol/sdk/browser')
|
|
115
|
+
*
|
|
116
|
+
* @example Testing with mock proofs
|
|
117
|
+
* ```typescript
|
|
57
118
|
* import { MockProofProvider } from '@sip-protocol/sdk'
|
|
58
119
|
*
|
|
59
120
|
* const sip = new SIP({
|
|
60
121
|
* network: 'testnet',
|
|
61
|
-
* proofProvider: new MockProofProvider()
|
|
122
|
+
* proofProvider: new MockProofProvider()
|
|
123
|
+
* })
|
|
124
|
+
* ```
|
|
125
|
+
*
|
|
126
|
+
* @example Production with Noir proofs (Node.js)
|
|
127
|
+
* ```typescript
|
|
128
|
+
* import { NoirProofProvider } from '@sip-protocol/sdk/proofs/noir'
|
|
129
|
+
*
|
|
130
|
+
* const provider = new NoirProofProvider()
|
|
131
|
+
* await provider.initialize()
|
|
132
|
+
*
|
|
133
|
+
* const sip = new SIP({
|
|
134
|
+
* network: 'mainnet',
|
|
135
|
+
* proofProvider: provider
|
|
62
136
|
* })
|
|
63
137
|
* ```
|
|
64
138
|
*/
|
|
65
139
|
proofProvider?: ProofProvider
|
|
140
|
+
|
|
66
141
|
/**
|
|
67
|
-
* NEAR Intents adapter
|
|
142
|
+
* NEAR Intents adapter for production mode
|
|
68
143
|
*
|
|
69
|
-
* Required
|
|
144
|
+
* Required when `mode: 'production'`. Provides connection to the 1Click API
|
|
145
|
+
* for real cross-chain swaps via NEAR Intents.
|
|
70
146
|
*
|
|
71
|
-
*
|
|
147
|
+
* Can be either:
|
|
148
|
+
* - Configuration object ({@link NEARIntentsAdapterConfig})
|
|
149
|
+
* - Pre-configured adapter instance ({@link NEARIntentsAdapter})
|
|
150
|
+
*
|
|
151
|
+
* @example With JWT token
|
|
72
152
|
* ```typescript
|
|
73
153
|
* const sip = new SIP({
|
|
74
154
|
* network: 'mainnet',
|
|
75
155
|
* mode: 'production',
|
|
76
156
|
* intentsAdapter: {
|
|
77
|
-
* jwtToken: process.env.NEAR_INTENTS_JWT
|
|
78
|
-
* }
|
|
157
|
+
* jwtToken: process.env.NEAR_INTENTS_JWT
|
|
158
|
+
* }
|
|
159
|
+
* })
|
|
160
|
+
* ```
|
|
161
|
+
*
|
|
162
|
+
* @example With pre-configured adapter
|
|
163
|
+
* ```typescript
|
|
164
|
+
* import { createNEARIntentsAdapter } from '@sip-protocol/sdk'
|
|
165
|
+
*
|
|
166
|
+
* const adapter = createNEARIntentsAdapter({
|
|
167
|
+
* jwtToken: process.env.NEAR_INTENTS_JWT
|
|
168
|
+
* })
|
|
169
|
+
*
|
|
170
|
+
* const sip = new SIP({
|
|
171
|
+
* network: 'mainnet',
|
|
172
|
+
* mode: 'production',
|
|
173
|
+
* intentsAdapter: adapter
|
|
79
174
|
* })
|
|
80
175
|
* ```
|
|
81
176
|
*/
|
|
@@ -83,33 +178,212 @@ export interface SIPConfig {
|
|
|
83
178
|
}
|
|
84
179
|
|
|
85
180
|
/**
|
|
86
|
-
* Wallet adapter interface
|
|
181
|
+
* Wallet adapter interface for blockchain interactions
|
|
182
|
+
*
|
|
183
|
+
* Provides a unified interface for signing messages and transactions
|
|
184
|
+
* across different blockchain wallets (Ethereum, Solana, etc.).
|
|
185
|
+
*
|
|
186
|
+
* @example Implementing a wallet adapter
|
|
187
|
+
* ```typescript
|
|
188
|
+
* class MyWalletAdapter implements WalletAdapter {
|
|
189
|
+
* chain = 'ethereum' as const
|
|
190
|
+
* address = '0x...'
|
|
191
|
+
*
|
|
192
|
+
* async signMessage(message: string): Promise<string> {
|
|
193
|
+
* return await wallet.signMessage(message)
|
|
194
|
+
* }
|
|
195
|
+
*
|
|
196
|
+
* async signTransaction(tx: unknown): Promise<unknown> {
|
|
197
|
+
* return await wallet.signTransaction(tx)
|
|
198
|
+
* }
|
|
199
|
+
* }
|
|
200
|
+
* ```
|
|
87
201
|
*/
|
|
88
202
|
export interface WalletAdapter {
|
|
89
|
-
/**
|
|
203
|
+
/**
|
|
204
|
+
* Blockchain network this wallet is connected to
|
|
205
|
+
*
|
|
206
|
+
* Must match one of the supported {@link ChainId} values.
|
|
207
|
+
*/
|
|
90
208
|
chain: ChainId
|
|
91
|
-
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Wallet address on the connected chain
|
|
212
|
+
*
|
|
213
|
+
* Format depends on the chain:
|
|
214
|
+
* - Ethereum: `0x...` (checksummed)
|
|
215
|
+
* - Solana: Base58-encoded public key
|
|
216
|
+
* - NEAR: Account ID or implicit address
|
|
217
|
+
*/
|
|
92
218
|
address: string
|
|
93
|
-
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Sign a message with the wallet's private key
|
|
222
|
+
*
|
|
223
|
+
* @param message - UTF-8 string to sign
|
|
224
|
+
* @returns Signature as hex string or base58 (chain-dependent)
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```typescript
|
|
228
|
+
* const signature = await wallet.signMessage('Hello SIP!')
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
94
231
|
signMessage(message: string): Promise<string>
|
|
95
|
-
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Sign a transaction without broadcasting
|
|
235
|
+
*
|
|
236
|
+
* @param tx - Chain-specific transaction object
|
|
237
|
+
* @returns Signed transaction ready for broadcast
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* ```typescript
|
|
241
|
+
* const signedTx = await wallet.signTransaction(tx)
|
|
242
|
+
* ```
|
|
243
|
+
*/
|
|
96
244
|
signTransaction(tx: unknown): Promise<unknown>
|
|
97
|
-
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Sign and broadcast a transaction (optional)
|
|
248
|
+
*
|
|
249
|
+
* If implemented, allows the wallet to handle both signing and sending.
|
|
250
|
+
* If not implemented, caller must broadcast the signed transaction separately.
|
|
251
|
+
*
|
|
252
|
+
* @param tx - Chain-specific transaction object
|
|
253
|
+
* @returns Transaction hash after broadcast
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* ```typescript
|
|
257
|
+
* if (wallet.sendTransaction) {
|
|
258
|
+
* const txHash = await wallet.sendTransaction(tx)
|
|
259
|
+
* }
|
|
260
|
+
* ```
|
|
261
|
+
*/
|
|
98
262
|
sendTransaction?(tx: unknown): Promise<string>
|
|
99
263
|
}
|
|
100
264
|
|
|
101
265
|
/**
|
|
102
|
-
* Extended quote with
|
|
266
|
+
* Extended quote with production-specific metadata
|
|
267
|
+
*
|
|
268
|
+
* In production mode, quotes include deposit addresses and raw API responses
|
|
269
|
+
* from the NEAR 1Click API for advanced use cases.
|
|
103
270
|
*/
|
|
104
271
|
export interface ProductionQuote extends Quote {
|
|
105
|
-
/**
|
|
272
|
+
/**
|
|
273
|
+
* Deposit address for input tokens
|
|
274
|
+
*
|
|
275
|
+
* When using NEAR Intents in production mode, users deposit funds to this
|
|
276
|
+
* address to initiate the swap.
|
|
277
|
+
*
|
|
278
|
+
* Only present in production mode quotes.
|
|
279
|
+
*/
|
|
106
280
|
depositAddress?: string
|
|
107
|
-
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Raw response from NEAR 1Click API
|
|
284
|
+
*
|
|
285
|
+
* Contains the complete quote data from the settlement backend.
|
|
286
|
+
* Useful for debugging or accessing provider-specific metadata.
|
|
287
|
+
*
|
|
288
|
+
* Only present in production mode quotes.
|
|
289
|
+
*/
|
|
108
290
|
rawQuote?: OneClickQuoteResponse
|
|
109
291
|
}
|
|
110
292
|
|
|
111
293
|
/**
|
|
112
|
-
* Main SIP SDK
|
|
294
|
+
* Main SIP SDK client for privacy-preserving cross-chain transactions
|
|
295
|
+
*
|
|
296
|
+
* The SIP class is the primary interface for interacting with the Shielded Intents Protocol.
|
|
297
|
+
* It provides methods for:
|
|
298
|
+
*
|
|
299
|
+
* - Creating shielded intents with privacy guarantees
|
|
300
|
+
* - Fetching quotes from solvers/market makers
|
|
301
|
+
* - Executing cross-chain swaps via settlement backends
|
|
302
|
+
* - Managing stealth addresses and viewing keys
|
|
303
|
+
* - Generating zero-knowledge proofs
|
|
304
|
+
*
|
|
305
|
+
* **Key Concepts:**
|
|
306
|
+
*
|
|
307
|
+
* - **Intent**: A declaration of desired output (e.g., "I want 95+ ZEC on Zcash")
|
|
308
|
+
* - **Privacy Levels**: transparent (public), shielded (private), compliant (private + auditable)
|
|
309
|
+
* - **Stealth Address**: One-time recipient address for unlinkable transactions
|
|
310
|
+
* - **Commitment**: Cryptographic hiding of amounts using Pedersen commitments
|
|
311
|
+
* - **Viewing Key**: Selective disclosure key for compliance/auditing
|
|
312
|
+
*
|
|
313
|
+
* @example Basic usage (demo mode)
|
|
314
|
+
* ```typescript
|
|
315
|
+
* import { SIP, PrivacyLevel } from '@sip-protocol/sdk'
|
|
316
|
+
*
|
|
317
|
+
* // Initialize client
|
|
318
|
+
* const sip = new SIP({ network: 'testnet' })
|
|
319
|
+
*
|
|
320
|
+
* // Create a shielded intent
|
|
321
|
+
* const intent = await sip.createIntent({
|
|
322
|
+
* input: {
|
|
323
|
+
* asset: { chain: 'solana', symbol: 'SOL', address: null, decimals: 9 },
|
|
324
|
+
* amount: 10n * 10n**9n, // 10 SOL
|
|
325
|
+
* },
|
|
326
|
+
* output: {
|
|
327
|
+
* asset: { chain: 'ethereum', symbol: 'ETH', address: null, decimals: 18 },
|
|
328
|
+
* minAmount: 0n, // Accept any amount
|
|
329
|
+
* maxSlippage: 0.01, // 1%
|
|
330
|
+
* },
|
|
331
|
+
* privacy: PrivacyLevel.SHIELDED,
|
|
332
|
+
* })
|
|
333
|
+
*
|
|
334
|
+
* // Get quotes from solvers
|
|
335
|
+
* const quotes = await sip.getQuotes(intent)
|
|
336
|
+
*
|
|
337
|
+
* // Execute with best quote
|
|
338
|
+
* const result = await sip.execute(intent, quotes[0])
|
|
339
|
+
* console.log('Swap completed:', result.txHash)
|
|
340
|
+
* ```
|
|
341
|
+
*
|
|
342
|
+
* @example Production mode with NEAR Intents
|
|
343
|
+
* ```typescript
|
|
344
|
+
* import { SIP, PrivacyLevel, MockProofProvider } from '@sip-protocol/sdk'
|
|
345
|
+
*
|
|
346
|
+
* // Initialize with production backend
|
|
347
|
+
* const sip = new SIP({
|
|
348
|
+
* network: 'mainnet',
|
|
349
|
+
* mode: 'production',
|
|
350
|
+
* proofProvider: new MockProofProvider(), // Use NoirProofProvider in prod
|
|
351
|
+
* intentsAdapter: {
|
|
352
|
+
* jwtToken: process.env.NEAR_INTENTS_JWT,
|
|
353
|
+
* },
|
|
354
|
+
* })
|
|
355
|
+
*
|
|
356
|
+
* // Connect wallet
|
|
357
|
+
* sip.connect(myWalletAdapter)
|
|
358
|
+
*
|
|
359
|
+
* // Generate stealth keys for receiving
|
|
360
|
+
* const stealthMetaAddress = sip.generateStealthKeys('ethereum', 'My Privacy Wallet')
|
|
361
|
+
*
|
|
362
|
+
* // Create intent with stealth recipient
|
|
363
|
+
* const intent = await sip.createIntent({
|
|
364
|
+
* input: { asset: { chain: 'near', symbol: 'NEAR', address: null, decimals: 24 }, amount: 100n },
|
|
365
|
+
* output: { asset: { chain: 'zcash', symbol: 'ZEC', address: null, decimals: 8 }, minAmount: 0n, maxSlippage: 0.01 },
|
|
366
|
+
* privacy: PrivacyLevel.SHIELDED,
|
|
367
|
+
* recipientMetaAddress: sip.getStealthAddress(),
|
|
368
|
+
* })
|
|
369
|
+
*
|
|
370
|
+
* // Get real quotes
|
|
371
|
+
* const quotes = await sip.getQuotes(intent)
|
|
372
|
+
*
|
|
373
|
+
* // Execute with deposit callback
|
|
374
|
+
* const result = await sip.execute(intent, quotes[0], {
|
|
375
|
+
* onDepositRequired: async (depositAddr, amount) => {
|
|
376
|
+
* console.log(`Deposit ${amount} to ${depositAddr}`)
|
|
377
|
+
* const tx = await wallet.transfer(depositAddr, amount)
|
|
378
|
+
* return tx.hash
|
|
379
|
+
* },
|
|
380
|
+
* onStatusUpdate: (status) => console.log('Status:', status),
|
|
381
|
+
* })
|
|
382
|
+
* ```
|
|
383
|
+
*
|
|
384
|
+
* @see {@link SIPConfig} for configuration options
|
|
385
|
+
* @see {@link createShieldedIntent} for intent creation
|
|
386
|
+
* @see {@link PrivacyLevel} for privacy modes
|
|
113
387
|
*/
|
|
114
388
|
export class SIP {
|
|
115
389
|
private config: SIPConfig & { mode: 'demo' | 'production' }
|
|
@@ -124,6 +398,31 @@ export class SIP {
|
|
|
124
398
|
/** Cache of pending swaps by intent ID */
|
|
125
399
|
private pendingSwaps: Map<string, { depositAddress: string; quote: OneClickQuoteResponse }> = new Map()
|
|
126
400
|
|
|
401
|
+
/**
|
|
402
|
+
* Create a new SIP SDK client
|
|
403
|
+
*
|
|
404
|
+
* @param config - Configuration options for the client
|
|
405
|
+
* @throws {ValidationError} If configuration is invalid
|
|
406
|
+
*
|
|
407
|
+
* @example Minimal configuration
|
|
408
|
+
* ```typescript
|
|
409
|
+
* const sip = new SIP({ network: 'testnet' })
|
|
410
|
+
* ```
|
|
411
|
+
*
|
|
412
|
+
* @example Full configuration
|
|
413
|
+
* ```typescript
|
|
414
|
+
* const sip = new SIP({
|
|
415
|
+
* network: 'mainnet',
|
|
416
|
+
* mode: 'production',
|
|
417
|
+
* defaultPrivacy: PrivacyLevel.COMPLIANT,
|
|
418
|
+
* proofProvider: await NoirProofProvider.create(),
|
|
419
|
+
* intentsAdapter: { jwtToken: process.env.JWT },
|
|
420
|
+
* rpcEndpoints: {
|
|
421
|
+
* ethereum: 'https://eth-mainnet.g.alchemy.com/v2/KEY',
|
|
422
|
+
* },
|
|
423
|
+
* })
|
|
424
|
+
* ```
|
|
425
|
+
*/
|
|
127
426
|
constructor(config: SIPConfig) {
|
|
128
427
|
// Validate config
|
|
129
428
|
if (!config || typeof config !== 'object') {
|
package/src/stealth.ts
CHANGED
|
@@ -36,12 +36,66 @@ import {
|
|
|
36
36
|
import { secureWipe, secureWipeAll } from './secure-memory'
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
|
-
* Generate a new stealth meta-address keypair
|
|
39
|
+
* Generate a new stealth meta-address keypair for receiving private payments
|
|
40
40
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
41
|
+
* Creates a reusable meta-address that senders can use to derive one-time stealth
|
|
42
|
+
* addresses. The recipient publishes the meta-address publicly, and senders generate
|
|
43
|
+
* unique payment addresses from it.
|
|
44
|
+
*
|
|
45
|
+
* **Security:** Private keys must be stored securely and never shared. The meta-address
|
|
46
|
+
* (containing only public keys) can be safely published.
|
|
47
|
+
*
|
|
48
|
+
* **Algorithm:** Uses secp256k1 elliptic curve (EIP-5564 style) for:
|
|
49
|
+
* - Ethereum, Polygon, Arbitrum, Optimism, Base, Bitcoin, Zcash
|
|
50
|
+
*
|
|
51
|
+
* For Solana/NEAR/Aptos/Sui chains, use {@link generateEd25519StealthMetaAddress} instead.
|
|
52
|
+
*
|
|
53
|
+
* @param chain - Target blockchain network (determines address format)
|
|
54
|
+
* @param label - Optional human-readable label for identification
|
|
55
|
+
* @returns Object containing:
|
|
56
|
+
* - `metaAddress`: Public keys to share with senders
|
|
57
|
+
* - `spendingPrivateKey`: Secret key for claiming funds (keep secure!)
|
|
58
|
+
* - `viewingPrivateKey`: Secret key for scanning incoming payments (keep secure!)
|
|
59
|
+
*
|
|
60
|
+
* @throws {ValidationError} If chain is invalid or not supported
|
|
61
|
+
*
|
|
62
|
+
* @example Generate stealth keys for Ethereum
|
|
63
|
+
* ```typescript
|
|
64
|
+
* import { generateStealthMetaAddress, encodeStealthMetaAddress } from '@sip-protocol/sdk'
|
|
65
|
+
*
|
|
66
|
+
* // Generate keys
|
|
67
|
+
* const { metaAddress, spendingPrivateKey, viewingPrivateKey } =
|
|
68
|
+
* generateStealthMetaAddress('ethereum', 'My Privacy Wallet')
|
|
69
|
+
*
|
|
70
|
+
* // Encode for sharing (QR code, website, etc.)
|
|
71
|
+
* const encoded = encodeStealthMetaAddress(metaAddress)
|
|
72
|
+
* console.log('Share this:', encoded)
|
|
73
|
+
* // Output: "sip:ethereum:0x02abc...123:0x03def...456"
|
|
74
|
+
*
|
|
75
|
+
* // Store private keys securely (e.g., encrypted keystore)
|
|
76
|
+
* secureStorage.save({
|
|
77
|
+
* spendingPrivateKey,
|
|
78
|
+
* viewingPrivateKey,
|
|
79
|
+
* })
|
|
80
|
+
* ```
|
|
81
|
+
*
|
|
82
|
+
* @example Multi-chain setup
|
|
83
|
+
* ```typescript
|
|
84
|
+
* // Generate different stealth keys for each chain
|
|
85
|
+
* const ethKeys = generateStealthMetaAddress('ethereum', 'ETH Privacy')
|
|
86
|
+
* const zkKeys = generateStealthMetaAddress('zcash', 'ZEC Privacy')
|
|
87
|
+
*
|
|
88
|
+
* // Publish meta-addresses
|
|
89
|
+
* publishToProfile({
|
|
90
|
+
* ethereum: encodeStealthMetaAddress(ethKeys.metaAddress),
|
|
91
|
+
* zcash: encodeStealthMetaAddress(zkKeys.metaAddress),
|
|
92
|
+
* })
|
|
93
|
+
* ```
|
|
94
|
+
*
|
|
95
|
+
* @see {@link generateStealthAddress} to generate payment addresses as a sender
|
|
96
|
+
* @see {@link encodeStealthMetaAddress} to encode for sharing
|
|
97
|
+
* @see {@link deriveStealthPrivateKey} to claim funds as a recipient
|
|
98
|
+
* @see {@link generateEd25519StealthMetaAddress} for Solana/NEAR chains
|
|
45
99
|
*/
|
|
46
100
|
export function generateStealthMetaAddress(
|
|
47
101
|
chain: ChainId,
|
|
@@ -125,11 +179,68 @@ function validateStealthMetaAddress(
|
|
|
125
179
|
}
|
|
126
180
|
|
|
127
181
|
/**
|
|
128
|
-
* Generate a one-time stealth address for a recipient
|
|
182
|
+
* Generate a one-time stealth address for sending funds to a recipient
|
|
129
183
|
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
184
|
+
* As a sender, use this function to create a unique, unlinkable payment address
|
|
185
|
+
* from the recipient's public meta-address. Each call generates a new address
|
|
186
|
+
* that only the recipient can link to their identity.
|
|
187
|
+
*
|
|
188
|
+
* **Privacy Properties:**
|
|
189
|
+
* - Address is unique per transaction (prevents on-chain linkability)
|
|
190
|
+
* - Only recipient can detect and claim payments
|
|
191
|
+
* - Third-party observers cannot link payments to the same recipient
|
|
192
|
+
* - View tag enables efficient payment scanning
|
|
193
|
+
*
|
|
194
|
+
* **Algorithm (EIP-5564 DKSAP):**
|
|
195
|
+
* 1. Generate ephemeral keypair (r, R = r*G)
|
|
196
|
+
* 2. Compute shared secret: S = r * P_spend
|
|
197
|
+
* 3. Derive stealth address: A = P_view + hash(S)*G
|
|
198
|
+
* 4. Publish (R, A) on-chain; keep r secret
|
|
199
|
+
*
|
|
200
|
+
* @param recipientMetaAddress - Recipient's public stealth meta-address
|
|
201
|
+
* @returns Object containing:
|
|
202
|
+
* - `stealthAddress`: One-time payment address to publish on-chain
|
|
203
|
+
* - `sharedSecret`: Secret for sender's records (optional, don't publish!)
|
|
204
|
+
*
|
|
205
|
+
* @throws {ValidationError} If meta-address is invalid or malformed
|
|
206
|
+
*
|
|
207
|
+
* @example Send shielded payment
|
|
208
|
+
* ```typescript
|
|
209
|
+
* import { generateStealthAddress, decodeStealthMetaAddress } from '@sip-protocol/sdk'
|
|
210
|
+
*
|
|
211
|
+
* // Recipient shares their meta-address (e.g., on website, profile)
|
|
212
|
+
* const recipientMetaAddr = 'sip:ethereum:0x02abc...123:0x03def...456'
|
|
213
|
+
*
|
|
214
|
+
* // Decode the meta-address
|
|
215
|
+
* const metaAddress = decodeStealthMetaAddress(recipientMetaAddr)
|
|
216
|
+
*
|
|
217
|
+
* // Generate one-time payment address
|
|
218
|
+
* const { stealthAddress } = generateStealthAddress(metaAddress)
|
|
219
|
+
*
|
|
220
|
+
* // Use the stealth address in your transaction
|
|
221
|
+
* await sendPayment({
|
|
222
|
+
* to: stealthAddress.address, // One-time address
|
|
223
|
+
* amount: '1000000000000000000', // 1 ETH
|
|
224
|
+
* ephemeralKey: stealthAddress.ephemeralPublicKey, // Publish for recipient
|
|
225
|
+
* viewTag: stealthAddress.viewTag, // For efficient scanning
|
|
226
|
+
* })
|
|
227
|
+
* ```
|
|
228
|
+
*
|
|
229
|
+
* @example Integrate with SIP intent
|
|
230
|
+
* ```typescript
|
|
231
|
+
* // In a shielded intent, the recipient stealth address is generated automatically
|
|
232
|
+
* const intent = await sip.createIntent({
|
|
233
|
+
* input: { asset: { chain: 'solana', symbol: 'SOL', address: null, decimals: 9 }, amount: 10n },
|
|
234
|
+
* output: { asset: { chain: 'ethereum', symbol: 'ETH', address: null, decimals: 18 }, minAmount: 0n, maxSlippage: 0.01 },
|
|
235
|
+
* privacy: PrivacyLevel.SHIELDED,
|
|
236
|
+
* recipientMetaAddress: 'sip:ethereum:0x02abc...123:0x03def...456',
|
|
237
|
+
* })
|
|
238
|
+
* // intent.recipientStealth contains the generated stealth address
|
|
239
|
+
* ```
|
|
240
|
+
*
|
|
241
|
+
* @see {@link generateStealthMetaAddress} to create meta-address as recipient
|
|
242
|
+
* @see {@link deriveStealthPrivateKey} for recipient to claim funds
|
|
243
|
+
* @see {@link checkStealthAddress} to scan for incoming payments
|
|
133
244
|
*/
|
|
134
245
|
export function generateStealthAddress(
|
|
135
246
|
recipientMetaAddress: StealthMetaAddress,
|
|
@@ -303,9 +303,8 @@ export class LedgerWalletAdapter extends BaseWalletAdapter {
|
|
|
303
303
|
*/
|
|
304
304
|
private async loadTransport(): Promise<TransportWebUSBType> {
|
|
305
305
|
try {
|
|
306
|
-
// @ts-expect-error - Dynamic import
|
|
307
306
|
const module = await import('@ledgerhq/hw-transport-webusb')
|
|
308
|
-
return module.default
|
|
307
|
+
return module.default as unknown as TransportWebUSBType
|
|
309
308
|
} catch {
|
|
310
309
|
throw new HardwareWalletError(
|
|
311
310
|
'Failed to load Ledger transport. Install @ledgerhq/hw-transport-webusb',
|