@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.
- package/dist/bridge/use-private-teleport.d.ts +1 -1
- package/dist/bridge/use-private-teleport.d.ts.map +1 -1
- package/dist/bridge/use-private-teleport.js +73 -71
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/package.json +5 -1
- package/src/bridge/cross-chain-store.ts +210 -0
- package/src/bridge/index.ts +81 -0
- package/src/bridge/private-teleport-types.ts +578 -0
- package/src/bridge/types.ts +125 -0
- package/src/bridge/use-cross-chain-mint.ts +299 -0
- package/src/bridge/use-private-teleport.ts +951 -0
- package/src/index.ts +2 -2
- package/dist/bridge/__tests__/use-private-teleport.test.d.ts +0 -2
- package/dist/bridge/__tests__/use-private-teleport.test.d.ts.map +0 -1
- package/dist/bridge/__tests__/use-private-teleport.test.js +0 -272
package/src/index.ts
CHANGED
|
@@ -27,5 +27,5 @@ export * from './hooks'
|
|
|
27
27
|
// Stores
|
|
28
28
|
export * from './stores'
|
|
29
29
|
|
|
30
|
-
//
|
|
31
|
-
|
|
30
|
+
// Bridge (cross-chain + Z-Chain privacy layer)
|
|
31
|
+
export * from './bridge'
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-private-teleport.test.d.ts","sourceRoot":"","sources":["../../../src/bridge/__tests__/use-private-teleport.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,272 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { TeleportState } from '../private-teleport-types';
|
|
3
|
-
// Test that types are correctly exported and usable
|
|
4
|
-
describe('PrivateTeleport Types', () => {
|
|
5
|
-
describe('TeleportState enum', () => {
|
|
6
|
-
it('should have correct numeric values', () => {
|
|
7
|
-
expect(TeleportState.INITIATED).toBe(0);
|
|
8
|
-
expect(TeleportState.SHIELDED).toBe(1);
|
|
9
|
-
expect(TeleportState.SWAP_COMPLETE).toBe(2);
|
|
10
|
-
expect(TeleportState.EXPORTED).toBe(3);
|
|
11
|
-
expect(TeleportState.COMPLETED).toBe(4);
|
|
12
|
-
expect(TeleportState.CANCELLED).toBe(5);
|
|
13
|
-
expect(TeleportState.EXPIRED).toBe(6);
|
|
14
|
-
});
|
|
15
|
-
it('should have all expected states', () => {
|
|
16
|
-
const states = Object.values(TeleportState).filter(v => typeof v === 'number');
|
|
17
|
-
expect(states).toHaveLength(7);
|
|
18
|
-
});
|
|
19
|
-
});
|
|
20
|
-
describe('ZNote type', () => {
|
|
21
|
-
it('should allow valid ZNote creation', () => {
|
|
22
|
-
const znote = {
|
|
23
|
-
commitment: '0x1234567890abcdef',
|
|
24
|
-
nullifier: '0xfedcba0987654321',
|
|
25
|
-
encryptedAmount: '0xencrypted',
|
|
26
|
-
owner: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
|
|
27
|
-
};
|
|
28
|
-
expect(znote.commitment).toBe('0x1234567890abcdef');
|
|
29
|
-
expect(znote.nullifier).toBe('0xfedcba0987654321');
|
|
30
|
-
expect(znote.encryptedAmount).toBe('0xencrypted');
|
|
31
|
-
expect(znote.owner).toBe('0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266');
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
describe('TeleportInfo type', () => {
|
|
35
|
-
it('should allow valid TeleportInfo creation', () => {
|
|
36
|
-
const info = {
|
|
37
|
-
id: '0xteleportId',
|
|
38
|
-
sourceChain: 1,
|
|
39
|
-
destChain: 2,
|
|
40
|
-
sourceToken: '0xsourceToken',
|
|
41
|
-
destToken: '0xdestToken',
|
|
42
|
-
sender: '0xsender',
|
|
43
|
-
recipient: '0xrecipient',
|
|
44
|
-
amount: BigInt(1000000000000000000),
|
|
45
|
-
state: TeleportState.INITIATED,
|
|
46
|
-
createdAt: BigInt(Date.now()),
|
|
47
|
-
deadline: BigInt(Date.now() + 3600000),
|
|
48
|
-
};
|
|
49
|
-
expect(info.state).toBe(TeleportState.INITIATED);
|
|
50
|
-
expect(info.sourceChain).toBe(1);
|
|
51
|
-
expect(info.destChain).toBe(2);
|
|
52
|
-
});
|
|
53
|
-
it('should handle optional znote field', () => {
|
|
54
|
-
const infoWithZNote = {
|
|
55
|
-
id: '0xteleportId',
|
|
56
|
-
sourceChain: 1,
|
|
57
|
-
destChain: 2,
|
|
58
|
-
sourceToken: '0xsourceToken',
|
|
59
|
-
destToken: '0xdestToken',
|
|
60
|
-
sender: '0xsender',
|
|
61
|
-
recipient: '0xrecipient',
|
|
62
|
-
amount: BigInt(1000000000000000000),
|
|
63
|
-
state: TeleportState.SHIELDED,
|
|
64
|
-
createdAt: BigInt(Date.now()),
|
|
65
|
-
deadline: BigInt(Date.now() + 3600000),
|
|
66
|
-
znote: {
|
|
67
|
-
commitment: '0xcommitment',
|
|
68
|
-
nullifier: '0xnullifier',
|
|
69
|
-
encryptedAmount: '0xencrypted',
|
|
70
|
-
owner: '0xowner',
|
|
71
|
-
},
|
|
72
|
-
};
|
|
73
|
-
expect(infoWithZNote.znote).toBeDefined();
|
|
74
|
-
expect(infoWithZNote.znote?.commitment).toBe('0xcommitment');
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
describe('PrivateTeleportConfig type', () => {
|
|
78
|
-
it('should allow valid config creation', () => {
|
|
79
|
-
const config = {
|
|
80
|
-
sourceChainId: 1,
|
|
81
|
-
destChainId: 2,
|
|
82
|
-
sourceToken: '0xsourceToken',
|
|
83
|
-
destToken: '0xdestToken',
|
|
84
|
-
amount: BigInt(1000000000000000000),
|
|
85
|
-
recipient: '0xrecipient',
|
|
86
|
-
slippageTolerance: 50, // 0.5%
|
|
87
|
-
deadline: BigInt(Date.now() + 3600000),
|
|
88
|
-
};
|
|
89
|
-
expect(config.sourceChainId).toBe(1);
|
|
90
|
-
expect(config.destChainId).toBe(2);
|
|
91
|
-
expect(config.slippageTolerance).toBe(50);
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
describe('TeleportState transitions', () => {
|
|
96
|
-
it('should follow valid state progression', () => {
|
|
97
|
-
// Valid progression: INITIATED -> SHIELDED -> SWAP_COMPLETE -> EXPORTED -> COMPLETED
|
|
98
|
-
const validProgression = [
|
|
99
|
-
TeleportState.INITIATED,
|
|
100
|
-
TeleportState.SHIELDED,
|
|
101
|
-
TeleportState.SWAP_COMPLETE,
|
|
102
|
-
TeleportState.EXPORTED,
|
|
103
|
-
TeleportState.COMPLETED,
|
|
104
|
-
];
|
|
105
|
-
for (let i = 0; i < validProgression.length - 1; i++) {
|
|
106
|
-
expect(validProgression[i]).toBeLessThan(validProgression[i + 1]);
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
it('should identify terminal states', () => {
|
|
110
|
-
const terminalStates = [TeleportState.COMPLETED, TeleportState.CANCELLED, TeleportState.EXPIRED];
|
|
111
|
-
terminalStates.forEach((state) => {
|
|
112
|
-
expect(state).toBeGreaterThanOrEqual(TeleportState.COMPLETED);
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
it('should identify cancellable states', () => {
|
|
116
|
-
const cancellableStates = [TeleportState.INITIATED, TeleportState.SHIELDED];
|
|
117
|
-
cancellableStates.forEach((state) => {
|
|
118
|
-
expect(state).toBeLessThan(TeleportState.SWAP_COMPLETE);
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
});
|
|
122
|
-
describe('Amount calculations', () => {
|
|
123
|
-
it('should handle BigInt amounts correctly', () => {
|
|
124
|
-
const oneEther = BigInt(1e18);
|
|
125
|
-
const halfEther = BigInt(5e17);
|
|
126
|
-
expect(oneEther + halfEther).toBe(BigInt(15e17));
|
|
127
|
-
expect(oneEther - halfEther).toBe(halfEther);
|
|
128
|
-
expect(oneEther / BigInt(2)).toBe(halfEther);
|
|
129
|
-
});
|
|
130
|
-
it('should calculate slippage correctly', () => {
|
|
131
|
-
const amount = BigInt(1000000000000000000); // 1 ETH
|
|
132
|
-
const slippageBps = 50; // 0.5%
|
|
133
|
-
const minOutput = amount - (amount * BigInt(slippageBps)) / BigInt(10000);
|
|
134
|
-
const expectedMinOutput = BigInt(995000000000000000); // 0.995 ETH
|
|
135
|
-
expect(minOutput).toBe(expectedMinOutput);
|
|
136
|
-
});
|
|
137
|
-
it('should handle zero amounts', () => {
|
|
138
|
-
const zero = BigInt(0);
|
|
139
|
-
expect(zero).toBe(BigInt(0));
|
|
140
|
-
expect(zero + BigInt(100)).toBe(BigInt(100));
|
|
141
|
-
});
|
|
142
|
-
});
|
|
143
|
-
describe('Address validation helpers', () => {
|
|
144
|
-
it('should validate Ethereum addresses', () => {
|
|
145
|
-
const validAddress = '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266';
|
|
146
|
-
expect(validAddress.length).toBe(42);
|
|
147
|
-
expect(validAddress.startsWith('0x')).toBe(true);
|
|
148
|
-
expect(/^0x[a-fA-F0-9]{40}$/.test(validAddress)).toBe(true);
|
|
149
|
-
});
|
|
150
|
-
it('should reject invalid addresses', () => {
|
|
151
|
-
const invalidAddresses = ['0x123', 'notanaddress', '0x' + 'g'.repeat(40)];
|
|
152
|
-
invalidAddresses.forEach((addr) => {
|
|
153
|
-
expect(/^0x[a-fA-F0-9]{40}$/.test(addr)).toBe(false);
|
|
154
|
-
});
|
|
155
|
-
});
|
|
156
|
-
it('should handle checksummed addresses', () => {
|
|
157
|
-
const checksummed = '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266';
|
|
158
|
-
const lowercase = checksummed.toLowerCase();
|
|
159
|
-
expect(checksummed.toLowerCase()).toBe(lowercase);
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
describe('Chain ID validation', () => {
|
|
163
|
-
const supportedChains = [1, 96369, 200200, 200201]; // Mainnet, Lux, Zoo, Zootest
|
|
164
|
-
it('should identify supported chains', () => {
|
|
165
|
-
supportedChains.forEach((chainId) => {
|
|
166
|
-
expect(chainId).toBeGreaterThan(0);
|
|
167
|
-
});
|
|
168
|
-
});
|
|
169
|
-
it('should reject invalid chain IDs', () => {
|
|
170
|
-
const invalidChains = [0, -1];
|
|
171
|
-
invalidChains.forEach((chainId) => {
|
|
172
|
-
expect(chainId).toBeLessThanOrEqual(0);
|
|
173
|
-
});
|
|
174
|
-
});
|
|
175
|
-
});
|
|
176
|
-
describe('Deadline handling', () => {
|
|
177
|
-
it('should calculate valid deadline', () => {
|
|
178
|
-
const now = BigInt(Math.floor(Date.now() / 1000));
|
|
179
|
-
const oneHourFromNow = now + BigInt(3600);
|
|
180
|
-
expect(oneHourFromNow).toBeGreaterThan(now);
|
|
181
|
-
});
|
|
182
|
-
it('should identify expired deadlines', () => {
|
|
183
|
-
const now = BigInt(Math.floor(Date.now() / 1000));
|
|
184
|
-
const oneHourAgo = now - BigInt(3600);
|
|
185
|
-
expect(oneHourAgo).toBeLessThan(now);
|
|
186
|
-
});
|
|
187
|
-
it('should handle deadline extension', () => {
|
|
188
|
-
const now = BigInt(Math.floor(Date.now() / 1000));
|
|
189
|
-
const deadline = now + BigInt(3600);
|
|
190
|
-
const extendedDeadline = deadline + BigInt(1800); // Add 30 minutes
|
|
191
|
-
expect(extendedDeadline).toBeGreaterThan(deadline);
|
|
192
|
-
expect(extendedDeadline - deadline).toBe(BigInt(1800));
|
|
193
|
-
});
|
|
194
|
-
});
|
|
195
|
-
describe('Error scenarios', () => {
|
|
196
|
-
it('should handle insufficient balance error', () => {
|
|
197
|
-
const balance = BigInt(1e18);
|
|
198
|
-
const requested = BigInt(2e18);
|
|
199
|
-
expect(balance < requested).toBe(true);
|
|
200
|
-
});
|
|
201
|
-
it('should handle slippage exceeded error', () => {
|
|
202
|
-
const expectedOutput = BigInt(1e18); // 1 ETH expected
|
|
203
|
-
const actualOutput = BigInt(9e17); // 0.9 ETH received (10% slippage)
|
|
204
|
-
const minAcceptable = BigInt(95e16); // 0.95 ETH (5% slippage tolerance)
|
|
205
|
-
// Actual output is below minimum acceptable, so slippage exceeded
|
|
206
|
-
expect(actualOutput < minAcceptable).toBe(true);
|
|
207
|
-
expect(actualOutput < expectedOutput).toBe(true);
|
|
208
|
-
});
|
|
209
|
-
it('should handle deadline passed error', () => {
|
|
210
|
-
const now = Math.floor(Date.now() / 1000);
|
|
211
|
-
const expiredDeadline = now - 3600;
|
|
212
|
-
expect(expiredDeadline < now).toBe(true);
|
|
213
|
-
});
|
|
214
|
-
});
|
|
215
|
-
describe('Privacy features', () => {
|
|
216
|
-
it('should generate unique commitments', () => {
|
|
217
|
-
// Mock commitment generation - in reality uses keccak256(secret + value)
|
|
218
|
-
const commitment1 = '0x' + '1'.repeat(64);
|
|
219
|
-
const commitment2 = '0x' + '2'.repeat(64);
|
|
220
|
-
expect(commitment1).not.toBe(commitment2);
|
|
221
|
-
expect(commitment1.length).toBe(66); // 0x + 64 hex chars
|
|
222
|
-
});
|
|
223
|
-
it('should verify nullifier uniqueness', () => {
|
|
224
|
-
const nullifiers = new Set();
|
|
225
|
-
const nullifier1 = '0x' + 'a'.repeat(64);
|
|
226
|
-
const nullifier2 = '0x' + 'b'.repeat(64);
|
|
227
|
-
nullifiers.add(nullifier1);
|
|
228
|
-
expect(nullifiers.has(nullifier1)).toBe(true);
|
|
229
|
-
expect(nullifiers.has(nullifier2)).toBe(false);
|
|
230
|
-
});
|
|
231
|
-
it('should handle encrypted amounts', () => {
|
|
232
|
-
// FHE encrypted values are opaque strings
|
|
233
|
-
const encryptedAmount = '0x' + 'encrypted_data'.padEnd(128, '0');
|
|
234
|
-
expect(encryptedAmount.startsWith('0x')).toBe(true);
|
|
235
|
-
expect(encryptedAmount.length).toBeGreaterThan(2);
|
|
236
|
-
});
|
|
237
|
-
});
|
|
238
|
-
describe('Swap routing', () => {
|
|
239
|
-
it('should calculate price impact', () => {
|
|
240
|
-
const inputAmount = BigInt(1e18);
|
|
241
|
-
const outputAmount = BigInt(998e15); // 0.998 ETH equivalent
|
|
242
|
-
const priceImpactBps = ((inputAmount - outputAmount) * BigInt(10000)) / inputAmount;
|
|
243
|
-
expect(priceImpactBps).toBe(BigInt(20)); // 0.2%
|
|
244
|
-
});
|
|
245
|
-
it('should select optimal route', () => {
|
|
246
|
-
const routes = [
|
|
247
|
-
{ output: BigInt(990e15), path: ['A', 'B'] },
|
|
248
|
-
{ output: BigInt(995e15), path: ['A', 'C', 'B'] },
|
|
249
|
-
{ output: BigInt(998e15), path: ['A', 'B'] },
|
|
250
|
-
];
|
|
251
|
-
const bestRoute = routes.reduce((best, current) => (current.output > best.output ? current : best));
|
|
252
|
-
expect(bestRoute.output).toBe(BigInt(998e15));
|
|
253
|
-
});
|
|
254
|
-
});
|
|
255
|
-
describe('Cross-chain message verification', () => {
|
|
256
|
-
it('should verify Warp message format', () => {
|
|
257
|
-
const warpMessage = {
|
|
258
|
-
sourceChainId: 1,
|
|
259
|
-
destChainId: 96369,
|
|
260
|
-
payload: '0x' + 'data'.padEnd(64, '0'),
|
|
261
|
-
signature: '0x' + 'sig'.padEnd(130, '0'),
|
|
262
|
-
};
|
|
263
|
-
expect(warpMessage.sourceChainId).toBe(1);
|
|
264
|
-
expect(warpMessage.destChainId).toBe(96369);
|
|
265
|
-
expect(warpMessage.payload.startsWith('0x')).toBe(true);
|
|
266
|
-
});
|
|
267
|
-
it('should validate BLS signature length', () => {
|
|
268
|
-
// BLS signatures are 96 bytes = 192 hex chars
|
|
269
|
-
const blsSignature = '0x' + '0'.repeat(192);
|
|
270
|
-
expect(blsSignature.length).toBe(194); // 0x + 192 hex chars
|
|
271
|
-
});
|
|
272
|
-
});
|