@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.
- package/dist/bridge/__tests__/use-private-teleport.test.d.ts +2 -0
- package/dist/bridge/__tests__/use-private-teleport.test.d.ts.map +1 -0
- package/dist/bridge/__tests__/use-private-teleport.test.js +272 -0
- package/dist/bridge/cross-chain-store.d.ts +57 -0
- package/dist/bridge/cross-chain-store.d.ts.map +1 -0
- package/dist/bridge/cross-chain-store.js +158 -0
- package/dist/bridge/index.d.ts +78 -0
- package/dist/bridge/index.d.ts.map +1 -0
- package/dist/bridge/index.js +79 -0
- package/dist/bridge/private-teleport-types.d.ts +634 -0
- package/dist/bridge/private-teleport-types.d.ts.map +1 -0
- package/dist/bridge/private-teleport-types.js +308 -0
- package/dist/bridge/types.d.ts +84 -0
- package/dist/bridge/types.d.ts.map +1 -0
- package/dist/bridge/types.js +37 -0
- package/dist/bridge/use-cross-chain-mint.d.ts +34 -0
- package/dist/bridge/use-cross-chain-mint.d.ts.map +1 -0
- package/dist/bridge/use-cross-chain-mint.js +228 -0
- package/dist/bridge/use-private-teleport.d.ts +69 -0
- package/dist/bridge/use-private-teleport.d.ts.map +1 -0
- package/dist/bridge/use-private-teleport.js +666 -0
- package/dist/chains/index.d.ts +6 -0
- package/dist/chains/index.d.ts.map +1 -0
- package/dist/chains/index.js +6 -0
- package/dist/chains/lux.d.ts +508 -0
- package/dist/chains/lux.d.ts.map +1 -0
- package/dist/chains/lux.js +131 -0
- package/dist/contracts/abis/dex-swap-router.d.ts +137 -0
- package/dist/contracts/abis/dex-swap-router.d.ts.map +1 -0
- package/dist/contracts/abis/dex-swap-router.js +95 -0
- package/dist/contracts/abis/erc20.d.ts +136 -0
- package/dist/contracts/abis/erc20.d.ts.map +1 -0
- package/dist/contracts/abis/erc20.js +96 -0
- package/dist/contracts/abis/index.d.ts +15 -0
- package/dist/contracts/abis/index.d.ts.map +1 -0
- package/dist/contracts/abis/index.js +15 -0
- package/dist/contracts/abis/nft-position-manager.d.ts +235 -0
- package/dist/contracts/abis/nft-position-manager.d.ts.map +1 -0
- package/dist/contracts/abis/nft-position-manager.js +146 -0
- package/dist/contracts/abis/pool-manager.d.ts +315 -0
- package/dist/contracts/abis/pool-manager.d.ts.map +1 -0
- package/dist/contracts/abis/pool-manager.js +191 -0
- package/dist/contracts/abis/quoter-v2.d.ts +103 -0
- package/dist/contracts/abis/quoter-v2.d.ts.map +1 -0
- package/dist/contracts/abis/quoter-v2.js +68 -0
- package/dist/contracts/abis/swap-router.d.ts +119 -0
- package/dist/contracts/abis/swap-router.d.ts.map +1 -0
- package/dist/contracts/abis/swap-router.js +75 -0
- package/dist/contracts/abis/uniswap-v2-factory.d.ts +75 -0
- package/dist/contracts/abis/uniswap-v2-factory.d.ts.map +1 -0
- package/dist/contracts/abis/uniswap-v2-factory.js +49 -0
- package/dist/contracts/abis/uniswap-v2-pair.d.ts +119 -0
- package/dist/contracts/abis/uniswap-v2-pair.d.ts.map +1 -0
- package/dist/contracts/abis/uniswap-v2-pair.js +85 -0
- package/dist/contracts/abis/uniswap-v2-router.d.ts +249 -0
- package/dist/contracts/abis/uniswap-v2-router.d.ts.map +1 -0
- package/dist/contracts/abis/uniswap-v2-router.js +146 -0
- package/dist/contracts/abis/uniswap-v3-factory.d.ts +77 -0
- package/dist/contracts/abis/uniswap-v3-factory.d.ts.map +1 -0
- package/dist/contracts/abis/uniswap-v3-factory.js +45 -0
- package/dist/contracts/abis/uniswap-v3-pool.d.ts +128 -0
- package/dist/contracts/abis/uniswap-v3-pool.d.ts.map +1 -0
- package/dist/contracts/abis/uniswap-v3-pool.js +81 -0
- package/dist/contracts/addresses.d.ts +141 -0
- package/dist/contracts/addresses.d.ts.map +1 -0
- package/dist/contracts/addresses.js +108 -0
- package/dist/contracts/index.d.ts +6 -0
- package/dist/contracts/index.d.ts.map +1 -0
- package/dist/contracts/index.js +5 -0
- package/dist/dex/balance-delta.d.ts +27 -0
- package/dist/dex/balance-delta.d.ts.map +1 -0
- package/dist/dex/balance-delta.js +45 -0
- package/dist/dex/index.d.ts +7 -0
- package/dist/dex/index.d.ts.map +1 -0
- package/dist/dex/index.js +6 -0
- package/dist/dex/pool-key.d.ts +19 -0
- package/dist/dex/pool-key.d.ts.map +1 -0
- package/dist/dex/pool-key.js +44 -0
- package/dist/dex/types.d.ts +71 -0
- package/dist/dex/types.d.ts.map +1 -0
- package/dist/dex/types.js +28 -0
- package/dist/hooks/index.d.ts +10 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +9 -0
- package/dist/hooks/use-pools.d.ts +24 -0
- package/dist/hooks/use-pools.d.ts.map +1 -0
- package/dist/hooks/use-pools.js +85 -0
- package/dist/hooks/use-positions.d.ts +17 -0
- package/dist/hooks/use-positions.d.ts.map +1 -0
- package/dist/hooks/use-positions.js +65 -0
- package/dist/hooks/use-swap-quote.d.ts +19 -0
- package/dist/hooks/use-swap-quote.d.ts.map +1 -0
- package/dist/hooks/use-swap-quote.js +54 -0
- package/dist/hooks/use-swap.d.ts +22 -0
- package/dist/hooks/use-swap.d.ts.map +1 -0
- package/dist/hooks/use-swap.js +46 -0
- package/dist/hooks/use-token-allowance.d.ts +27 -0
- package/dist/hooks/use-token-allowance.d.ts.map +1 -0
- package/dist/hooks/use-token-allowance.js +59 -0
- package/dist/hooks/use-token-balance.d.ts +17 -0
- package/dist/hooks/use-token-balance.d.ts.map +1 -0
- package/dist/hooks/use-token-balance.js +58 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/stores/index.d.ts +7 -0
- package/dist/stores/index.d.ts.map +1 -0
- package/dist/stores/index.js +6 -0
- package/dist/stores/settings-store.d.ts +25 -0
- package/dist/stores/settings-store.d.ts.map +1 -0
- package/dist/stores/settings-store.js +16 -0
- package/dist/stores/swap-store.d.ts +38 -0
- package/dist/stores/swap-store.d.ts.map +1 -0
- package/dist/stores/swap-store.js +58 -0
- package/dist/stores/token-store.d.ts +21 -0
- package/dist/stores/token-store.d.ts.map +1 -0
- package/dist/stores/token-store.js +32 -0
- package/dist/tokens/index.d.ts +65 -0
- package/dist/tokens/index.d.ts.map +1 -0
- package/dist/tokens/index.js +185 -0
- package/package.json +78 -0
- package/src/chains/index.ts +21 -0
- package/src/chains/lux.ts +141 -0
- package/src/contracts/abis/dex-swap-router.ts +98 -0
- package/src/contracts/abis/erc20.ts +96 -0
- package/src/contracts/abis/index.ts +17 -0
- package/src/contracts/abis/nft-position-manager.ts +146 -0
- package/src/contracts/abis/pool-manager.ts +198 -0
- package/src/contracts/abis/quoter-v2.ts +68 -0
- package/src/contracts/abis/swap-router.ts +75 -0
- package/src/contracts/abis/uniswap-v2-factory.ts +49 -0
- package/src/contracts/abis/uniswap-v2-pair.ts +85 -0
- package/src/contracts/abis/uniswap-v2-router.ts +146 -0
- package/src/contracts/abis/uniswap-v3-factory.ts +45 -0
- package/src/contracts/abis/uniswap-v3-pool.ts +81 -0
- package/src/contracts/addresses.ts +128 -0
- package/src/contracts/index.ts +14 -0
- package/src/dex/balance-delta.ts +52 -0
- package/src/dex/index.ts +7 -0
- package/src/dex/pool-key.ts +62 -0
- package/src/dex/types.ts +87 -0
- package/src/hooks/index.ts +10 -0
- package/src/hooks/use-pools.ts +116 -0
- package/src/hooks/use-positions.ts +90 -0
- package/src/hooks/use-swap-quote.ts +81 -0
- package/src/hooks/use-swap.ts +64 -0
- package/src/hooks/use-token-allowance.ts +74 -0
- package/src/hooks/use-token-balance.ts +71 -0
- package/src/index.ts +31 -0
- package/src/stores/index.ts +7 -0
- package/src/stores/settings-store.ts +54 -0
- package/src/stores/swap-store.ts +112 -0
- package/src/stores/token-store.ts +62 -0
- 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';
|