@luxfi/dex 1.2.1 → 1.3.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/client/clob.d.ts +52 -0
- package/dist/client/clob.d.ts.map +1 -0
- package/dist/client/clob.js +196 -0
- package/dist/client/index.d.ts +7 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +6 -0
- package/dist/client/types.d.ts +126 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +5 -0
- package/dist/hooks/index.d.ts +7 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +6 -0
- package/dist/hooks/use-quote.d.ts +18 -0
- package/dist/hooks/use-quote.d.ts.map +1 -0
- package/dist/hooks/use-quote.js +65 -0
- package/dist/hooks/use-swap.d.ts +17 -0
- package/dist/hooks/use-swap.d.ts.map +1 -0
- package/dist/hooks/use-swap.js +75 -0
- package/dist/index.d.ts +33 -115
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +41 -225
- package/dist/precompile/abis.d.ts +400 -0
- package/dist/precompile/abis.d.ts.map +1 -0
- package/dist/precompile/abis.js +287 -0
- package/dist/precompile/addresses.d.ts +65 -0
- package/dist/precompile/addresses.d.ts.map +1 -0
- package/dist/precompile/addresses.js +52 -0
- package/dist/precompile/index.d.ts +8 -0
- package/dist/precompile/index.d.ts.map +1 -0
- package/dist/precompile/index.js +7 -0
- package/dist/precompile/types.d.ts +76 -0
- package/dist/precompile/types.d.ts.map +1 -0
- package/dist/precompile/types.js +17 -0
- package/dist/router/index.d.ts +7 -0
- package/dist/router/index.d.ts.map +1 -0
- package/dist/router/index.js +6 -0
- package/dist/router/router.d.ts +58 -0
- package/dist/router/router.d.ts.map +1 -0
- package/dist/router/router.js +272 -0
- package/dist/router/types.d.ts +76 -0
- package/dist/router/types.d.ts.map +1 -0
- package/dist/router/types.js +1 -0
- package/package.json +55 -29
- package/src/client/clob.ts +256 -0
- package/src/client/index.ts +6 -0
- package/src/client/types.ts +148 -0
- package/src/hooks/index.ts +6 -0
- package/src/hooks/use-quote.ts +92 -0
- package/src/hooks/use-swap.ts +103 -0
- package/src/index.ts +76 -309
- package/src/precompile/abis.ts +291 -0
- package/src/precompile/addresses.ts +72 -0
- package/src/precompile/index.ts +7 -0
- package/src/precompile/types.ts +96 -0
- package/src/router/index.ts +6 -0
- package/src/router/router.ts +338 -0
- package/src/router/types.ts +87 -0
- package/dist/marketData.d.ts +0 -152
- package/dist/marketData.d.ts.map +0 -1
- package/dist/marketData.js +0 -253
- package/src/marketData.ts +0 -351
- package/tsconfig.json +0 -19
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLOB Client
|
|
3
|
+
* WebSocket client for lux/dex order book
|
|
4
|
+
*/
|
|
5
|
+
import type { ICLOBClient, OrderRequest, Order, OrderBook, Trade, Position, Balance } from './types';
|
|
6
|
+
interface CLOBClientOptions {
|
|
7
|
+
url: string;
|
|
8
|
+
debug?: boolean;
|
|
9
|
+
reconnect?: boolean;
|
|
10
|
+
reconnectInterval?: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Central Limit Order Book client
|
|
14
|
+
* Connects to lux/dex WebSocket server
|
|
15
|
+
*/
|
|
16
|
+
export declare class CLOBClient implements ICLOBClient {
|
|
17
|
+
private ws;
|
|
18
|
+
private url;
|
|
19
|
+
private debug;
|
|
20
|
+
private reconnect;
|
|
21
|
+
private reconnectInterval;
|
|
22
|
+
private connected;
|
|
23
|
+
private authenticated;
|
|
24
|
+
private requestId;
|
|
25
|
+
private pendingRequests;
|
|
26
|
+
private subscriptions;
|
|
27
|
+
constructor(options: CLOBClientOptions);
|
|
28
|
+
private log;
|
|
29
|
+
connect(): Promise<void>;
|
|
30
|
+
disconnect(): Promise<void>;
|
|
31
|
+
isConnected(): boolean;
|
|
32
|
+
private handleMessage;
|
|
33
|
+
private request;
|
|
34
|
+
authenticate(apiKey: string, apiSecret: string): Promise<void>;
|
|
35
|
+
placeOrder(order: OrderRequest): Promise<Order>;
|
|
36
|
+
cancelOrder(orderId: string): Promise<void>;
|
|
37
|
+
getOrder(orderId: string): Promise<Order>;
|
|
38
|
+
getOrders(symbol?: string): Promise<Order[]>;
|
|
39
|
+
getOrderBook(symbol: string, depth?: number): Promise<OrderBook>;
|
|
40
|
+
getTrades(symbol: string, limit?: number): Promise<Trade[]>;
|
|
41
|
+
getPositions(): Promise<Position[]>;
|
|
42
|
+
getBalances(): Promise<Balance[]>;
|
|
43
|
+
subscribeOrderBook(symbol: string, callback: (book: OrderBook) => void): () => void;
|
|
44
|
+
subscribeTrades(symbol: string, callback: (trade: Trade) => void): () => void;
|
|
45
|
+
subscribeOrders(callback: (order: Order) => void): () => void;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Create a CLOB client
|
|
49
|
+
*/
|
|
50
|
+
export declare function createCLOBClient(url: string, debug?: boolean): ICLOBClient;
|
|
51
|
+
export {};
|
|
52
|
+
//# sourceMappingURL=clob.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clob.d.ts","sourceRoot":"","sources":["../../src/client/clob.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EACV,WAAW,EACX,YAAY,EACZ,KAAK,EACL,SAAS,EACT,KAAK,EACL,QAAQ,EACR,OAAO,EACR,MAAM,SAAS,CAAA;AAEhB,UAAU,iBAAiB;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B;AAID;;;GAGG;AACH,qBAAa,UAAW,YAAW,WAAW;IAC5C,OAAO,CAAC,EAAE,CAAyB;IACnC,OAAO,CAAC,GAAG,CAAQ;IACnB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,iBAAiB,CAAQ;IACjC,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,aAAa,CAAiB;IACtC,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,eAAe,CAAkE;IACzF,OAAO,CAAC,aAAa,CAA8C;gBAEvD,OAAO,EAAE,iBAAiB;IAOtC,OAAO,CAAC,GAAG;IAML,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAmCxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAQjC,WAAW,IAAI,OAAO;IAItB,OAAO,CAAC,aAAa;YA4BP,OAAO;IA4Bf,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK9D,UAAU,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC;IAI/C,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3C,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAIzC,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAI5C,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,OAAO,CAAC,SAAS,CAAC;IAIpE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,GAAE,MAAY,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAIhE,YAAY,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAInC,WAAW,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAIvC,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,GAAG,MAAM,IAAI;IAmBnF,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,MAAM,IAAI;IAmB7E,eAAe,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,MAAM,IAAI;CAkB9D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,GAAE,OAAe,GAAG,WAAW,CAEjF"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Central Limit Order Book client
|
|
3
|
+
* Connects to lux/dex WebSocket server
|
|
4
|
+
*/
|
|
5
|
+
export class CLOBClient {
|
|
6
|
+
ws = null;
|
|
7
|
+
url;
|
|
8
|
+
debug;
|
|
9
|
+
reconnect;
|
|
10
|
+
reconnectInterval;
|
|
11
|
+
connected = false;
|
|
12
|
+
authenticated = false;
|
|
13
|
+
requestId = 0;
|
|
14
|
+
pendingRequests = new Map();
|
|
15
|
+
subscriptions = new Map();
|
|
16
|
+
constructor(options) {
|
|
17
|
+
this.url = options.url;
|
|
18
|
+
this.debug = options.debug ?? false;
|
|
19
|
+
this.reconnect = options.reconnect ?? true;
|
|
20
|
+
this.reconnectInterval = options.reconnectInterval ?? 5000;
|
|
21
|
+
}
|
|
22
|
+
log(...args) {
|
|
23
|
+
if (this.debug) {
|
|
24
|
+
console.log('[CLOBClient]', ...args);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async connect() {
|
|
28
|
+
return new Promise((resolve, reject) => {
|
|
29
|
+
try {
|
|
30
|
+
this.ws = new WebSocket(this.url);
|
|
31
|
+
this.ws.onopen = () => {
|
|
32
|
+
this.connected = true;
|
|
33
|
+
this.log('Connected to', this.url);
|
|
34
|
+
resolve();
|
|
35
|
+
};
|
|
36
|
+
this.ws.onclose = () => {
|
|
37
|
+
this.connected = false;
|
|
38
|
+
this.authenticated = false;
|
|
39
|
+
this.log('Disconnected');
|
|
40
|
+
if (this.reconnect) {
|
|
41
|
+
setTimeout(() => this.connect(), this.reconnectInterval);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
this.ws.onerror = (error) => {
|
|
45
|
+
this.log('Error:', error);
|
|
46
|
+
reject(error);
|
|
47
|
+
};
|
|
48
|
+
this.ws.onmessage = (event) => {
|
|
49
|
+
this.handleMessage(event.data);
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
reject(error);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
async disconnect() {
|
|
58
|
+
this.reconnect = false;
|
|
59
|
+
this.ws?.close();
|
|
60
|
+
this.ws = null;
|
|
61
|
+
this.connected = false;
|
|
62
|
+
this.authenticated = false;
|
|
63
|
+
}
|
|
64
|
+
isConnected() {
|
|
65
|
+
return this.connected;
|
|
66
|
+
}
|
|
67
|
+
handleMessage(data) {
|
|
68
|
+
try {
|
|
69
|
+
const message = JSON.parse(data);
|
|
70
|
+
this.log('Received:', message);
|
|
71
|
+
// Handle response to request
|
|
72
|
+
if (message.id && this.pendingRequests.has(message.id)) {
|
|
73
|
+
const { resolve, reject } = this.pendingRequests.get(message.id);
|
|
74
|
+
this.pendingRequests.delete(message.id);
|
|
75
|
+
if (message.error) {
|
|
76
|
+
reject(new Error(message.error));
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
resolve(message.result || message);
|
|
80
|
+
}
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
// Handle subscription updates
|
|
84
|
+
const type = message.type || message.channel;
|
|
85
|
+
if (type && this.subscriptions.has(type)) {
|
|
86
|
+
this.subscriptions.get(type).forEach(handler => handler(message));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
this.log('Parse error:', error);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async request(method, params) {
|
|
94
|
+
if (!this.connected) {
|
|
95
|
+
throw new Error('Not connected');
|
|
96
|
+
}
|
|
97
|
+
const id = ++this.requestId;
|
|
98
|
+
const message = {
|
|
99
|
+
jsonrpc: '2.0',
|
|
100
|
+
id,
|
|
101
|
+
method,
|
|
102
|
+
params,
|
|
103
|
+
};
|
|
104
|
+
return new Promise((resolve, reject) => {
|
|
105
|
+
this.pendingRequests.set(id, { resolve, reject });
|
|
106
|
+
this.ws.send(JSON.stringify(message));
|
|
107
|
+
this.log('Sent:', message);
|
|
108
|
+
// Timeout after 30 seconds
|
|
109
|
+
setTimeout(() => {
|
|
110
|
+
if (this.pendingRequests.has(id)) {
|
|
111
|
+
this.pendingRequests.delete(id);
|
|
112
|
+
reject(new Error('Request timeout'));
|
|
113
|
+
}
|
|
114
|
+
}, 30000);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
async authenticate(apiKey, apiSecret) {
|
|
118
|
+
await this.request('authenticate', { apiKey, apiSecret });
|
|
119
|
+
this.authenticated = true;
|
|
120
|
+
}
|
|
121
|
+
async placeOrder(order) {
|
|
122
|
+
return this.request('placeOrder', order);
|
|
123
|
+
}
|
|
124
|
+
async cancelOrder(orderId) {
|
|
125
|
+
await this.request('cancelOrder', { orderId });
|
|
126
|
+
}
|
|
127
|
+
async getOrder(orderId) {
|
|
128
|
+
return this.request('getOrder', { orderId });
|
|
129
|
+
}
|
|
130
|
+
async getOrders(symbol) {
|
|
131
|
+
return this.request('getOrders', { symbol });
|
|
132
|
+
}
|
|
133
|
+
async getOrderBook(symbol, depth = 20) {
|
|
134
|
+
return this.request('getOrderBook', { symbol, depth });
|
|
135
|
+
}
|
|
136
|
+
async getTrades(symbol, limit = 100) {
|
|
137
|
+
return this.request('getTrades', { symbol, limit });
|
|
138
|
+
}
|
|
139
|
+
async getPositions() {
|
|
140
|
+
return this.request('getPositions', {});
|
|
141
|
+
}
|
|
142
|
+
async getBalances() {
|
|
143
|
+
return this.request('getBalances', {});
|
|
144
|
+
}
|
|
145
|
+
subscribeOrderBook(symbol, callback) {
|
|
146
|
+
const channel = `orderbook:${symbol}`;
|
|
147
|
+
if (!this.subscriptions.has(channel)) {
|
|
148
|
+
this.subscriptions.set(channel, new Set());
|
|
149
|
+
this.request('subscribe', { channel: 'orderbook', symbol }).catch(console.error);
|
|
150
|
+
}
|
|
151
|
+
this.subscriptions.get(channel).add(callback);
|
|
152
|
+
return () => {
|
|
153
|
+
this.subscriptions.get(channel)?.delete(callback);
|
|
154
|
+
if (this.subscriptions.get(channel)?.size === 0) {
|
|
155
|
+
this.subscriptions.delete(channel);
|
|
156
|
+
this.request('unsubscribe', { channel: 'orderbook', symbol }).catch(console.error);
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
subscribeTrades(symbol, callback) {
|
|
161
|
+
const channel = `trades:${symbol}`;
|
|
162
|
+
if (!this.subscriptions.has(channel)) {
|
|
163
|
+
this.subscriptions.set(channel, new Set());
|
|
164
|
+
this.request('subscribe', { channel: 'trades', symbol }).catch(console.error);
|
|
165
|
+
}
|
|
166
|
+
this.subscriptions.get(channel).add(callback);
|
|
167
|
+
return () => {
|
|
168
|
+
this.subscriptions.get(channel)?.delete(callback);
|
|
169
|
+
if (this.subscriptions.get(channel)?.size === 0) {
|
|
170
|
+
this.subscriptions.delete(channel);
|
|
171
|
+
this.request('unsubscribe', { channel: 'trades', symbol }).catch(console.error);
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
subscribeOrders(callback) {
|
|
176
|
+
const channel = 'orders';
|
|
177
|
+
if (!this.subscriptions.has(channel)) {
|
|
178
|
+
this.subscriptions.set(channel, new Set());
|
|
179
|
+
this.request('subscribe', { channel: 'orders' }).catch(console.error);
|
|
180
|
+
}
|
|
181
|
+
this.subscriptions.get(channel).add(callback);
|
|
182
|
+
return () => {
|
|
183
|
+
this.subscriptions.get(channel)?.delete(callback);
|
|
184
|
+
if (this.subscriptions.get(channel)?.size === 0) {
|
|
185
|
+
this.subscriptions.delete(channel);
|
|
186
|
+
this.request('unsubscribe', { channel: 'orders' }).catch(console.error);
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Create a CLOB client
|
|
193
|
+
*/
|
|
194
|
+
export function createCLOBClient(url, debug = false) {
|
|
195
|
+
return new CLOBClient({ url, debug });
|
|
196
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,SAAS,CAAA;AACvB,cAAc,QAAQ,CAAA"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLOB Client Types
|
|
3
|
+
* Interfaces for Central Limit Order Book operations
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Order side
|
|
7
|
+
*/
|
|
8
|
+
export type OrderSide = 'buy' | 'sell';
|
|
9
|
+
/**
|
|
10
|
+
* Order type
|
|
11
|
+
*/
|
|
12
|
+
export type OrderType = 'limit' | 'market' | 'stop' | 'stop_limit';
|
|
13
|
+
/**
|
|
14
|
+
* Order status
|
|
15
|
+
*/
|
|
16
|
+
export type OrderStatus = 'pending' | 'open' | 'partial' | 'filled' | 'cancelled' | 'rejected';
|
|
17
|
+
/**
|
|
18
|
+
* Time in force
|
|
19
|
+
*/
|
|
20
|
+
export type TimeInForce = 'GTC' | 'IOC' | 'FOK' | 'GTD';
|
|
21
|
+
/**
|
|
22
|
+
* Order request
|
|
23
|
+
*/
|
|
24
|
+
export interface OrderRequest {
|
|
25
|
+
symbol: string;
|
|
26
|
+
side: OrderSide;
|
|
27
|
+
type: OrderType;
|
|
28
|
+
price?: number;
|
|
29
|
+
size: number;
|
|
30
|
+
timeInForce?: TimeInForce;
|
|
31
|
+
clientOrderId?: string;
|
|
32
|
+
reduceOnly?: boolean;
|
|
33
|
+
postOnly?: boolean;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Order response
|
|
37
|
+
*/
|
|
38
|
+
export interface Order {
|
|
39
|
+
orderId: string;
|
|
40
|
+
clientOrderId?: string;
|
|
41
|
+
symbol: string;
|
|
42
|
+
side: OrderSide;
|
|
43
|
+
type: OrderType;
|
|
44
|
+
price: number;
|
|
45
|
+
size: number;
|
|
46
|
+
filledSize: number;
|
|
47
|
+
remainingSize: number;
|
|
48
|
+
status: OrderStatus;
|
|
49
|
+
timeInForce: TimeInForce;
|
|
50
|
+
createdAt: number;
|
|
51
|
+
updatedAt: number;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Order book entry
|
|
55
|
+
*/
|
|
56
|
+
export interface OrderBookEntry {
|
|
57
|
+
price: number;
|
|
58
|
+
size: number;
|
|
59
|
+
count: number;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Order book
|
|
63
|
+
*/
|
|
64
|
+
export interface OrderBook {
|
|
65
|
+
symbol: string;
|
|
66
|
+
bids: OrderBookEntry[];
|
|
67
|
+
asks: OrderBookEntry[];
|
|
68
|
+
timestamp: number;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Trade
|
|
72
|
+
*/
|
|
73
|
+
export interface Trade {
|
|
74
|
+
tradeId: string;
|
|
75
|
+
symbol: string;
|
|
76
|
+
side: OrderSide;
|
|
77
|
+
price: number;
|
|
78
|
+
size: number;
|
|
79
|
+
timestamp: number;
|
|
80
|
+
makerOrderId: string;
|
|
81
|
+
takerOrderId: string;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Position
|
|
85
|
+
*/
|
|
86
|
+
export interface Position {
|
|
87
|
+
symbol: string;
|
|
88
|
+
side: 'long' | 'short';
|
|
89
|
+
size: number;
|
|
90
|
+
entryPrice: number;
|
|
91
|
+
markPrice: number;
|
|
92
|
+
liquidationPrice: number;
|
|
93
|
+
unrealizedPnl: number;
|
|
94
|
+
margin: number;
|
|
95
|
+
leverage: number;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Balance
|
|
99
|
+
*/
|
|
100
|
+
export interface Balance {
|
|
101
|
+
currency: string;
|
|
102
|
+
available: number;
|
|
103
|
+
locked: number;
|
|
104
|
+
total: number;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* CLOB client interface
|
|
108
|
+
*/
|
|
109
|
+
export interface ICLOBClient {
|
|
110
|
+
connect(): Promise<void>;
|
|
111
|
+
disconnect(): Promise<void>;
|
|
112
|
+
isConnected(): boolean;
|
|
113
|
+
authenticate(apiKey: string, apiSecret: string): Promise<void>;
|
|
114
|
+
placeOrder(order: OrderRequest): Promise<Order>;
|
|
115
|
+
cancelOrder(orderId: string): Promise<void>;
|
|
116
|
+
getOrder(orderId: string): Promise<Order>;
|
|
117
|
+
getOrders(symbol?: string): Promise<Order[]>;
|
|
118
|
+
getOrderBook(symbol: string, depth?: number): Promise<OrderBook>;
|
|
119
|
+
getTrades(symbol: string, limit?: number): Promise<Trade[]>;
|
|
120
|
+
getPositions(): Promise<Position[]>;
|
|
121
|
+
getBalances(): Promise<Balance[]>;
|
|
122
|
+
subscribeOrderBook(symbol: string, callback: (book: OrderBook) => void): () => void;
|
|
123
|
+
subscribeTrades(symbol: string, callback: (trade: Trade) => void): () => void;
|
|
124
|
+
subscribeOrders(callback: (order: Order) => void): () => void;
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/client/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Address } from 'viem';
|
|
2
|
+
import { type Quote } from '../router';
|
|
3
|
+
interface UseQuoteOptions {
|
|
4
|
+
refreshInterval?: number;
|
|
5
|
+
enabled?: boolean;
|
|
6
|
+
}
|
|
7
|
+
interface UseQuoteResult {
|
|
8
|
+
quote: Quote | null;
|
|
9
|
+
isLoading: boolean;
|
|
10
|
+
error: Error | null;
|
|
11
|
+
refetch: () => Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Hook to get swap quotes from the omnichain router
|
|
15
|
+
*/
|
|
16
|
+
export declare function useQuote(tokenIn: Address | undefined, tokenOut: Address | undefined, amountIn: bigint | undefined, options?: UseQuoteOptions): UseQuoteResult;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=use-quote.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-quote.d.ts","sourceRoot":"","sources":["../../src/hooks/use-quote.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAEnC,OAAO,EAAmB,KAAK,KAAK,EAAqB,MAAM,WAAW,CAAA;AAE1E,UAAU,eAAe;IACvB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,UAAU,cAAc;IACtB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;IACnB,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;IACnB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7B;AAED;;GAEG;AACH,wBAAgB,QAAQ,CACtB,OAAO,EAAE,OAAO,GAAG,SAAS,EAC5B,QAAQ,EAAE,OAAO,GAAG,SAAS,EAC7B,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,OAAO,GAAE,eAAoB,GAC5B,cAAc,CAgEhB"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useState, useCallback, useEffect, useRef } from 'react';
|
|
3
|
+
import { usePublicClient } from 'wagmi';
|
|
4
|
+
import { OmnichainRouter } from '../router';
|
|
5
|
+
/**
|
|
6
|
+
* Hook to get swap quotes from the omnichain router
|
|
7
|
+
*/
|
|
8
|
+
export function useQuote(tokenIn, tokenOut, amountIn, options = {}) {
|
|
9
|
+
const { refreshInterval = 10000, enabled = true } = options;
|
|
10
|
+
const publicClient = usePublicClient();
|
|
11
|
+
const routerRef = useRef(null);
|
|
12
|
+
const [quote, setQuote] = useState(null);
|
|
13
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
14
|
+
const [error, setError] = useState(null);
|
|
15
|
+
// Initialize router
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
if (!routerRef.current) {
|
|
18
|
+
routerRef.current = new OmnichainRouter();
|
|
19
|
+
}
|
|
20
|
+
if (publicClient) {
|
|
21
|
+
routerRef.current.setPublicClient(publicClient);
|
|
22
|
+
}
|
|
23
|
+
}, [publicClient]);
|
|
24
|
+
const fetchQuote = useCallback(async () => {
|
|
25
|
+
if (!tokenIn || !tokenOut || !amountIn || amountIn === 0n || !enabled) {
|
|
26
|
+
setQuote(null);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
setIsLoading(true);
|
|
30
|
+
setError(null);
|
|
31
|
+
try {
|
|
32
|
+
const request = {
|
|
33
|
+
tokenIn,
|
|
34
|
+
tokenOut,
|
|
35
|
+
amountIn,
|
|
36
|
+
};
|
|
37
|
+
const newQuote = await routerRef.current.getQuote(request);
|
|
38
|
+
setQuote(newQuote);
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
setError(err instanceof Error ? err : new Error('Failed to get quote'));
|
|
42
|
+
setQuote(null);
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
setIsLoading(false);
|
|
46
|
+
}
|
|
47
|
+
}, [tokenIn, tokenOut, amountIn, enabled]);
|
|
48
|
+
// Fetch on mount and when inputs change
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
fetchQuote();
|
|
51
|
+
}, [fetchQuote]);
|
|
52
|
+
// Auto-refresh
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (!enabled || refreshInterval <= 0)
|
|
55
|
+
return;
|
|
56
|
+
const interval = setInterval(fetchQuote, refreshInterval);
|
|
57
|
+
return () => clearInterval(interval);
|
|
58
|
+
}, [fetchQuote, enabled, refreshInterval]);
|
|
59
|
+
return {
|
|
60
|
+
quote,
|
|
61
|
+
isLoading,
|
|
62
|
+
error,
|
|
63
|
+
refetch: fetchQuote,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Address } from 'viem';
|
|
2
|
+
import type { Quote } from '../router';
|
|
3
|
+
interface UseSwapResult {
|
|
4
|
+
swap: (quote: Quote, recipient: Address) => Promise<void>;
|
|
5
|
+
isPending: boolean;
|
|
6
|
+
isConfirming: boolean;
|
|
7
|
+
isSuccess: boolean;
|
|
8
|
+
error: Error | null;
|
|
9
|
+
txHash: `0x${string}` | undefined;
|
|
10
|
+
reset: () => void;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Hook to execute swaps via the DEX precompiles
|
|
14
|
+
*/
|
|
15
|
+
export declare function useSwap(): UseSwapResult;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=use-swap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-swap.d.ts","sourceRoot":"","sources":["../../src/hooks/use-swap.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAKnC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,WAAW,CAAA;AAEtC,UAAU,aAAa;IACrB,IAAI,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACzD,SAAS,EAAE,OAAO,CAAA;IAClB,YAAY,EAAE,OAAO,CAAA;IACrB,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;IACnB,MAAM,EAAE,KAAK,MAAM,EAAE,GAAG,SAAS,CAAA;IACjC,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB;AAED;;GAEG;AACH,wBAAgB,OAAO,IAAI,aAAa,CA+EvC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useState, useCallback } from 'react';
|
|
3
|
+
import { useWriteContract, useWaitForTransactionReceipt } from 'wagmi';
|
|
4
|
+
import { DEX_PRECOMPILES } from '../precompile/addresses';
|
|
5
|
+
import { SWAP_ROUTER_ABI } from '../precompile/abis';
|
|
6
|
+
import { createPoolKey } from '../precompile/types';
|
|
7
|
+
/**
|
|
8
|
+
* Hook to execute swaps via the DEX precompiles
|
|
9
|
+
*/
|
|
10
|
+
export function useSwap() {
|
|
11
|
+
const [error, setError] = useState(null);
|
|
12
|
+
const { data: txHash, writeContractAsync, isPending, reset: resetWrite, } = useWriteContract();
|
|
13
|
+
const { isLoading: isConfirming, isSuccess, } = useWaitForTransactionReceipt({
|
|
14
|
+
hash: txHash,
|
|
15
|
+
});
|
|
16
|
+
const swap = useCallback(async (quote, recipient) => {
|
|
17
|
+
setError(null);
|
|
18
|
+
if (!quote || quote.route.length === 0) {
|
|
19
|
+
setError(new Error('Invalid quote'));
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const step = quote.route[0];
|
|
23
|
+
if (step.source === 'amm') {
|
|
24
|
+
try {
|
|
25
|
+
// Execute AMM swap via precompile
|
|
26
|
+
const poolKey = createPoolKey(quote.tokenIn, quote.tokenOut);
|
|
27
|
+
const zeroForOne = quote.tokenIn.toLowerCase() < quote.tokenOut.toLowerCase();
|
|
28
|
+
await writeContractAsync({
|
|
29
|
+
address: DEX_PRECOMPILES.SWAP_ROUTER,
|
|
30
|
+
abi: SWAP_ROUTER_ABI,
|
|
31
|
+
functionName: 'exactInputSingle',
|
|
32
|
+
args: [{
|
|
33
|
+
poolKey,
|
|
34
|
+
zeroForOne,
|
|
35
|
+
amountIn: quote.amountIn,
|
|
36
|
+
amountOutMinimum: quote.minimumAmountOut,
|
|
37
|
+
sqrtPriceLimitX96: 0n,
|
|
38
|
+
hookData: '0x',
|
|
39
|
+
}],
|
|
40
|
+
// Include native value if swapping from native LUX
|
|
41
|
+
value: quote.tokenIn === '0x0000000000000000000000000000000000000000'
|
|
42
|
+
? quote.amountIn
|
|
43
|
+
: 0n,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
setError(err instanceof Error ? err : new Error('Swap failed'));
|
|
48
|
+
throw err;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else if (step.source === 'clob') {
|
|
52
|
+
// CLOB swaps are handled off-chain
|
|
53
|
+
// The frontend should use the CLOB client directly
|
|
54
|
+
setError(new Error('CLOB swaps should be executed via CLOB client'));
|
|
55
|
+
throw new Error('CLOB swaps not supported in this hook');
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
setError(new Error(`Unknown route source: ${step.source}`));
|
|
59
|
+
throw new Error(`Unknown route source: ${step.source}`);
|
|
60
|
+
}
|
|
61
|
+
}, [writeContractAsync]);
|
|
62
|
+
const reset = useCallback(() => {
|
|
63
|
+
setError(null);
|
|
64
|
+
resetWrite();
|
|
65
|
+
}, [resetWrite]);
|
|
66
|
+
return {
|
|
67
|
+
swap,
|
|
68
|
+
isPending,
|
|
69
|
+
isConfirming,
|
|
70
|
+
isSuccess,
|
|
71
|
+
error,
|
|
72
|
+
txHash,
|
|
73
|
+
reset,
|
|
74
|
+
};
|
|
75
|
+
}
|