@sip-protocol/sdk 0.8.1 → 0.10.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.
Files changed (65) hide show
  1. package/LICENSE +21 -0
  2. package/dist/{TransportWebUSB-YQMAGJAJ.mjs → TransportWebUSB-2KITI5HD.mjs} +24 -12
  3. package/dist/browser.d.mts +4 -4
  4. package/dist/browser.d.ts +4 -4
  5. package/dist/browser.js +1358 -847
  6. package/dist/browser.mjs +13 -3
  7. package/dist/{chunk-64AYA5F5.mjs → chunk-G3TBBG2K.mjs} +221 -146
  8. package/dist/{chunk-4GRJ5MAW.mjs → chunk-KXETSSKP.mjs} +4 -0
  9. package/dist/{chunk-YWGJ77A2.mjs → chunk-PT2DNA7E.mjs} +335 -310
  10. package/dist/{constants-LHAAUC2T.mjs → constants-DCJYTIU3.mjs} +5 -1
  11. package/dist/{dist-2OGQ7FED.mjs → dist-PYEXZNFD.mjs} +609 -221
  12. package/dist/{index-DeE1ZzA4.d.mts → index-B1d8pihL.d.mts} +117 -33
  13. package/dist/{index-DXh2IGkz.d.ts → index-UQhQJZbM.d.ts} +117 -33
  14. package/dist/index.d.mts +3 -3
  15. package/dist/index.d.ts +3 -3
  16. package/dist/index.js +1348 -837
  17. package/dist/index.mjs +13 -3
  18. package/dist/{interface-Bf7w1PLW.d.mts → interface-CQi0-WfS.d.mts} +2 -2
  19. package/dist/{interface-Bf7w1PLW.d.ts → interface-CQi0-WfS.d.ts} +2 -2
  20. package/dist/{noir-kzbLVTei.d.mts → noir-CwPIyBLj.d.mts} +1 -1
  21. package/dist/{noir-kzbLVTei.d.ts → noir-CwPIyBLj.d.ts} +1 -1
  22. package/dist/proofs/halo2.d.mts +1 -1
  23. package/dist/proofs/halo2.d.ts +1 -1
  24. package/dist/proofs/kimchi.d.mts +1 -1
  25. package/dist/proofs/kimchi.d.ts +1 -1
  26. package/dist/proofs/noir.d.mts +1 -1
  27. package/dist/proofs/noir.d.ts +1 -1
  28. package/dist/{solana-U3MEGU7W.mjs → solana-ZWNIQTSU.mjs} +6 -6
  29. package/package.json +32 -32
  30. package/src/adapters/gelato-relay.ts +386 -0
  31. package/src/adapters/index.ts +28 -0
  32. package/src/adapters/oneinch.ts +126 -0
  33. package/src/chains/ethereum/constants.ts +33 -1
  34. package/src/chains/ethereum/index.ts +2 -1
  35. package/src/chains/ethereum/privacy-adapter.ts +44 -26
  36. package/src/chains/ethereum/stealth.ts +84 -30
  37. package/src/chains/ethereum/types.ts +4 -0
  38. package/src/chains/near/privacy-adapter.ts +8 -5
  39. package/src/chains/near/resolver.ts +22 -8
  40. package/src/chains/near/stealth.ts +9 -9
  41. package/src/chains/solana/constants.ts +13 -1
  42. package/src/chains/solana/ephemeral-keys.ts +3 -257
  43. package/src/chains/solana/index.ts +2 -3
  44. package/src/chains/solana/providers/helius-enhanced.ts +6 -6
  45. package/src/chains/solana/providers/webhook.ts +2 -2
  46. package/src/chains/solana/scan.ts +9 -8
  47. package/src/chains/solana/stealth-scanner.ts +3 -3
  48. package/src/chains/solana/types.ts +18 -4
  49. package/src/cosmos/ibc-stealth.ts +6 -6
  50. package/src/index.ts +6 -0
  51. package/src/move/aptos.ts +15 -9
  52. package/src/move/sui.ts +15 -9
  53. package/src/nft/private-nft.ts +10 -6
  54. package/src/privacy-backends/shadowwire.ts +13 -0
  55. package/src/stealth/ed25519.ts +173 -12
  56. package/src/stealth/index.ts +47 -4
  57. package/src/stealth/secp256k1.ts +144 -7
  58. package/src/stealth.ts +7 -0
  59. package/src/wallet/ethereum/privacy-adapter.ts +1 -1
  60. package/src/wallet/hardware/ledger-privacy.ts +2 -2
  61. package/src/wallet/near/adapter.ts +2 -2
  62. package/src/wallet/near/meteor-wallet.ts +2 -2
  63. package/src/wallet/near/my-near-wallet.ts +2 -2
  64. package/src/wallet/near/wallet-selector.ts +2 -2
  65. package/src/wallet/solana/privacy-adapter.ts +9 -9
