@luxfi/exchange 0.1.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 (154) hide show
  1. package/dist/bridge/__tests__/use-private-teleport.test.d.ts +2 -0
  2. package/dist/bridge/__tests__/use-private-teleport.test.d.ts.map +1 -0
  3. package/dist/bridge/__tests__/use-private-teleport.test.js +272 -0
  4. package/dist/bridge/cross-chain-store.d.ts +57 -0
  5. package/dist/bridge/cross-chain-store.d.ts.map +1 -0
  6. package/dist/bridge/cross-chain-store.js +158 -0
  7. package/dist/bridge/index.d.ts +78 -0
  8. package/dist/bridge/index.d.ts.map +1 -0
  9. package/dist/bridge/index.js +79 -0
  10. package/dist/bridge/private-teleport-types.d.ts +634 -0
  11. package/dist/bridge/private-teleport-types.d.ts.map +1 -0
  12. package/dist/bridge/private-teleport-types.js +308 -0
  13. package/dist/bridge/types.d.ts +84 -0
  14. package/dist/bridge/types.d.ts.map +1 -0
  15. package/dist/bridge/types.js +37 -0
  16. package/dist/bridge/use-cross-chain-mint.d.ts +34 -0
  17. package/dist/bridge/use-cross-chain-mint.d.ts.map +1 -0
  18. package/dist/bridge/use-cross-chain-mint.js +228 -0
  19. package/dist/bridge/use-private-teleport.d.ts +69 -0
  20. package/dist/bridge/use-private-teleport.d.ts.map +1 -0
  21. package/dist/bridge/use-private-teleport.js +666 -0
  22. package/dist/chains/index.d.ts +6 -0
  23. package/dist/chains/index.d.ts.map +1 -0
  24. package/dist/chains/index.js +6 -0
  25. package/dist/chains/lux.d.ts +508 -0
  26. package/dist/chains/lux.d.ts.map +1 -0
  27. package/dist/chains/lux.js +131 -0
  28. package/dist/contracts/abis/dex-swap-router.d.ts +137 -0
  29. package/dist/contracts/abis/dex-swap-router.d.ts.map +1 -0
  30. package/dist/contracts/abis/dex-swap-router.js +95 -0
  31. package/dist/contracts/abis/erc20.d.ts +136 -0
  32. package/dist/contracts/abis/erc20.d.ts.map +1 -0
  33. package/dist/contracts/abis/erc20.js +96 -0
  34. package/dist/contracts/abis/index.d.ts +15 -0
  35. package/dist/contracts/abis/index.d.ts.map +1 -0
  36. package/dist/contracts/abis/index.js +15 -0
  37. package/dist/contracts/abis/nft-position-manager.d.ts +235 -0
  38. package/dist/contracts/abis/nft-position-manager.d.ts.map +1 -0
  39. package/dist/contracts/abis/nft-position-manager.js +146 -0
  40. package/dist/contracts/abis/pool-manager.d.ts +315 -0
  41. package/dist/contracts/abis/pool-manager.d.ts.map +1 -0
  42. package/dist/contracts/abis/pool-manager.js +191 -0
  43. package/dist/contracts/abis/quoter-v2.d.ts +103 -0
  44. package/dist/contracts/abis/quoter-v2.d.ts.map +1 -0
  45. package/dist/contracts/abis/quoter-v2.js +68 -0
  46. package/dist/contracts/abis/swap-router.d.ts +119 -0
  47. package/dist/contracts/abis/swap-router.d.ts.map +1 -0
  48. package/dist/contracts/abis/swap-router.js +75 -0
  49. package/dist/contracts/abis/uniswap-v2-factory.d.ts +75 -0
  50. package/dist/contracts/abis/uniswap-v2-factory.d.ts.map +1 -0
  51. package/dist/contracts/abis/uniswap-v2-factory.js +49 -0
  52. package/dist/contracts/abis/uniswap-v2-pair.d.ts +119 -0
  53. package/dist/contracts/abis/uniswap-v2-pair.d.ts.map +1 -0
  54. package/dist/contracts/abis/uniswap-v2-pair.js +85 -0
  55. package/dist/contracts/abis/uniswap-v2-router.d.ts +249 -0
  56. package/dist/contracts/abis/uniswap-v2-router.d.ts.map +1 -0
  57. package/dist/contracts/abis/uniswap-v2-router.js +146 -0
  58. package/dist/contracts/abis/uniswap-v3-factory.d.ts +77 -0
  59. package/dist/contracts/abis/uniswap-v3-factory.d.ts.map +1 -0
  60. package/dist/contracts/abis/uniswap-v3-factory.js +45 -0
  61. package/dist/contracts/abis/uniswap-v3-pool.d.ts +128 -0
  62. package/dist/contracts/abis/uniswap-v3-pool.d.ts.map +1 -0
  63. package/dist/contracts/abis/uniswap-v3-pool.js +81 -0
  64. package/dist/contracts/addresses.d.ts +141 -0
  65. package/dist/contracts/addresses.d.ts.map +1 -0
  66. package/dist/contracts/addresses.js +108 -0
  67. package/dist/contracts/index.d.ts +6 -0
  68. package/dist/contracts/index.d.ts.map +1 -0
  69. package/dist/contracts/index.js +5 -0
  70. package/dist/dex/balance-delta.d.ts +27 -0
  71. package/dist/dex/balance-delta.d.ts.map +1 -0
  72. package/dist/dex/balance-delta.js +45 -0
  73. package/dist/dex/index.d.ts +7 -0
  74. package/dist/dex/index.d.ts.map +1 -0
  75. package/dist/dex/index.js +6 -0
  76. package/dist/dex/pool-key.d.ts +19 -0
  77. package/dist/dex/pool-key.d.ts.map +1 -0
  78. package/dist/dex/pool-key.js +44 -0
  79. package/dist/dex/types.d.ts +71 -0
  80. package/dist/dex/types.d.ts.map +1 -0
  81. package/dist/dex/types.js +28 -0
  82. package/dist/hooks/index.d.ts +10 -0
  83. package/dist/hooks/index.d.ts.map +1 -0
  84. package/dist/hooks/index.js +9 -0
  85. package/dist/hooks/use-pools.d.ts +24 -0
  86. package/dist/hooks/use-pools.d.ts.map +1 -0
  87. package/dist/hooks/use-pools.js +85 -0
  88. package/dist/hooks/use-positions.d.ts +17 -0
  89. package/dist/hooks/use-positions.d.ts.map +1 -0
  90. package/dist/hooks/use-positions.js +65 -0
  91. package/dist/hooks/use-swap-quote.d.ts +19 -0
  92. package/dist/hooks/use-swap-quote.d.ts.map +1 -0
  93. package/dist/hooks/use-swap-quote.js +54 -0
  94. package/dist/hooks/use-swap.d.ts +22 -0
  95. package/dist/hooks/use-swap.d.ts.map +1 -0
  96. package/dist/hooks/use-swap.js +46 -0
  97. package/dist/hooks/use-token-allowance.d.ts +27 -0
  98. package/dist/hooks/use-token-allowance.d.ts.map +1 -0
  99. package/dist/hooks/use-token-allowance.js +59 -0
  100. package/dist/hooks/use-token-balance.d.ts +17 -0
  101. package/dist/hooks/use-token-balance.d.ts.map +1 -0
  102. package/dist/hooks/use-token-balance.js +58 -0
  103. package/dist/index.d.ts +17 -0
  104. package/dist/index.d.ts.map +1 -0
  105. package/dist/index.js +24 -0
  106. package/dist/stores/index.d.ts +7 -0
  107. package/dist/stores/index.d.ts.map +1 -0
  108. package/dist/stores/index.js +6 -0
  109. package/dist/stores/settings-store.d.ts +25 -0
  110. package/dist/stores/settings-store.d.ts.map +1 -0
  111. package/dist/stores/settings-store.js +16 -0
  112. package/dist/stores/swap-store.d.ts +38 -0
  113. package/dist/stores/swap-store.d.ts.map +1 -0
  114. package/dist/stores/swap-store.js +58 -0
  115. package/dist/stores/token-store.d.ts +21 -0
  116. package/dist/stores/token-store.d.ts.map +1 -0
  117. package/dist/stores/token-store.js +32 -0
  118. package/dist/tokens/index.d.ts +65 -0
  119. package/dist/tokens/index.d.ts.map +1 -0
  120. package/dist/tokens/index.js +185 -0
  121. package/package.json +78 -0
  122. package/src/chains/index.ts +21 -0
  123. package/src/chains/lux.ts +141 -0
  124. package/src/contracts/abis/dex-swap-router.ts +98 -0
  125. package/src/contracts/abis/erc20.ts +96 -0
  126. package/src/contracts/abis/index.ts +17 -0
  127. package/src/contracts/abis/nft-position-manager.ts +146 -0
  128. package/src/contracts/abis/pool-manager.ts +198 -0
  129. package/src/contracts/abis/quoter-v2.ts +68 -0
  130. package/src/contracts/abis/swap-router.ts +75 -0
  131. package/src/contracts/abis/uniswap-v2-factory.ts +49 -0
  132. package/src/contracts/abis/uniswap-v2-pair.ts +85 -0
  133. package/src/contracts/abis/uniswap-v2-router.ts +146 -0
  134. package/src/contracts/abis/uniswap-v3-factory.ts +45 -0
  135. package/src/contracts/abis/uniswap-v3-pool.ts +81 -0
  136. package/src/contracts/addresses.ts +128 -0
  137. package/src/contracts/index.ts +14 -0
  138. package/src/dex/balance-delta.ts +52 -0
  139. package/src/dex/index.ts +7 -0
  140. package/src/dex/pool-key.ts +62 -0
  141. package/src/dex/types.ts +87 -0
  142. package/src/hooks/index.ts +10 -0
  143. package/src/hooks/use-pools.ts +116 -0
  144. package/src/hooks/use-positions.ts +90 -0
  145. package/src/hooks/use-swap-quote.ts +81 -0
  146. package/src/hooks/use-swap.ts +64 -0
  147. package/src/hooks/use-token-allowance.ts +74 -0
  148. package/src/hooks/use-token-balance.ts +71 -0
  149. package/src/index.ts +31 -0
  150. package/src/stores/index.ts +7 -0
  151. package/src/stores/settings-store.ts +54 -0
  152. package/src/stores/swap-store.ts +112 -0
  153. package/src/stores/token-store.ts +62 -0
  154. package/src/tokens/index.ts +220 -0
