@luxfi/exchange 0.1.0 → 0.2.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.
@@ -4,7 +4,7 @@
4
4
  * React hook for cross-chain private teleportation
5
5
  * Enables: XVM UTXO → ZNote (shielded) → Z-Chain AMM → destination
6
6
  */
7
- import { type PrivateTeleportConfig, type PrivateTeleportRequest, type TeleportRecord, type TeleportState } from './private-teleport-types';
7
+ import { type PrivateTeleportConfig, type PrivateTeleportRequest, type TeleportRecord, TeleportState } from './private-teleport-types';
8
8
  export interface UsePrivateTeleportOptions {
9
9
  /** Custom config */
10
10
  config?: Partial<PrivateTeleportConfig>;
@@ -1 +1 @@
1
- {"version":3,"file":"use-private-teleport.d.ts","sourceRoot":"","sources":["../../src/bridge/use-private-teleport.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"use-private-teleport.d.ts","sourceRoot":"","sources":["../../src/bridge/use-private-teleport.ts"],"names":[],"mappings":"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"}
@@ -7,7 +7,7 @@
7
7
  import { useCallback, useEffect, useState } from 'react';
8
8
  import { usePublicClient, useWalletClient } from 'wagmi';
9
9
  import { encodeFunctionData, keccak256, toHex } from 'viem';
10
- import { DEFAULT_PRIVATE_TELEPORT_CONFIG, PRIVATE_TELEPORT_ABI, ZNOTE_ABI, } from './private-teleport-types';
10
+ import { TeleportState, DEFAULT_PRIVATE_TELEPORT_CONFIG, PRIVATE_TELEPORT_ABI, ZNOTE_ABI, } from './private-teleport-types';
11
11
  // ═══════════════════════════════════════════════════════════════════════════
12
12
  // CRYPTO UTILITIES (STUB - REAL IMPL USES @luxfi/crypto)
13
13
  // ═══════════════════════════════════════════════════════════════════════════
@@ -20,7 +20,7 @@ async function generateCommitment(amount, blindingFactor) {
20
20
  const bf = blindingFactor ?? toHex(BigInt(Math.random() * Number.MAX_SAFE_INTEGER));
21
21
  // Pedersen: C = g^amount * h^blinding
22
22
  // Simplified for now - real implementation uses elliptic curve ops
23
- const commitment = keccak256(toHex(amount) + bf.slice(2));
23
+ const commitment = keccak256(`${toHex(amount)}${bf.slice(2)}`);
24
24
  return {
25
25
  commitment,
26
26
  blindingFactor: bf,
@@ -32,7 +32,7 @@ async function generateCommitment(amount, blindingFactor) {
32
32
  */
33
33
  async function fheEncrypt(value, publicKey) {
34
34
  // Simplified - real implementation uses TFHE
35
- const ciphertext = keccak256(toHex(value) + publicKey.slice(2));
35
+ const ciphertext = keccak256(`${toHex(value)}${publicKey.slice(2)}`);
36
36
  return {
37
37
  ciphertext,
38
38
  publicKey,
@@ -44,7 +44,7 @@ async function fheEncrypt(value, publicKey) {
44
44
  */
45
45
  async function generateRangeProof(amount, commitment, blindingFactor, rangeBits = 64) {
46
46
  // Simplified - real implementation generates actual Bulletproof
47
- const proof = keccak256(commitment + blindingFactor.slice(2) + toHex(amount).slice(2));
47
+ const proof = keccak256(`${commitment}${blindingFactor.slice(2)}${toHex(amount).slice(2)}`);
48
48
  return {
49
49
  proof,
50
50
  commitment,
@@ -55,19 +55,19 @@ async function generateRangeProof(amount, commitment, blindingFactor, rangeBits
55
55
  * Generate nullifier for spending a note
56
56
  */
57
57
  function generateNullifier(commitment, spendingKey, noteIndex) {
58
- return keccak256(commitment + spendingKey.slice(2) + toHex(noteIndex).slice(2));
58
+ return keccak256(`${commitment}${spendingKey.slice(2)}${toHex(noteIndex).slice(2)}`);
59
59
  }
60
60
  // ═══════════════════════════════════════════════════════════════════════════
61
61
  // STATE MAPPING
62
62
  // ═══════════════════════════════════════════════════════════════════════════
63
63
  const stateMap = {
64
- 0: 'pending',
65
- 1: 'shielded',
66
- 2: 'swapped',
67
- 3: 'exporting',
68
- 4: 'complete',
69
- 5: 'cancelled',
70
- 6: 'expired',
64
+ 0: TeleportState.INITIATED,
65
+ 1: TeleportState.SHIELDED,
66
+ 2: TeleportState.SWAP_COMPLETE,
67
+ 3: TeleportState.EXPORTED,
68
+ 4: TeleportState.COMPLETED,
69
+ 5: TeleportState.CANCELLED,
70
+ 6: TeleportState.EXPIRED,
71
71
  };
72
72
  // ═══════════════════════════════════════════════════════════════════════════
73
73
  // HOOK IMPLEMENTATION
@@ -148,7 +148,7 @@ export function usePrivateTeleport(options = {}) {
148
148
  noteIndex: 0, // Would be extracted from event
149
149
  }));
150
150
  setCurrentTeleportId(teleportId);
151
- setCurrentState('pending');
151
+ setCurrentState(TeleportState.INITIATED);
152
152
  return teleportId;
153
153
  }
154
154
  catch (err) {
@@ -191,8 +191,8 @@ export function usePrivateTeleport(options = {}) {
191
191
  value: BigInt(0),
192
192
  });
193
193
  await publicClient.waitForTransactionReceipt({ hash });
194
- setCurrentState('swapped');
195
- onStateChange?.(teleportId, 'swapped');
194
+ setCurrentState(TeleportState.SWAP_COMPLETE);
195
+ onStateChange?.(teleportId, TeleportState.SWAP_COMPLETE);
196
196
  }
197
197
  catch (err) {
198
198
  const e = err instanceof Error ? err : new Error(String(err));
@@ -204,6 +204,46 @@ export function usePrivateTeleport(options = {}) {
204
204
  }
205
205
  }, [walletClient, publicClient, config, onStateChange]);
206
206
  // ─────────────────────────────────────────────────────────────────────────
207
+ // GET TELEPORT RECORD (defined early for use by other callbacks)
208
+ // ─────────────────────────────────────────────────────────────────────────
209
+ const getTeleportRecord = useCallback(async (teleportId) => {
210
+ if (!publicClient) {
211
+ throw new Error('Client not connected');
212
+ }
213
+ try {
214
+ const result = await publicClient.readContract({
215
+ address: config.teleportContract,
216
+ abi: PRIVATE_TELEPORT_ABI,
217
+ functionName: 'getTeleport',
218
+ args: [teleportId],
219
+ });
220
+ const tuple = result;
221
+ const [id, state, sourceChain, destChain, sourceAsset, destAsset, noteCommitment, encryptedAmount, nullifierHash, sender, recipient, deadline, createdBlock, privateSwap] = tuple;
222
+ if (id === '0x' + '00'.repeat(32)) {
223
+ return null;
224
+ }
225
+ return {
226
+ teleportId: id,
227
+ state: stateMap[state] ?? TeleportState.INITIATED,
228
+ sourceChain,
229
+ destChain,
230
+ sourceAsset,
231
+ destAsset,
232
+ noteCommitment,
233
+ encryptedAmount,
234
+ nullifierHash: nullifierHash !== '0x' + '00'.repeat(32) ? nullifierHash : undefined,
235
+ sender,
236
+ recipient,
237
+ deadline: Number(deadline),
238
+ createdBlock: Number(createdBlock),
239
+ privateSwap,
240
+ };
241
+ }
242
+ catch {
243
+ return null;
244
+ }
245
+ }, [publicClient, config]);
246
+ // ─────────────────────────────────────────────────────────────────────────
207
247
  // EXPORT TO DESTINATION
208
248
  // ─────────────────────────────────────────────────────────────────────────
209
249
  const exportToDestination = useCallback(async (teleportId) => {
@@ -250,8 +290,8 @@ export function usePrivateTeleport(options = {}) {
250
290
  value: BigInt(0),
251
291
  });
252
292
  await publicClient.waitForTransactionReceipt({ hash });
253
- setCurrentState('exporting');
254
- onStateChange?.(teleportId, 'exporting');
293
+ setCurrentState(TeleportState.EXPORTED);
294
+ onStateChange?.(teleportId, TeleportState.EXPORTED);
255
295
  }
256
296
  catch (err) {
257
297
  const e = err instanceof Error ? err : new Error(String(err));
@@ -283,8 +323,8 @@ export function usePrivateTeleport(options = {}) {
283
323
  value: BigInt(0),
284
324
  });
285
325
  await publicClient.waitForTransactionReceipt({ hash });
286
- setCurrentState('complete');
287
- onStateChange?.(teleportId, 'complete');
326
+ setCurrentState(TeleportState.COMPLETED);
327
+ onStateChange?.(teleportId, TeleportState.COMPLETED);
288
328
  // Clean up secrets
289
329
  setSecrets(prev => {
290
330
  const next = new Map(prev);
@@ -352,8 +392,8 @@ export function usePrivateTeleport(options = {}) {
352
392
  const receipt = await publicClient.waitForTransactionReceipt({ hash });
353
393
  // Extract exportTxId from logs
354
394
  const exportTxId = receipt.logs[0]?.topics[1] ?? hash;
355
- setCurrentState('complete');
356
- onStateChange?.(request.teleportId, 'complete');
395
+ setCurrentState(TeleportState.COMPLETED);
396
+ onStateChange?.(request.teleportId, TeleportState.COMPLETED);
357
397
  // Clean up secrets
358
398
  setSecrets(prev => {
359
399
  const next = new Map(prev);
@@ -392,7 +432,7 @@ export function usePrivateTeleport(options = {}) {
392
432
  // Generate new commitment for recipient
393
433
  const recipientCommitment = await generateCommitment(request.amount);
394
434
  // Encrypt note to recipient's viewing key
395
- const encryptedNote = keccak256(request.recipientViewKey + recipientCommitment.commitment.slice(2));
435
+ const encryptedNote = keccak256(`${request.recipientViewKey}${recipientCommitment.commitment.slice(2)}`);
396
436
  // Generate nullifier
397
437
  const nullifier = generateNullifier(record.noteCommitment, secret.spendingKey, secret.noteIndex);
398
438
  // Get Merkle proof
@@ -403,7 +443,7 @@ export function usePrivateTeleport(options = {}) {
403
443
  args: [BigInt(secret.noteIndex)],
404
444
  });
405
445
  // Generate transfer proof (proves amount conservation)
406
- const transferProof = keccak256(record.noteCommitment + recipientCommitment.commitment.slice(2));
446
+ const transferProof = keccak256(`${record.noteCommitment}${recipientCommitment.commitment.slice(2)}`);
407
447
  const txData = encodeFunctionData({
408
448
  abi: PRIVATE_TELEPORT_ABI,
409
449
  functionName: 'privateTransferToRecipient',
@@ -424,8 +464,8 @@ export function usePrivateTeleport(options = {}) {
424
464
  const receipt = await publicClient.waitForTransactionReceipt({ hash });
425
465
  // Extract note index from logs (simplified)
426
466
  const newNoteIndex = Number(receipt.logs[0]?.data?.slice(0, 66) ?? '0');
427
- setCurrentState('complete');
428
- onStateChange?.(request.teleportId, 'complete');
467
+ setCurrentState(TeleportState.COMPLETED);
468
+ onStateChange?.(request.teleportId, TeleportState.COMPLETED);
429
469
  // Clean up secrets for this teleport
430
470
  setSecrets(prev => {
431
471
  const next = new Map(prev);
@@ -467,7 +507,7 @@ export function usePrivateTeleport(options = {}) {
467
507
  // Generate commitments for each output
468
508
  const outputNotes = await Promise.all(outputs.map(async (output) => {
469
509
  const commitment = await generateCommitment(output.amount);
470
- const encryptedNote = keccak256(output.recipient + commitment.commitment.slice(2));
510
+ const encryptedNote = keccak256(`${output.recipient}${commitment.commitment.slice(2)}`);
471
511
  return {
472
512
  commitment: commitment.commitment,
473
513
  encryptedNote,
@@ -484,7 +524,7 @@ export function usePrivateTeleport(options = {}) {
484
524
  args: [BigInt(secret.noteIndex)],
485
525
  });
486
526
  // Generate split proof (proves sum of outputs = input)
487
- const splitProof = keccak256(record.noteCommitment + outputNotes.map(n => n.commitment).join(''));
527
+ const splitProof = keccak256(`${record.noteCommitment}${outputNotes.map(n => n.commitment.slice(2)).join('')}`);
488
528
  const txData = encodeFunctionData({
489
529
  abi: PRIVATE_TELEPORT_ABI,
490
530
  functionName: 'splitAndTransfer',
@@ -504,8 +544,8 @@ export function usePrivateTeleport(options = {}) {
504
544
  const receipt = await publicClient.waitForTransactionReceipt({ hash });
505
545
  // Extract note indices from logs (simplified)
506
546
  const noteIndices = outputs.map((_, i) => i);
507
- setCurrentState('complete');
508
- onStateChange?.(teleportId, 'complete');
547
+ setCurrentState(TeleportState.COMPLETED);
548
+ onStateChange?.(teleportId, TeleportState.COMPLETED);
509
549
  // Clean up secrets for this teleport
510
550
  setSecrets(prev => {
511
551
  const next = new Map(prev);
@@ -544,8 +584,8 @@ export function usePrivateTeleport(options = {}) {
544
584
  value: BigInt(0),
545
585
  });
546
586
  await publicClient.waitForTransactionReceipt({ hash });
547
- setCurrentState('cancelled');
548
- onStateChange?.(teleportId, 'cancelled');
587
+ setCurrentState(TeleportState.CANCELLED);
588
+ onStateChange?.(teleportId, TeleportState.CANCELLED);
549
589
  // Clean up secrets
550
590
  setSecrets(prev => {
551
591
  const next = new Map(prev);
@@ -562,45 +602,7 @@ export function usePrivateTeleport(options = {}) {
562
602
  setIsLoading(false);
563
603
  }
564
604
  }, [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]);
605
+ // Wrapper for external API
604
606
  const getTeleport = useCallback(async (teleportId) => {
605
607
  return getTeleportRecord(teleportId);
606
608
  }, [getTeleportRecord]);
@@ -628,7 +630,7 @@ export function usePrivateTeleport(options = {}) {
628
630
  // POLLING
629
631
  // ─────────────────────────────────────────────────────────────────────────
630
632
  useEffect(() => {
631
- if (!currentTeleportId || !publicClient || currentState === 'complete' || currentState === 'cancelled') {
633
+ if (!currentTeleportId || !publicClient || currentState === TeleportState.COMPLETED || currentState === TeleportState.CANCELLED) {
632
634
  return;
633
635
  }
634
636
  const poll = async () => {
package/dist/index.d.ts CHANGED
@@ -14,4 +14,5 @@ export * from './contracts';
14
14
  export * from './dex';
15
15
  export * from './hooks';
16
16
  export * from './stores';
17
+ export * from './bridge';
17
18
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,cAAc,UAAU,CAAA;AAGxB,cAAc,UAAU,CAAA;AAGxB,cAAc,aAAa,CAAA;AAG3B,cAAc,OAAO,CAAA;AAGrB,cAAc,SAAS,CAAA;AAGvB,cAAc,UAAU,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,cAAc,UAAU,CAAA;AAGxB,cAAc,UAAU,CAAA;AAGxB,cAAc,aAAa,CAAA;AAG3B,cAAc,OAAO,CAAA;AAGrB,cAAc,SAAS,CAAA;AAGvB,cAAc,UAAU,CAAA;AAGxB,cAAc,UAAU,CAAA"}
package/dist/index.js CHANGED
@@ -20,5 +20,5 @@ export * from './dex';
20
20
  export * from './hooks';
21
21
  // Stores
22
22
  export * from './stores';
23
- // Note: Bridge module is experimental and will be added in a future release
24
- // See bridge-wip/ for the work-in-progress implementation
23
+ // Bridge (cross-chain + Z-Chain privacy layer)
24
+ export * from './bridge';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luxfi/exchange",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Lux Exchange SDK - React hooks and utilities for Lux DEX",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",
@@ -34,6 +34,10 @@
34
34
  "./dex": {
35
35
  "types": "./dist/dex/index.d.ts",
36
36
  "import": "./dist/dex/index.js"
37
+ },
38
+ "./bridge": {
39
+ "types": "./dist/bridge/index.d.ts",
40
+ "import": "./dist/bridge/index.js"
37
41
  }
38
42
  },
39
43
  "files": [
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Zustand store for cross-chain mint operations
3
+ */
4
+
5
+ import { create } from 'zustand'
6
+ import { devtools, persist } from 'zustand/middleware'
7
+ import type { CrossChainMintRequest, CrossChainMintState, CrossChainMintStatus } from './types'
8
+
9
+ interface PendingMint extends CrossChainMintRequest {
10
+ state: CrossChainMintState
11
+ }
12
+
13
+ export interface CrossChainStore {
14
+ /** Currently active mints by swap ID */
15
+ pendingMints: Record<string, PendingMint>
16
+ /** Most recent completed mints (for history) */
17
+ recentMints: PendingMint[]
18
+ /** Maximum number of recent mints to keep */
19
+ maxRecentMints: number
20
+
21
+ // Actions
22
+ initiateMint: (request: CrossChainMintRequest) => string
23
+ updateMintStatus: (swapId: string, status: CrossChainMintStatus) => void
24
+ updateMintTxHash: (swapId: string, field: 'sourceTxHash' | 'mintTxHash' | 'swapTxHash', hash: string) => void
25
+ completeMint: (swapId: string) => void
26
+ failMint: (swapId: string, error: string) => void
27
+ cancelMint: (swapId: string) => void
28
+ clearPendingMint: (swapId: string) => void
29
+ getPendingMint: (swapId: string) => PendingMint | undefined
30
+ getActiveMints: () => PendingMint[]
31
+ }
32
+
33
+ // Generate a random swap ID
34
+ function generateSwapId(): string {
35
+ const bytes = new Uint8Array(32)
36
+ crypto.getRandomValues(bytes)
37
+ return '0x' + Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('')
38
+ }
39
+
40
+ export const useCrossChainStore = create<CrossChainStore>()(
41
+ devtools(
42
+ persist(
43
+ (set, get) => ({
44
+ pendingMints: {},
45
+ recentMints: [],
46
+ maxRecentMints: 20,
47
+
48
+ initiateMint: (request: CrossChainMintRequest) => {
49
+ const swapId = generateSwapId()
50
+ const now = Date.now()
51
+
52
+ const pendingMint: PendingMint = {
53
+ ...request,
54
+ state: {
55
+ swapId: swapId as `0x${string}`,
56
+ status: 'initiating',
57
+ sourceTxHash: null,
58
+ mintTxHash: null,
59
+ swapTxHash: null,
60
+ error: null,
61
+ startedAt: now,
62
+ completedAt: null,
63
+ },
64
+ }
65
+
66
+ set((state) => ({
67
+ pendingMints: {
68
+ ...state.pendingMints,
69
+ [swapId]: pendingMint,
70
+ },
71
+ }))
72
+
73
+ return swapId
74
+ },
75
+
76
+ updateMintStatus: (swapId: string, status: CrossChainMintStatus) => {
77
+ set((state) => {
78
+ const mint = state.pendingMints[swapId]
79
+ if (!mint) return state
80
+
81
+ return {
82
+ pendingMints: {
83
+ ...state.pendingMints,
84
+ [swapId]: {
85
+ ...mint,
86
+ state: {
87
+ ...mint.state,
88
+ status,
89
+ },
90
+ },
91
+ },
92
+ }
93
+ })
94
+ },
95
+
96
+ updateMintTxHash: (swapId: string, field: 'sourceTxHash' | 'mintTxHash' | 'swapTxHash', hash: string) => {
97
+ set((state) => {
98
+ const mint = state.pendingMints[swapId]
99
+ if (!mint) return state
100
+
101
+ return {
102
+ pendingMints: {
103
+ ...state.pendingMints,
104
+ [swapId]: {
105
+ ...mint,
106
+ state: {
107
+ ...mint.state,
108
+ [field]: hash,
109
+ },
110
+ },
111
+ },
112
+ }
113
+ })
114
+ },
115
+
116
+ completeMint: (swapId: string) => {
117
+ set((state) => {
118
+ const mint = state.pendingMints[swapId]
119
+ if (!mint) return state
120
+
121
+ const completedMint: PendingMint = {
122
+ ...mint,
123
+ state: {
124
+ ...mint.state,
125
+ status: 'complete',
126
+ completedAt: Date.now(),
127
+ },
128
+ }
129
+
130
+ const { [swapId]: _, ...remainingPending } = state.pendingMints
131
+ const newRecent = [completedMint, ...state.recentMints].slice(0, state.maxRecentMints)
132
+
133
+ return {
134
+ pendingMints: remainingPending,
135
+ recentMints: newRecent,
136
+ }
137
+ })
138
+ },
139
+
140
+ failMint: (swapId: string, error: string) => {
141
+ set((state) => {
142
+ const mint = state.pendingMints[swapId]
143
+ if (!mint) return state
144
+
145
+ return {
146
+ pendingMints: {
147
+ ...state.pendingMints,
148
+ [swapId]: {
149
+ ...mint,
150
+ state: {
151
+ ...mint.state,
152
+ status: 'failed',
153
+ error,
154
+ completedAt: Date.now(),
155
+ },
156
+ },
157
+ },
158
+ }
159
+ })
160
+ },
161
+
162
+ cancelMint: (swapId: string) => {
163
+ set((state) => {
164
+ const mint = state.pendingMints[swapId]
165
+ if (!mint) return state
166
+
167
+ return {
168
+ pendingMints: {
169
+ ...state.pendingMints,
170
+ [swapId]: {
171
+ ...mint,
172
+ state: {
173
+ ...mint.state,
174
+ status: 'cancelled',
175
+ completedAt: Date.now(),
176
+ },
177
+ },
178
+ },
179
+ }
180
+ })
181
+ },
182
+
183
+ clearPendingMint: (swapId: string) => {
184
+ set((state) => {
185
+ const { [swapId]: _, ...remainingPending } = state.pendingMints
186
+ return { pendingMints: remainingPending }
187
+ })
188
+ },
189
+
190
+ getPendingMint: (swapId: string) => {
191
+ return get().pendingMints[swapId]
192
+ },
193
+
194
+ getActiveMints: () => {
195
+ const { pendingMints } = get()
196
+ return Object.values(pendingMints).filter(
197
+ (m) => m.state.status !== 'failed' && m.state.status !== 'cancelled'
198
+ )
199
+ },
200
+ }),
201
+ {
202
+ name: 'cross-chain-mint-storage',
203
+ partialize: (state) => ({
204
+ recentMints: state.recentMints,
205
+ }),
206
+ }
207
+ ),
208
+ { name: 'CrossChainStore' }
209
+ )
210
+ )
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Cross-chain bridge module for XVM ↔ C-Chain atomic swaps
3
+ *
4
+ * Enables one-click minting of wrapped tokens on C-Chain from X-Chain assets
5
+ * using Warp cross-chain messaging and HTLC atomic swaps.
6
+ *
7
+ * Includes Z-Chain privacy layer for fully shielded cross-chain teleportation:
8
+ * XVM UTXO → ZNote (shielded) → Z-Chain AMM (private swap) → destination
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * // Standard cross-chain mint
13
+ * import { useCrossChainMint } from '@luxfi/exchange/bridge'
14
+ *
15
+ * function MintButton() {
16
+ * const { mint, isLoading } = useCrossChainMint()
17
+ *
18
+ * const handleMint = async () => {
19
+ * const swapId = await mint({
20
+ * sourceAsset: '0x...', // XVM asset ID
21
+ * amount: 1000000n, // 1 token (6 decimals)
22
+ * recipient: '0x...', // C-Chain recipient
23
+ * targetToken: '0x...', // Optional: swap to this token
24
+ * minReceive: 990000n, // Slippage protection
25
+ * })
26
+ * console.log('Mint initiated:', swapId)
27
+ * }
28
+ *
29
+ * return (
30
+ * <button onClick={handleMint} disabled={isLoading}>
31
+ * {isLoading ? 'Minting...' : 'Mint on C-Chain'}
32
+ * </button>
33
+ * )
34
+ * }
35
+ * ```
36
+ *
37
+ * @example
38
+ * ```tsx
39
+ * // Private teleport with Z-Chain
40
+ * import { usePrivateTeleport } from '@luxfi/exchange/bridge'
41
+ *
42
+ * function PrivateTeleportButton() {
43
+ * const { teleport, executeSwap, exportToDestination, isLoading } = usePrivateTeleport()
44
+ *
45
+ * const handlePrivateTeleport = async () => {
46
+ * // 1. Initiate shielded teleport (creates ZNote)
47
+ * const teleportId = await teleport({
48
+ * sourceChain: '0x...', // X-Chain ID
49
+ * destChain: '0x...', // C-Chain ID
50
+ * sourceAsset: '0x...', // Asset to teleport
51
+ * destAsset: '0x...', // Asset to receive (if swapping)
52
+ * amount: 1000000n, // Amount (will be encrypted)
53
+ * recipient: '0x...', // Destination address
54
+ * deadline: Math.floor(Date.now() / 1000) + 3600,
55
+ * privateSwap: true, // Use Z-Chain AMM for private swap
56
+ * })
57
+ *
58
+ * // 2. Execute private swap on Z-Chain (optional)
59
+ * await executeSwap(teleportId, '0x...poolId', 990000n)
60
+ *
61
+ * // 3. Export to destination chain with range proof
62
+ * await exportToDestination(teleportId)
63
+ * }
64
+ *
65
+ * return (
66
+ * <button onClick={handlePrivateTeleport} disabled={isLoading}>
67
+ * Private Teleport
68
+ * </button>
69
+ * )
70
+ * }
71
+ * ```
72
+ */
73
+
74
+ // Standard cross-chain (public)
75
+ export * from './types'
76
+ export * from './cross-chain-store'
77
+ export * from './use-cross-chain-mint'
78
+
79
+ // Private teleport (Z-Chain privacy layer)
80
+ export * from './private-teleport-types'
81
+ export * from './use-private-teleport'