@@ -0,0 +1,386 @@
1
+ /**
2
+ * Gelato Relay Adapter for SIP Protocol
3
+ *
4
+ * Enables gasless claim and withdrawal from stealth addresses via Gelato Relay.
5
+ * Recipients can claim funds without holding ETH for gas — critical for stealth
6
+ * addresses which are freshly generated and have zero balance.
7
+ *
8
+ * ## Two Modes
9
+ *
10
+ * - **sponsoredCall**: SIP pays gas from Gas Tank (requires API key)
11
+ * - **callWithSyncFee**: Fee deducted from withdrawal amount (requires SIPRelayer)
12
+ *
13
+ * ```
14
+ * ┌──────────────────────────────────────────────────────────┐
15
+ * │ GELATO RELAY + SIP PRIVACY FLOW │
16
+ * │ │
17
+ * │ Sponsored Mode: │
18
+ * │ 1. Recipient calls sponsoredClaim() with proof │
19
+ * │ 2. Gelato relays tx to SIPPrivacy.withdrawDeposit() │
20
+ * │ 3. SIP Gas Tank pays the gas fee │
21
+ * │ 4. Funds arrive at recipient stealth address │
22
+ * │ │
23
+ * │ SyncFee Mode: │
24
+ * │ 1. Recipient calls syncFeeClaim() with proof + maxFee │
25
+ * │ 2. Gelato relays tx to SIPRelayer contract │
26
+ * │ 3. SIPRelayer calls SIPPrivacy.withdrawDeposit() │
27
+ * │ 4. SIPRelayer deducts gas fee from withdrawn amount │
28
+ * │ 5. Remainder arrives at recipient stealth address │
29
+ * │ │
30
+ * │ Result: Zero-gas claims from stealth addresses │
31
+ * └──────────────────────────────────────────────────────────┘
32
+ * ```
33
+ *
34
+ * ## ABI Encoding
35
+ *
36
+ * Uses manual ABI encoding with @noble/hashes keccak256 for function selectors.
37
+ * No ethers.js or viem dependency required.
38
+ *
39
+ * @see https://docs.gelato.network/web3-services/relay
40
+ */
41
+
42
+ import { keccak_256 } from '@noble/hashes/sha3'
43
+ import { bytesToHex } from '@noble/hashes/utils'
44
+
45
+ // ═══════════════════════════════════════════
46
+ // Types
47
+ // ═══════════════════════════════════════════
48
+
49
+ export interface GelatoRelayConfig {
50
+ /** Gelato Gas Tank API key (required for sponsoredCall) */
51
+ apiKey?: string
52
+ /** Target chain ID (e.g. 11155111 for Sepolia) */
53
+ chainId: number
54
+ /** SIPPrivacy contract address */
55
+ sipPrivacyAddress: string
56
+ /** SIPRelayer contract address (required for callWithSyncFee) */
57
+ sipRelayerAddress?: string
58
+ }
59
+
60
+ export interface RelayClaimParams {
61
+ /** Deposit transfer ID */
62
+ transferId: bigint
63
+ /** Nullifier hash (bytes32 hex) */
64
+ nullifier: string
65
+ /** ZK proof (bytes hex) */
66
+ proof: string
67
+ /** Recipient address (20-byte hex) */
68
+ recipient: string
69
+ }
70
+
71
+ export interface SyncFeeClaimParams extends RelayClaimParams {
72
+ /** Token to pay Gelato fee in */
73
+ feeToken: string
74
+ /** Maximum fee willing to pay */
75
+ maxFee: bigint
76
+ /** ERC20 token address (omit or zero address for ETH) */
77
+ token?: string
78
+ }
79
+
80
+ export interface RelayResult {
81
+ /** Gelato task ID for tracking */
82
+ taskId: string
83
+ /** Which relay mode was used */
84
+ mode: 'sponsored' | 'syncFee'
85
+ }
86
+
87
+ export type TaskStatus =
88
+ | 'CheckPending'
89
+ | 'ExecPending'
90
+ | 'ExecSuccess'
91
+ | 'ExecReverted'
92
+ | 'Cancelled'
93
+
94
+ export interface TaskStatusResult {
95
+ /** Gelato task ID */
96
+ taskId: string
97
+ /** Current task state */
98
+ taskState: TaskStatus
99
+ /** Transaction hash (available after execution) */
100
+ transactionHash?: string
101
+ /** Block number (available after execution) */
102
+ blockNumber?: number
103
+ }
104
+
105
+ // ═══════════════════════════════════════════
106
+ // Constants
107
+ // ═══════════════════════════════════════════
108
+
109
+ const GELATO_RELAY_URL = 'https://relay.gelato.digital'
110
+ const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
111
+
112
+ // ═══════════════════════════════════════════
113
+ // ABI Encoding Helpers (no ethers/viem)
114
+ // ═══════════════════════════════════════════
115
+
116
+ /**
117
+ * Compute 4-byte function selector from Solidity signature.
118
+ * selector = keccak256(signature)[0:4]
119
+ */
120
+ export function functionSelector(signature: string): string {
121
+ const hash = keccak_256(new TextEncoder().encode(signature))
122
+ return '0x' + bytesToHex(hash).slice(0, 8)
123
+ }
124
+
125
+ /** Left-pad a bigint to 32 bytes (64 hex chars) */
126
+ function padUint256(value: bigint): string {
127
+ if (value < 0n) throw new Error(`uint256 cannot be negative: ${value}`)
128
+ if (value >= 2n ** 256n) throw new Error(`uint256 overflow: ${value}`)
129
+ return value.toString(16).padStart(64, '0')
130
+ }
131
+
132
+ /** Left-pad an address to 32 bytes (64 hex chars) */
133
+ function padAddress(addr: string): string {
134
+ const clean = addr.startsWith('0x') ? addr.slice(2) : addr
135
+ if (clean.length !== 40) {
136
+ throw new Error(`Invalid address length: expected 40 hex chars, got ${clean.length}`)
137
+ }
138
+ return clean.toLowerCase().padStart(64, '0')
139
+ }
140
+
141
+ /** Right-pad a bytes32 value to 32 bytes (64 hex chars) */
142
+ function padBytes32(value: string): string {
143
+ const clean = value.startsWith('0x') ? value.slice(2) : value
144
+ if (clean.length > 64) {
145
+ throw new Error(`bytes32 value too long: ${clean.length} hex chars (max 64)`)
146
+ }
147
+ return clean.padEnd(64, '0')
148
+ }
149
+
150
+ /**
151
+ * ABI-encode a dynamic `bytes` value.
152
+ * Returns: length (32 bytes) + data (padded to 32-byte boundary)
153
+ */
154
+ function encodeBytes(value: string): string {
155
+ const clean = value.startsWith('0x') ? value.slice(2) : value
156
+ if (clean.length % 2 !== 0) {
157
+ throw new Error(`bytes value must have even hex length, got ${clean.length}`)
158
+ }
159
+ const length = clean.length / 2
160
+ const paddedData = clean.length % 64 === 0
161
+ ? clean
162
+ : clean + '0'.repeat(64 - (clean.length % 64))
163
+ return padUint256(BigInt(length)) + paddedData
164
+ }
165
+
166
+ // ═══════════════════════════════════════════
167
+ // GelatoRelayAdapter
168
+ // ═══════════════════════════════════════════
169
+
170
+ export class GelatoRelayAdapter {
171
+ private config: GelatoRelayConfig
172
+
173
+ constructor(config: GelatoRelayConfig) {
174
+ if (!config.sipPrivacyAddress) {
175
+ throw new Error('sipPrivacyAddress is required')
176
+ }
177
+ if (!config.chainId) {
178
+ throw new Error('chainId is required')
179
+ }
180
+ this.config = config
181
+ }
182
+
183
+ /**
184
+ * Gasless withdrawal via sponsoredCall (SIP pays gas from Gas Tank).
185
+ * Calls SIPPrivacy.withdrawDeposit() directly.
186
+ */
187
+ async sponsoredClaim(params: RelayClaimParams): Promise<RelayResult> {
188
+ if (!this.config.apiKey) {
189
+ throw new Error('API key required for sponsoredCall')
190
+ }
191
+
192
+ const data = this.encodeWithdrawDeposit(params)
193
+
194
+ const response = await fetch(`${GELATO_RELAY_URL}/relays/v2/sponsored-call`, {
195
+ method: 'POST',
196
+ headers: { 'Content-Type': 'application/json' },
197
+ body: JSON.stringify({
198
+ chainId: this.config.chainId,
199
+ target: this.config.sipPrivacyAddress,
200
+ data,
201
+ sponsorApiKey: this.config.apiKey,
202
+ }),
203
+ })
204
+
205
+ if (!response.ok) {
206
+ const text = await response.text().catch(() => response.statusText)
207
+ throw new Error(`Gelato relay error: ${response.status} ${text}`)
208
+ }
209
+
210
+ const result = await response.json()
211
+ return { taskId: result.taskId, mode: 'sponsored' }
212
+ }
213
+
214
+ /**
215
+ * Gasless withdrawal via callWithSyncFee (fee deducted from withdrawn amount).
216
+ * Routes through SIPRelayer contract which handles fee deduction.
217
+ *
218
+ * - ETH withdrawals: calls relayedWithdrawETH()
219
+ * - ERC20 withdrawals: calls relayedWithdrawToken() (when params.token is set)
220
+ */
221
+ async syncFeeClaim(params: SyncFeeClaimParams): Promise<RelayResult> {
222
+ if (!this.config.sipRelayerAddress) {
223
+ throw new Error('SIPRelayer address required for callWithSyncFee')
224
+ }
225
+
226
+ const isToken = params.token && params.token !== ZERO_ADDRESS
227
+ const data = isToken
228
+ ? this.encodeRelayedWithdrawToken(params)
229
+ : this.encodeRelayedWithdrawETH(params)
230
+
231
+ const response = await fetch(`${GELATO_RELAY_URL}/relays/v2/call-with-sync-fee`, {
232
+ method: 'POST',
233
+ headers: { 'Content-Type': 'application/json' },
234
+ body: JSON.stringify({
235
+ chainId: this.config.chainId,
236
+ target: this.config.sipRelayerAddress,
237
+ data,
238
+ feeToken: params.feeToken,
239
+ isRelayContext: true,
240
+ }),
241
+ })
242
+
243
+ if (!response.ok) {
244
+ const text = await response.text().catch(() => response.statusText)
245
+ throw new Error(`Gelato relay error: ${response.status} ${text}`)
246
+ }
247
+
248
+ const result = await response.json()
249
+ return { taskId: result.taskId, mode: 'syncFee' }
250
+ }
251
+
252
+ /**
253
+ * Check relay task status.
254
+ * Poll this after submitting a relay request to track execution.
255
+ */
256
+ async getTaskStatus(taskId: string): Promise<TaskStatusResult> {
257
+ if (!taskId) {
258
+ throw new Error('taskId is required')
259
+ }
260
+ if (!/^[a-zA-Z0-9_-]+$/.test(taskId)) {
261
+ throw new Error(`Invalid taskId format: ${taskId}`)
262
+ }
263
+
264
+ const response = await fetch(`${GELATO_RELAY_URL}/tasks/status/${taskId}`)
265
+
266
+ if (!response.ok) {
267
+ throw new Error(`Gelato status error: ${response.status}`)
268
+ }
269
+
270
+ const result = await response.json()
271
+ return {
272
+ taskId: result.task.taskId,
273
+ taskState: result.task.taskState,
274
+ transactionHash: result.task.transactionHash,
275
+ blockNumber: result.task.blockNumber,
276
+ }
277
+ }
278
+
279
+ // ═══════════════════════════════════════════
280
+ // ABI Encoding (no ethers/viem dependency)
281
+ // ═══════════════════════════════════════════
282
+
283
+ /**
284
+ * Encode withdrawDeposit(uint256,bytes32,bytes,address)
285
+ *
286
+ * ABI layout:
287
+ * [selector 4B]
288
+ * [0x00] transferId — uint256
289
+ * [0x20] nullifier — bytes32
290
+ * [0x40] proof offset — uint256 (points to 0x80)
291
+ * [0x60] recipient — address
292
+ * [0x80] proof length — uint256
293
+ * [0xa0] proof data — bytes (padded)
294
+ */
295
+ private encodeWithdrawDeposit(params: RelayClaimParams): string {
296
+ const selector = functionSelector('withdrawDeposit(uint256,bytes32,bytes,address)')
297
+ const proofOffset = padUint256(128n) // 4 slots * 32 = 128
298
+
299
+ return selector
300
+ + padUint256(params.transferId)
301
+ + padBytes32(params.nullifier)
302
+ + proofOffset
303
+ + padAddress(params.recipient)
304
+ + encodeBytes(params.proof)
305
+ }
306
+
307
+ /**
308
+ * Encode relayedWithdrawETH(uint256,bytes32,bytes,address,uint256)
309
+ *
310
+ * ABI layout:
311
+ * [selector 4B]
312
+ * [0x00] transferId — uint256
313
+ * [0x20] nullifier — bytes32
314
+ * [0x40] proof offset — uint256 (points to 0xa0)
315
+ * [0x60] recipient — address
316
+ * [0x80] maxFee — uint256
317
+ * [0xa0] proof length — uint256
318
+ * [0xc0] proof data — bytes (padded)
319
+ */
320
+ private encodeRelayedWithdrawETH(params: SyncFeeClaimParams): string {
321
+ const selector = functionSelector('relayedWithdrawETH(uint256,bytes32,bytes,address,uint256)')
322
+ const proofOffset = padUint256(160n) // 5 slots * 32 = 160
323
+
324
+ return selector
325
+ + padUint256(params.transferId)
326
+ + padBytes32(params.nullifier)
327
+ + proofOffset
328
+ + padAddress(params.recipient)
329
+ + padUint256(params.maxFee)
330
+ + encodeBytes(params.proof)
331
+ }
332
+
333
+ /**
334
+ * Encode relayedWithdrawToken(uint256,bytes32,bytes,address,address,uint256)
335
+ *
336
+ * ABI layout:
337
+ * [selector 4B]
338
+ * [0x00] transferId — uint256
339
+ * [0x20] nullifier — bytes32
340
+ * [0x40] proof offset — uint256 (points to 0xc0)
341
+ * [0x60] recipient — address
342
+ * [0x80] token — address
343
+ * [0xa0] maxFee — uint256
344
+ * [0xc0] proof length — uint256
345
+ * [0xe0] proof data — bytes (padded)
346
+ */
347
+ private encodeRelayedWithdrawToken(params: SyncFeeClaimParams): string {
348
+ const selector = functionSelector('relayedWithdrawToken(uint256,bytes32,bytes,address,address,uint256)')
349
+ const proofOffset = padUint256(192n) // 6 slots * 32 = 192
350
+
351
+ return selector
352
+ + padUint256(params.transferId)
353
+ + padBytes32(params.nullifier)
354
+ + proofOffset
355
+ + padAddress(params.recipient)
356
+ + padAddress(params.token!)
357
+ + padUint256(params.maxFee)
358
+ + encodeBytes(params.proof)
359
+ }
360
+ }
361
+
362
+ /**
363
+ * Factory function for creating a GelatoRelayAdapter.
364
+ *
365
+ * @example
366
+ * ```typescript
367
+ * // Sponsored mode (SIP pays gas)
368
+ * const relay = createGelatoRelayAdapter({
369
+ * apiKey: 'gelato-api-key',
370
+ * chainId: 11155111,
371
+ * sipPrivacyAddress: '0x1FED...',
372
+ * })
373
+ * const result = await relay.sponsoredClaim({ transferId, nullifier, proof, recipient })
374
+ *
375
+ * // SyncFee mode (fee from withdrawal)
376
+ * const relay = createGelatoRelayAdapter({
377
+ * chainId: 11155111,
378
+ * sipPrivacyAddress: '0x1FED...',
379
+ * sipRelayerAddress: '0xABC...',
380
+ * })
381
+ * const result = await relay.syncFeeClaim({ transferId, nullifier, proof, recipient, feeToken, maxFee })
382
+ * ```
383
+ */
384
+ export function createGelatoRelayAdapter(config: GelatoRelayConfig): GelatoRelayAdapter {
385
+ return new GelatoRelayAdapter(config)
386
+ }
@@ -11,6 +11,9 @@
11
11
  * ### Solana DEX