@@ -0,0 +1,666 @@
1
+ /**
2
+ * Private Teleport Hook
3
+ *
4
+ * React hook for cross-chain private teleportation
5
+ * Enables: XVM UTXO → ZNote (shielded) → Z-Chain AMM → destination
6
+ */
7
+ import { useCallback, useEffect, useState } from 'react';
8
+ import { usePublicClient, useWalletClient } from 'wagmi';
9
+ import { encodeFunctionData, keccak256, toHex } from 'viem';
10
+ import { DEFAULT_PRIVATE_TELEPORT_CONFIG, PRIVATE_TELEPORT_ABI, ZNOTE_ABI, } from './private-teleport-types';
11
+ // ═══════════════════════════════════════════════════════════════════════════
12
+ // CRYPTO UTILITIES (STUB - REAL IMPL USES @luxfi/crypto)
13
+ // ═══════════════════════════════════════════════════════════════════════════
14
+ /**
15
+ * Generate Pedersen commitment to an amount
16
+ * In production: Uses @luxfi/crypto Pedersen commitment scheme
17
+ */
18
+ async function generateCommitment(amount, blindingFactor) {
19
+ // Generate random blinding factor if not provided
20
+ const bf = blindingFactor ?? toHex(BigInt(Math.random() * Number.MAX_SAFE_INTEGER));
21
+ // Pedersen: C = g^amount * h^blinding
22
+ // Simplified for now - real implementation uses elliptic curve ops
23
+ const commitment = keccak256(toHex(amount) + bf.slice(2));
24
+ return {
25
+ commitment,
26
+ blindingFactor: bf,
27
+ };
28
+ }
29
+ /**
30
+ * FHE-encrypt a value
31
+ * In production: Uses @luxfi/fhe TFHE encryption
32
+ */
33
+ async function fheEncrypt(value, publicKey) {
34
+ // Simplified - real implementation uses TFHE
35
+ const ciphertext = keccak256(toHex(value) + publicKey.slice(2));
36
+ return {
37
+ ciphertext,
38
+ publicKey,
39
+ };
40
+ }
41
+ /**
42
+ * Generate Bulletproof range proof
43
+ * In production: Uses @luxfi/crypto Bulletproof implementation
44
+ */
45
+ async function generateRangeProof(amount, commitment, blindingFactor, rangeBits = 64) {
46
+ // Simplified - real implementation generates actual Bulletproof
47
+ const proof = keccak256(commitment + blindingFactor.slice(2) + toHex(amount).slice(2));
48
+ return {
49
+ proof,
50
+ commitment,
51
+ rangeBits,
52
+ };
53
+ }
54
+ /**
55
+ * Generate nullifier for spending a note
56
+ */
57
+ function generateNullifier(commitment, spendingKey, noteIndex) {
58
+ return keccak256(commitment + spendingKey.slice(2) + toHex(noteIndex).slice(2));
59
+ }
60
+ // ═══════════════════════════════════════════════════════════════════════════
61
+ // STATE MAPPING
62
+ // ═══════════════════════════════════════════════════════════════════════════
63
+ const stateMap = {
64
+ 0: 'pending',
65
+ 1: 'shielded',
66
+ 2: 'swapped',
67
+ 3: 'exporting',
68
+ 4: 'complete',
69
+ 5: 'cancelled',
70
+ 6: 'expired',
71
+ };
72
+ // ═══════════════════════════════════════════════════════════════════════════
73
+ // HOOK IMPLEMENTATION
74
+ // ═══════════════════════════════════════════════════════════════════════════
75
+ export function usePrivateTeleport(options = {}) {
76
+ const { config: configOverrides, pollInterval = 5000, onStateChange, } = options;
77
+ const config = {
78
+ ...DEFAULT_PRIVATE_TELEPORT_CONFIG,
79
+ ...configOverrides,
80
+ };
81
+ const publicClient = usePublicClient();
82
+ const { data: walletClient } = useWalletClient();
83
+ const [currentTeleportId, setCurrentTeleportId] = useState(null);
84
+ const [currentState, setCurrentState] = useState(null);
85
+ const [isLoading, setIsLoading] = useState(false);
86
+ const [error, setError] = useState(null);
87
+ // Store commitment secrets for later use
88
+ const [secrets, setSecrets] = useState(new Map());
89
+ // ─────────────────────────────────────────────────────────────────────────
90
+ // INITIATE TELEPORT
91
+ // ─────────────────────────────────────────────────────────────────────────
92
+ const teleport = useCallback(async (request) => {
93
+ if (!walletClient || !publicClient) {
94
+ throw new Error('Wallet not connected');
95
+ }
96
+ setIsLoading(true);
97
+ setError(null);
98
+ try {
99
+ // Generate Pedersen commitment
100
+ const commitment = await generateCommitment(request.amount);
101
+ // FHE-encrypt the amount
102
+ const fhePublicKey = '0x' + '00'.repeat(32); // Would fetch from ZNote
103
+ const encrypted = await fheEncrypt(request.amount, fhePublicKey);
104
+ // Build Warp message (would be signed by validators in production)
105
+ const warpMessage = encodeFunctionData({
106
+ abi: [{ name: 'teleport', type: 'function', inputs: [
107
+ { name: 'sourceChain', type: 'bytes32' },
108
+ { name: 'sourceAsset', type: 'bytes32' },
109
+ { name: 'sender', type: 'address' },
110
+ { name: 'deadline', type: 'uint256' },
111
+ ], outputs: [] }],
112
+ functionName: 'teleport',
113
+ args: [
114
+ request.sourceChain,
115
+ request.sourceAsset,
116
+ walletClient.account.address,
117
+ BigInt(request.deadline),
118
+ ],
119
+ });
120
+ // Call initiateTeleport
121
+ const txData = encodeFunctionData({
122
+ abi: PRIVATE_TELEPORT_ABI,
123
+ functionName: 'initiateTeleport',
124
+ args: [
125
+ warpMessage,
126
+ commitment.commitment,
127
+ encrypted.ciphertext,
128
+ request.recipient,
129
+ request.destChain,
130
+ request.destAsset ?? request.sourceAsset,
131
+ request.privateSwap,
132
+ ],
133
+ });
134
+ const hash = await walletClient.sendTransaction({
135
+ to: config.teleportContract,
136
+ data: txData,
137
+ value: BigInt(0),
138
+ });
139
+ // Wait for confirmation
140
+ const receipt = await publicClient.waitForTransactionReceipt({ hash });
141
+ // Extract teleportId from logs (simplified)
142
+ const teleportId = receipt.logs[0]?.topics[1] ?? hash;
143
+ // Store secrets for later
144
+ const spendingKey = keccak256(toHex(Date.now()));
145
+ setSecrets(prev => new Map(prev).set(teleportId, {
146
+ blindingFactor: commitment.blindingFactor,
147
+ spendingKey,
148
+ noteIndex: 0, // Would be extracted from event
149
+ }));
150
+ setCurrentTeleportId(teleportId);
151
+ setCurrentState('pending');
152
+ return teleportId;
153
+ }
154
+ catch (err) {
155
+ const e = err instanceof Error ? err : new Error(String(err));
156
+ setError(e);
157
+ throw e;
158
+ }
159
+ finally {
160
+ setIsLoading(false);
161
+ }
162
+ }, [walletClient, publicClient, config]);
163
+ // ─────────────────────────────────────────────────────────────────────────
164
+ // EXECUTE PRIVATE SWAP
165
+ // ─────────────────────────────────────────────────────────────────────────
166
+ const executeSwap = useCallback(async (teleportId, poolId, minOutput) => {
167
+ if (!walletClient || !publicClient) {
168
+ throw new Error('Wallet not connected');
169
+ }
170
+ setIsLoading(true);
171
+ setError(null);
172
+ try {
173
+ // Encrypt minimum output
174
+ const fhePublicKey = '0x' + '00'.repeat(32);
175
+ const encryptedMinOutput = await fheEncrypt(minOutput, fhePublicKey);
176
+ // Generate swap proof (stub)
177
+ const swapProof = keccak256(teleportId);
178
+ const txData = encodeFunctionData({
179
+ abi: PRIVATE_TELEPORT_ABI,
180
+ functionName: 'executePrivateSwap',
181
+ args: [
182
+ teleportId,
183
+ poolId,
184
+ encryptedMinOutput.ciphertext,
185
+ swapProof,
186
+ ],
187
+ });
188
+ const hash = await walletClient.sendTransaction({
189
+ to: config.teleportContract,
190
+ data: txData,
191
+ value: BigInt(0),
192
+ });
193
+ await publicClient.waitForTransactionReceipt({ hash });
194
+ setCurrentState('swapped');
195
+ onStateChange?.(teleportId, 'swapped');
196
+ }
197
+ catch (err) {
198
+ const e = err instanceof Error ? err : new Error(String(err));
199
+ setError(e);
200
+ throw e;
201
+ }
202
+ finally {
203
+ setIsLoading(false);
204
+ }
205
+ }, [walletClient, publicClient, config, onStateChange]);
206
+ // ─────────────────────────────────────────────────────────────────────────
207
+ // EXPORT TO DESTINATION
208
+ // ─────────────────────────────────────────────────────────────────────────
209
+ const exportToDestination = useCallback(async (teleportId) => {
210
+ if (!walletClient || !publicClient) {
211
+ throw new Error('Wallet not connected');
212
+ }
213
+ const secret = secrets.get(teleportId);
214
+ if (!secret) {
215
+ throw new Error('Secrets not found for teleport');
216
+ }
217
+ setIsLoading(true);
218
+ setError(null);
219
+ try {
220
+ // Get teleport record to get commitment
221
+ const record = await getTeleportRecord(teleportId);
222
+ if (!record) {
223
+ throw new Error('Teleport not found');
224
+ }
225
+ // Generate range proof
226
+ const rangeProof = await generateRangeProof(BigInt(0), // Would get actual amount from decrypted value
227
+ record.noteCommitment, secret.blindingFactor);
228
+ // Generate nullifier
229
+ const nullifier = generateNullifier(record.noteCommitment, secret.spendingKey, secret.noteIndex);
230
+ // Get Merkle proof from ZNote
231
+ const merkleProofData = await publicClient.readContract({
232
+ address: config.zNoteContract,
233
+ abi: ZNOTE_ABI,
234
+ functionName: 'getMerkleProof',
235
+ args: [BigInt(secret.noteIndex)],
236
+ });
237
+ const txData = encodeFunctionData({
238
+ abi: PRIVATE_TELEPORT_ABI,
239
+ functionName: 'exportToDestination',
240
+ args: [
241
+ teleportId,
242
+ rangeProof.proof,
243
+ nullifier,
244
+ merkleProofData,
245
+ ],
246
+ });
247
+ const hash = await walletClient.sendTransaction({
248
+ to: config.teleportContract,
249
+ data: txData,
250
+ value: BigInt(0),
251
+ });
252
+ await publicClient.waitForTransactionReceipt({ hash });
253
+ setCurrentState('exporting');
254
+ onStateChange?.(teleportId, 'exporting');
255
+ }
256
+ catch (err) {
257
+ const e = err instanceof Error ? err : new Error(String(err));
258
+ setError(e);
259
+ throw e;
260
+ }
261
+ finally {
262
+ setIsLoading(false);
263
+ }
264
+ }, [walletClient, publicClient, config, secrets, onStateChange]);
265
+ // ─────────────────────────────────────────────────────────────────────────
266
+ // COMPLETE TELEPORT
267
+ // ─────────────────────────────────────────────────────────────────────────
268
+ const completeTeleport = useCallback(async (teleportId, warpConfirmation) => {
269
+ if (!walletClient || !publicClient) {
270
+ throw new Error('Wallet not connected');
271
+ }
272
+ setIsLoading(true);
273
+ setError(null);
274
+ try {
275
+ const txData = encodeFunctionData({
276
+ abi: PRIVATE_TELEPORT_ABI,
277
+ functionName: 'completeTeleport',
278
+ args: [teleportId, warpConfirmation],
279
+ });
280
+ const hash = await walletClient.sendTransaction({
281
+ to: config.teleportContract,
282
+ data: txData,
283
+ value: BigInt(0),
284
+ });
285
+ await publicClient.waitForTransactionReceipt({ hash });
286
+ setCurrentState('complete');
287
+ onStateChange?.(teleportId, 'complete');
288
+ // Clean up secrets
289
+ setSecrets(prev => {
290
+ const next = new Map(prev);
291
+ next.delete(teleportId);
292
+ return next;
293
+ });
294
+ }
295
+ catch (err) {
296
+ const e = err instanceof Error ? err : new Error(String(err));
297
+ setError(e);
298
+ throw e;
299
+ }
300
+ finally {
301
+ setIsLoading(false);
302
+ }
303
+ }, [walletClient, publicClient, config, onStateChange]);
304
+ // ─────────────────────────────────────────────────────────────────────────
305
+ // UNSHIELD TO X-CHAIN
306
+ // ─────────────────────────────────────────────────────────────────────────
307
+ const unshieldToXChain = useCallback(async (request) => {
308
+ if (!walletClient || !publicClient) {
309
+ throw new Error('Wallet not connected');
310
+ }
311
+ const secret = secrets.get(request.teleportId);
312
+ if (!secret) {
313
+ throw new Error('Secrets not found for teleport');
314
+ }
315
+ setIsLoading(true);
316
+ setError(null);
317
+ try {
318
+ const record = await getTeleportRecord(request.teleportId);
319
+ if (!record) {
320
+ throw new Error('Teleport not found');
321
+ }
322
+ // Generate range proof (proves amount matches commitment)
323
+ const rangeProof = await generateRangeProof(request.amount, record.noteCommitment, secret.blindingFactor);
324
+ // Generate nullifier
325
+ const nullifier = generateNullifier(record.noteCommitment, secret.spendingKey, secret.noteIndex);
326
+ // Get Merkle proof
327
+ const merkleProofData = await publicClient.readContract({
328
+ address: config.zNoteContract,
329
+ abi: ZNOTE_ABI,
330
+ functionName: 'getMerkleProof',
331
+ args: [BigInt(secret.noteIndex)],
332
+ });
333
+ // Encode destination address
334
+ const destinationBytes = toHex(new TextEncoder().encode(request.destinationAddress));
335
+ const txData = encodeFunctionData({
336
+ abi: PRIVATE_TELEPORT_ABI,
337
+ functionName: 'unshieldToXChain',
338
+ args: [
339
+ request.teleportId,
340
+ destinationBytes,
341
+ BigInt(request.amount),
342
+ nullifier,
343
+ merkleProofData,
344
+ rangeProof.proof,
345
+ ],
346
+ });
347
+ const hash = await walletClient.sendTransaction({
348
+ to: config.teleportContract,
349
+ data: txData,
350
+ value: BigInt(0),
351
+ });
352
+ const receipt = await publicClient.waitForTransactionReceipt({ hash });
353
+ // Extract exportTxId from logs
354
+ const exportTxId = receipt.logs[0]?.topics[1] ?? hash;
355
+ setCurrentState('complete');
356
+ onStateChange?.(request.teleportId, 'complete');
357
+ // Clean up secrets
358
+ setSecrets(prev => {
359
+ const next = new Map(prev);
360
+ next.delete(request.teleportId);
361
+ return next;
362
+ });
363
+ return exportTxId;
364
+ }
365
+ catch (err) {
366
+ const e = err instanceof Error ? err : new Error(String(err));
367
+ setError(e);
368
+ throw e;
369
+ }
370
+ finally {
371
+ setIsLoading(false);
372
+ }
373
+ }, [walletClient, publicClient, config, secrets, onStateChange, getTeleportRecord]);
374
+ // ─────────────────────────────────────────────────────────────────────────
375
+ // PRIVATE TRANSFER TO RECIPIENT
376
+ // ─────────────────────────────────────────────────────────────────────────
377
+ const privateTransfer = useCallback(async (request) => {
378
+ if (!walletClient || !publicClient) {
379
+ throw new Error('Wallet not connected');
380
+ }
381
+ const secret = secrets.get(request.teleportId);
382
+ if (!secret) {
383
+ throw new Error('Secrets not found for teleport');
384
+ }
385
+ setIsLoading(true);
386
+ setError(null);
387
+ try {
388
+ const record = await getTeleportRecord(request.teleportId);
389
+ if (!record) {
390
+ throw new Error('Teleport not found');
391
+ }
392
+ // Generate new commitment for recipient
393
+ const recipientCommitment = await generateCommitment(request.amount);
394
+ // Encrypt note to recipient's viewing key
395
+ const encryptedNote = keccak256(request.recipientViewKey + recipientCommitment.commitment.slice(2));
396
+ // Generate nullifier
397
+ const nullifier = generateNullifier(record.noteCommitment, secret.spendingKey, secret.noteIndex);
398
+ // Get Merkle proof
399
+ const merkleProofData = await publicClient.readContract({
400
+ address: config.zNoteContract,
401
+ abi: ZNOTE_ABI,
402
+ functionName: 'getMerkleProof',
403
+ args: [BigInt(secret.noteIndex)],
404
+ });
405
+ // Generate transfer proof (proves amount conservation)
406
+ const transferProof = keccak256(record.noteCommitment + recipientCommitment.commitment.slice(2));
407
+ const txData = encodeFunctionData({
408
+ abi: PRIVATE_TELEPORT_ABI,
409
+ functionName: 'privateTransferToRecipient',
410
+ args: [
411
+ request.teleportId,
412
+ recipientCommitment.commitment,
413
+ encryptedNote,
414
+ nullifier,
415
+ merkleProofData,
416
+ transferProof,
417
+ ],
418
+ });
419
+ const hash = await walletClient.sendTransaction({
420
+ to: config.teleportContract,
421
+ data: txData,
422
+ value: BigInt(0),
423
+ });
424
+ const receipt = await publicClient.waitForTransactionReceipt({ hash });
425
+ // Extract note index from logs (simplified)
426
+ const newNoteIndex = Number(receipt.logs[0]?.data?.slice(0, 66) ?? '0');
427
+ setCurrentState('complete');
428
+ onStateChange?.(request.teleportId, 'complete');
429
+ // Clean up secrets for this teleport
430
+ setSecrets(prev => {
431
+ const next = new Map(prev);
432
+ next.delete(request.teleportId);
433
+ return next;
434
+ });
435
+ return newNoteIndex;
436
+ }
437
+ catch (err) {
438
+ const e = err instanceof Error ? err : new Error(String(err));
439
+ setError(e);
440
+ throw e;
441
+ }
442
+ finally {
443
+ setIsLoading(false);
444
+ }
445
+ }, [walletClient, publicClient, config, secrets, onStateChange, getTeleportRecord]);
446
+ // ─────────────────────────────────────────────────────────────────────────
447
+ // SPLIT AND TRANSFER
448
+ // ─────────────────────────────────────────────────────────────────────────
449
+ const splitAndTransfer = useCallback(async (teleportId, outputs) => {
450
+ if (!walletClient || !publicClient) {
451
+ throw new Error('Wallet not connected');
452
+ }
453
+ const secret = secrets.get(teleportId);
454
+ if (!secret) {
455
+ throw new Error('Secrets not found for teleport');
456
+ }
457
+ if (outputs.length === 0 || outputs.length > 16) {
458
+ throw new Error('Invalid number of outputs (1-16)');
459
+ }
460
+ setIsLoading(true);
461
+ setError(null);
462
+ try {
463
+ const record = await getTeleportRecord(teleportId);
464
+ if (!record) {
465
+ throw new Error('Teleport not found');
466
+ }
467
+ // Generate commitments for each output
468
+ const outputNotes = await Promise.all(outputs.map(async (output) => {
469
+ const commitment = await generateCommitment(output.amount);
470
+ const encryptedNote = keccak256(output.recipient + commitment.commitment.slice(2));
471
+ return {
472
+ commitment: commitment.commitment,
473
+ encryptedNote,
474
+ encryptedMemo: '0x',
475
+ };
476
+ }));
477
+ // Generate nullifier
478
+ const nullifier = generateNullifier(record.noteCommitment, secret.spendingKey, secret.noteIndex);
479
+ // Get Merkle proof
480
+ const merkleProofData = await publicClient.readContract({
481
+ address: config.zNoteContract,
482
+ abi: ZNOTE_ABI,
483
+ functionName: 'getMerkleProof',
484
+ args: [BigInt(secret.noteIndex)],
485
+ });
486
+ // Generate split proof (proves sum of outputs = input)
487
+ const splitProof = keccak256(record.noteCommitment + outputNotes.map(n => n.commitment).join(''));
488
+ const txData = encodeFunctionData({
489
+ abi: PRIVATE_TELEPORT_ABI,
490
+ functionName: 'splitAndTransfer',
491
+ args: [
492
+ teleportId,
493
+ outputNotes,
494
+ nullifier,
495
+ merkleProofData,
496
+ splitProof,
497
+ ],
498
+ });
499
+ const hash = await walletClient.sendTransaction({
500
+ to: config.teleportContract,
501
+ data: txData,
502
+ value: BigInt(0),
503
+ });
504
+ const receipt = await publicClient.waitForTransactionReceipt({ hash });
505
+ // Extract note indices from logs (simplified)
506
+ const noteIndices = outputs.map((_, i) => i);
507
+ setCurrentState('complete');
508
+ onStateChange?.(teleportId, 'complete');
509
+ // Clean up secrets for this teleport
510
+ setSecrets(prev => {
511
+ const next = new Map(prev);
512
+ next.delete(teleportId);
513
+ return next;
514
+ });
515
+ return noteIndices;
516
+ }
517
+ catch (err) {
518
+ const e = err instanceof Error ? err : new Error(String(err));
519
+ setError(e);
520
+ throw e;
521
+ }
522
+ finally {
523
+ setIsLoading(false);
524
+ }
525
+ }, [walletClient, publicClient, config, secrets, onStateChange, getTeleportRecord]);
526
+ // ─────────────────────────────────────────────────────────────────────────
527
+ // CANCEL TELEPORT
528
+ // ─────────────────────────────────────────────────────────────────────────
529
+ const cancelTeleport = useCallback(async (teleportId) => {
530
+ if (!walletClient || !publicClient) {
531
+ throw new Error('Wallet not connected');
532
+ }
533
+ setIsLoading(true);
534
+ setError(null);
535
+ try {
536
+ const txData = encodeFunctionData({
537
+ abi: PRIVATE_TELEPORT_ABI,
538
+ functionName: 'cancelTeleport',
539
+ args: [teleportId],
540
+ });
541
+ const hash = await walletClient.sendTransaction({
542
+ to: config.teleportContract,
543
+ data: txData,
544
+ value: BigInt(0),
545
+ });
546
+ await publicClient.waitForTransactionReceipt({ hash });
547
+ setCurrentState('cancelled');
548
+ onStateChange?.(teleportId, 'cancelled');
549
+ // Clean up secrets
550
+ setSecrets(prev => {
551
+ const next = new Map(prev);
552
+ next.delete(teleportId);
553
+ return next;
554
+ });
555
+ }
556
+ catch (err) {
557
+ const e = err instanceof Error ? err : new Error(String(err));
558
+ setError(e);
559
+ throw e;
560
+ }
561
+ finally {
562
+ setIsLoading(false);
563
+ }
564
+ }, [walletClient, publicClient, config, onStateChange]);
565
+ // ─────────────────────────────────────────────────────────────────────────
566
+ // GET TELEPORT RECORD
567
+ // ─────────────────────────────────────────────────────────────────────────
568
+ const getTeleportRecord = useCallback(async (teleportId) => {
569
+ if (!publicClient) {
570
+ throw new Error('Client not connected');
571
+ }
572
+ try {
573
+ const result = await publicClient.readContract({
574
+ address: config.teleportContract,
575
+ abi: PRIVATE_TELEPORT_ABI,
576
+ functionName: 'getTeleport',
577
+ args: [teleportId],
578
+ });
579
+ const [id, state, sourceChain, destChain, sourceAsset, destAsset, noteCommitment, encryptedAmount, nullifierHash, sender, recipient, deadline, createdBlock, privateSwap] = result;
580
+ if (id === '0x' + '00'.repeat(32)) {
581
+ return null;
582
+ }
583
+ return {
584
+ teleportId: id,
585
+ state: stateMap[state] ?? 'pending',
586
+ sourceChain,
587
+ destChain,
588
+ sourceAsset,
589
+ destAsset,
590
+ noteCommitment,
591
+ encryptedAmount,
592
+ nullifierHash: nullifierHash !== '0x' + '00'.repeat(32) ? nullifierHash : undefined,
593
+ sender,
594
+ recipient,
595
+ deadline: Number(deadline),
596
+ createdBlock: Number(createdBlock),
597
+ privateSwap,
598
+ };
599
+ }
600
+ catch {
601
+ return null;
602
+ }
603
+ }, [publicClient, config]);
604
+ const getTeleport = useCallback(async (teleportId) => {
605
+ return getTeleportRecord(teleportId);
606
+ }, [getTeleportRecord]);
607
+ // ─────────────────────────────────────────────────────────────────────────
608
+ // CHECK COMPLETION
609
+ // ─────────────────────────────────────────────────────────────────────────
610
+ const isComplete = useCallback(async (teleportId) => {
611
+ if (!publicClient) {
612
+ throw new Error('Client not connected');
613
+ }
614
+ try {
615
+ const result = await publicClient.readContract({
616
+ address: config.teleportContract,
617
+ abi: PRIVATE_TELEPORT_ABI,
618
+ functionName: 'isComplete',
619
+ args: [teleportId],
620
+ });
621
+ return result;
622
+ }
623
+ catch {
624
+ return false;
625
+ }
626
+ }, [publicClient, config]);
627
+ // ─────────────────────────────────────────────────────────────────────────
628
+ // POLLING
629
+ // ─────────────────────────────────────────────────────────────────────────
630
+ useEffect(() => {
631
+ if (!currentTeleportId || !publicClient || currentState === 'complete' || currentState === 'cancelled') {
632
+ return;
633
+ }
634
+ const poll = async () => {
635
+ const record = await getTeleportRecord(currentTeleportId);
636
+ if (record && record.state !== currentState) {
637
+ setCurrentState(record.state);
638
+ onStateChange?.(currentTeleportId, record.state);
639
+ }
640
+ };
641
+ const interval = setInterval(poll, pollInterval);
642
+ return () => clearInterval(interval);
643
+ }, [currentTeleportId, currentState, publicClient, pollInterval, onStateChange, getTeleportRecord]);
644
+ return {
645
+ // Initiate
646
+ teleport,
647
+ executeSwap,
648
+ // Export (unshield)
649
+ exportToDestination,
650
+ unshieldToXChain,
651
+ // Private transfers (stay shielded)
652
+ privateTransfer,
653
+ splitAndTransfer,
654
+ // Complete/cancel
655
+ completeTeleport,
656
+ cancelTeleport,
657
+ // Queries
658
+ getTeleport,
659
+ isComplete,
660
+ // State
661
+ currentTeleportId,
662
+ currentState,
663
+ isLoading,
664
+ error,
665
+ };
666
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Chain definitions for Lux Exchange
3
+ */
4
+ export { luxMainnet, luxTestnet, zooMainnet, zooTestnet, luxDev, supportedChains, LUX_MAINNET_ID, LUX_TESTNET_ID, ZOO_MAINNET_ID, ZOO_TESTNET_ID, LUX_DEV_ID, type SupportedChainId, } from './lux';
5
+ export { mainnet, sepolia, arbitrum, optimism, polygon, base } from 'wagmi/chains';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/chains/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,UAAU,EACV,UAAU,EACV,UAAU,EACV,UAAU,EACV,MAAM,EACN,eAAe,EACf,cAAc,EACd,cAAc,EACd,cAAc,EACd,cAAc,EACd,UAAU,EACV,KAAK,gBAAgB,GACtB,MAAM,OAAO,CAAA;AAGd,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Chain definitions for Lux Exchange
3
+ */
4
+ export { luxMainnet, luxTestnet, zooMainnet, zooTestnet, luxDev, supportedChains, LUX_MAINNET_ID, LUX_TESTNET_ID, ZOO_MAINNET_ID, ZOO_TESTNET_ID, LUX_DEV_ID, } from './lux';
5
+ // Re-export common chains from wagmi for external chain support
6
+ export { mainnet, sepolia, arbitrum, optimism, polygon, base } from 'wagmi/chains';