12
12
  * - **JupiterAdapter** — Jupiter aggregator for private Solana swaps
13
13
  *
14
+ * ### EVM Relay
15
+ * - **GelatoRelayAdapter** — Gasless claims from stealth addresses via Gelato Relay
16
+ *
14
17
  * @example
15
18
  * ```typescript
16
19
  * import { JupiterAdapter, NEARIntentsAdapter } from '@sip-protocol/sdk'
@@ -58,3 +61,28 @@ export type {
58
61
  JupiterSwapResult,
59
62
  JupiterPrivateSwapResult,
60
63
  } from './jupiter'
64
+
65
+ // 1inch Aggregator (EVM)
66
+ export { OneInchAdapter } from './oneinch'
67
+
68
+ export type {
69
+ OneInchQuote,
70
+ OneInchSwapData,
71
+ OneInchSwapParams,
72
+ } from './oneinch'
73
+
74
+ // Gelato Relay (EVM gasless)
75
+ export {
76
+ GelatoRelayAdapter,
77
+ createGelatoRelayAdapter,
78
+ functionSelector,
79
+ } from './gelato-relay'
80
+
81
+ export type {
82
+ GelatoRelayConfig,
83
+ RelayClaimParams,
84
+ SyncFeeClaimParams,
85
+ RelayResult,
86
+ TaskStatus,
87
+ TaskStatusResult,
88
+ } from './gelato-relay'
@@ -0,0 +1,126 @@
1
+ /**
2
+ * 1inch Aggregator Adapter for SIP Protocol
3
+ *
4
+ * Generates swap calldata for privacy-preserving EVM swaps via 1inch aggregator.
5
+ * SIP adds stealth addresses as the swap recipient, breaking the on-chain identity link.
6
+ *
7
+ * ## Privacy Model
8
+ *
9
+ * 1inch swaps are routed through 200+ DEX pools for best price. SIP enhances privacy by:
10
+ * - Setting `destReceiver` to a stealth address (recipient unlinkable)
11
+ * - SIPSwapRouter validates calldata on-chain before forwarding to 1inch
12
+ *
13
+ * ```
14
+ * ┌──────────────────────────────────────────────────────────────┐
15
+ * │ 1INCH + SIP PRIVACY FLOW │
16
+ * │ │
17
+ * │ 1. SDK: Generate stealth address for output │
18
+ * │ 2. SDK: Call 1inch API (destReceiver = stealth) │
19
+ * │ 3. SDK: Submit calldata to SIPSwapRouter │
20
+ * │ 4. Contract: Validate calldata, deduct fee, forward │
21
+ * │ 5. 1inch Router → DEX pools → stealth address │
22
+ * │ │
23
+ * │ Result: Best-price swap, recipient unlinkable │
24
+ * └──────────────────────────────────────────────────────────────┘
25
+ * ```
26
+ *
27
+ * @see https://portal.1inch.dev
28
+ */
29
+
30
+ export interface OneInchQuote {
31
+ toAmount: string
32
+ estimatedGas: string
33
+ protocols: Array<{ name: string; part: number }>
34
+ }
35
+
36
+ export interface OneInchSwapData {
37
+ tx: {
38
+ to: string
39
+ data: string
40
+ value: string
41
+ gas: number
42
+ }
43
+ toAmount: string
44
+ }
45
+
46
+ export interface OneInchSwapParams {
47
+ src: string
48
+ dst: string
49
+ amount: string
50
+ from: string
51
+ destReceiver: string
52
+ slippage: number
53
+ disableEstimate?: boolean
54
+ }
55
+
56
+ const CHAIN_IDS: Record<string, number> = {
57
+ ethereum: 1,
58
+ arbitrum: 42161,
59
+ optimism: 10,
60
+ base: 8453,
61
+ polygon: 137,
62
+ }
63
+
64
+ const ONEINCH_ROUTER = '0x111111125421cA6dc452d289314280a0f8842A65'
65
+ const API_BASE = 'https://api.1inch.dev/swap/v6.0'
66
+
67
+ export class OneInchAdapter {
68
+ private apiKey: string
69
+ private chainId: number
70
+
71
+ constructor(apiKey: string, chain: string | number) {
72
+ this.apiKey = apiKey
73
+ this.chainId = typeof chain === 'number' ? chain : CHAIN_IDS[chain]
74
+ if (!this.chainId) throw new Error(`Unsupported chain: ${chain}`)
75
+ }
76
+
77
+ get routerAddress(): string {
78
+ return ONEINCH_ROUTER
79
+ }
80
+
81
+ async getQuote(params: {
82
+ src: string
83
+ dst: string
84
+ amount: string
85
+ }): Promise<OneInchQuote> {
86
+ const url = new URL(`${API_BASE}/${this.chainId}/quote`)
87
+ url.searchParams.set('src', params.src)
88
+ url.searchParams.set('dst', params.dst)
89
+ url.searchParams.set('amount', params.amount)
90
+
91
+ const response = await fetch(url.toString(), {
92
+ headers: { Authorization: `Bearer ${this.apiKey}` },
93
+ })
94
+
95
+ if (!response.ok) {
96
+ throw new Error(`1inch API error: ${response.status} ${response.statusText}`)
97
+ }
98
+
99
+ return response.json()
100
+ }
101
+
102
+ async getSwapCalldata(params: OneInchSwapParams): Promise<OneInchSwapData> {
103
+ const url = new URL(`${API_BASE}/${this.chainId}/swap`)
104
+ url.searchParams.set('src', params.src)
105
+ url.searchParams.set('dst', params.dst)
106
+ url.searchParams.set('amount', params.amount)
107
+ url.searchParams.set('from', params.from)
108
+ url.searchParams.set('destReceiver', params.destReceiver)
109
+ url.searchParams.set('slippage', params.slippage.toString())
110
+ url.searchParams.set('disableEstimate', (params.disableEstimate ?? true).toString())
111
+
112
+ const response = await fetch(url.toString(), {
113
+ headers: { Authorization: `Bearer ${this.apiKey}` },
114
+ })
115
+
116
+ if (!response.ok) {
117
+ throw new Error(`1inch API error: ${response.status} ${response.statusText}`)
118
+ }
119
+
120
+ return response.json()
121
+ }
122
+
123
+ static supportedChains(): string[] {
124
+ return Object.keys(CHAIN_IDS)
125
+ }
126
+ }
@@ -129,7 +129,7 @@ export const ETHEREUM_TOKEN_CONTRACTS = {
129
129
  /** Tether USD */
130
130
  USDT: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
131
131
  /** Dai Stablecoin */
132
- DAI: '0x6B175474E89094C44Da98b954EescdeCB5bE3d830',
132
+ DAI: '0x6B175474E89094C44Da98b954EeDeAC495271d0F',
133
133
  /** Chainlink */
134
134
  LINK: '0x514910771AF9Ca656af840dff83E8264EcF986CA',
135
135
  /** Uniswap */
@@ -237,6 +237,38 @@ export const EIP5564_ANNOUNCER_ADDRESS = '0x55649E01B5Df198D18D95b5cc5051630cfD4
237
237
  */
238
238
  export const EIP5564_REGISTRY_ADDRESS = '0x6538E6bf4B0eBd30A8Ea10e318b7AEb51A8E4b5c'
239
239
 
240
+ // ─── SIP Deployed Contract Addresses ──────────────────────────────────────────
241
+
242
+ /**
243
+ * SIP Privacy contract addresses per network
244
+ * Deployed via Foundry Deploy.s.sol
245
+ */
246
+ export const SIP_CONTRACT_ADDRESSES: Partial<Record<EthereumNetwork, {
247
+ sipPrivacy: string
248
+ pedersenVerifier: string
249
+ zkVerifier: string
250
+ stealthAddressRegistry: string
251
+ }>> = {
252
+ sepolia: {
253
+ sipPrivacy: '0x0B0d06D6B5136d63Bd0817414E2D318999e50339',
254
+ pedersenVerifier: '0xEB14E9022A4c3DEED072DeC6b3858c19a00C87Db',
255
+ zkVerifier: '0x26988D988684627084e6ae113e0354f6bc56b126',
256
+ stealthAddressRegistry: '0x1f7f3edD264Cf255dD99Fd433eD9FADE427dEF99',
257
+ },
258
+ 'optimism-sepolia': {
259
+ sipPrivacy: '0x0B0d06D6B5136d63Bd0817414E2D318999e50339',
260
+ pedersenVerifier: '0xEB14E9022A4c3DEED072DeC6b3858c19a00C87Db',
261
+ zkVerifier: '0x26988D988684627084e6ae113e0354f6bc56b126',
262
+ stealthAddressRegistry: '0x1f7f3edD264Cf255dD99Fd433eD9FADE427dEF99',
263
+ },
264
+ 'base-sepolia': {
265
+ sipPrivacy: '0x0B0d06D6B5136d63Bd0817414E2D318999e50339',
266
+ pedersenVerifier: '0xEB14E9022A4c3DEED072DeC6b3858c19a00C87Db',
267
+ zkVerifier: '0x26988D988684627084e6ae113e0354f6bc56b126',
268
+ stealthAddressRegistry: '0x1f7f3edD264Cf255dD99Fd433eD9FADE427dEF99',
269
+ },
270
+ }
271
+
240
272
  /**
241
273
  * SIP announcement event signature (for log filtering)
242
274
  * Announcement(uint256 indexed schemeId, address indexed stealthAddress, address indexed caller, bytes ephemeralPubKey, bytes metadata)
@@ -39,6 +39,7 @@ export {
39
39
  isL2Network,
40
40
  isValidEthAddress,
41
41
  sanitizeUrl,
42
+ SIP_CONTRACT_ADDRESSES,
42
43
  } from './constants'
43
44
 
44
45
  // ─── Types ────────────────────────────────────────────────────────────────────
@@ -83,7 +84,7 @@ export {
83
84
  generateEthereumStealthAddress,
84
85
  deriveEthereumStealthPrivateKey,
85
86
  checkEthereumStealthAddress,
86
- checkViewTag,
87
+ checkEthereumStealthByEthAddress,
87
88
  stealthPublicKeyToEthAddress,
88
89
  extractPublicKeys,
89
90
  createMetaAddressFromPublicKeys,