@luxfi/dex 1.2.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/dist/client/clob.d.ts +52 -0
  2. package/dist/client/clob.d.ts.map +1 -0
  3. package/dist/client/clob.js +196 -0
  4. package/dist/client/index.d.ts +7 -0
  5. package/dist/client/index.d.ts.map +1 -0
  6. package/dist/client/index.js +6 -0
  7. package/dist/client/types.d.ts +126 -0
  8. package/dist/client/types.d.ts.map +1 -0
  9. package/dist/client/types.js +5 -0
  10. package/dist/hooks/index.d.ts +22 -0
  11. package/dist/hooks/index.d.ts.map +1 -0
  12. package/dist/hooks/index.js +25 -0
  13. package/dist/hooks/use-lxbook.d.ts +95 -0
  14. package/dist/hooks/use-lxbook.d.ts.map +1 -0
  15. package/dist/hooks/use-lxbook.js +213 -0
  16. package/dist/hooks/use-lxfeed.d.ts +111 -0
  17. package/dist/hooks/use-lxfeed.d.ts.map +1 -0
  18. package/dist/hooks/use-lxfeed.js +152 -0
  19. package/dist/hooks/use-lxvault.d.ts +137 -0
  20. package/dist/hooks/use-lxvault.d.ts.map +1 -0
  21. package/dist/hooks/use-lxvault.js +227 -0
  22. package/dist/hooks/use-quote.d.ts +18 -0
  23. package/dist/hooks/use-quote.d.ts.map +1 -0
  24. package/dist/hooks/use-quote.js +65 -0
  25. package/dist/hooks/use-swap.d.ts +17 -0
  26. package/dist/hooks/use-swap.d.ts.map +1 -0
  27. package/dist/hooks/use-swap.js +75 -0
  28. package/dist/index.d.ts +50 -115
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +72 -225
  31. package/dist/precompile/abis.d.ts +991 -0
  32. package/dist/precompile/abis.d.ts.map +1 -0
  33. package/dist/precompile/abis.js +743 -0
  34. package/dist/precompile/addresses.d.ts +129 -0
  35. package/dist/precompile/addresses.d.ts.map +1 -0
  36. package/dist/precompile/addresses.js +117 -0
  37. package/dist/precompile/index.d.ts +19 -0
  38. package/dist/precompile/index.d.ts.map +1 -0
  39. package/dist/precompile/index.js +18 -0
  40. package/dist/precompile/types.d.ts +246 -0
  41. package/dist/precompile/types.d.ts.map +1 -0
  42. package/dist/precompile/types.js +84 -0
  43. package/dist/router/index.d.ts +7 -0
  44. package/dist/router/index.d.ts.map +1 -0
  45. package/dist/router/index.js +6 -0
  46. package/dist/router/router.d.ts +58 -0
  47. package/dist/router/router.d.ts.map +1 -0
  48. package/dist/router/router.js +272 -0
  49. package/dist/router/types.d.ts +76 -0
  50. package/dist/router/types.d.ts.map +1 -0
  51. package/dist/router/types.js +1 -0
  52. package/package.json +55 -29
  53. package/src/client/clob.ts +256 -0
  54. package/src/client/index.ts +6 -0
  55. package/src/client/types.ts +148 -0
  56. package/src/hooks/index.ts +29 -0
  57. package/src/hooks/use-lxbook.ts +343 -0
  58. package/src/hooks/use-lxfeed.ts +179 -0
  59. package/src/hooks/use-lxvault.ts +318 -0
  60. package/src/hooks/use-quote.ts +92 -0
  61. package/src/hooks/use-swap.ts +103 -0
  62. package/src/index.ts +142 -309
  63. package/src/precompile/abis.ts +755 -0
  64. package/src/precompile/addresses.ts +153 -0
  65. package/src/precompile/index.ts +18 -0
  66. package/src/precompile/types.ts +295 -0
  67. package/src/router/index.ts +6 -0
  68. package/src/router/router.ts +338 -0
  69. package/src/router/types.ts +87 -0
  70. package/dist/marketData.d.ts +0 -152
  71. package/dist/marketData.d.ts.map +0 -1
  72. package/dist/marketData.js +0 -253
  73. package/src/marketData.ts +0 -351
  74. package/tsconfig.json +0 -19
@@ -0,0 +1,318 @@
1
+ /**
2
+ * LXVault Hooks (LP-9030)
3
+ * React hooks for custody, margin, and positions via LXVault precompile
4
+ */
5
+ import { useCallback } from 'react'
6
+ import { useReadContract, useWriteContract, useWaitForTransactionReceipt, useAccount } from 'wagmi'
7
+ import type { Address } from 'viem'
8
+ import { LX } from '../precompile/addresses'
9
+ import { LX_VAULT_ABI } from '../precompile/abis'
10
+ import type { LXAccount, LXPosition, LXMarginInfo } from '../precompile/types'
11
+
12
+ /**
13
+ * Build account tuple from address and subaccount
14
+ */
15
+ function buildAccount(main: Address, subaccountId: number = 0): LXAccount {
16
+ return { main, subaccountId }
17
+ }
18
+
19
+ /**
20
+ * Hook to get token balance in vault
21
+ */
22
+ export function useLXVaultBalance(token: Address, subaccountId: number = 0): any {
23
+ const { address } = useAccount()
24
+
25
+ const { data, isLoading, error, refetch } = useReadContract({
26
+ address: LX.LX_VAULT,
27
+ abi: LX_VAULT_ABI,
28
+ functionName: 'getBalance',
29
+ args: address ? [buildAccount(address, subaccountId), token] : undefined,
30
+ query: { enabled: !!address },
31
+ })
32
+
33
+ return {
34
+ balance: data as bigint | undefined,
35
+ isLoading,
36
+ error,
37
+ refetch,
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Hook to get position for a market
43
+ */
44
+ export function useLXVaultPosition(marketId: number, subaccountId: number = 0): any {
45
+ const { address } = useAccount()
46
+
47
+ const { data, isLoading, error, refetch } = useReadContract({
48
+ address: LX.LX_VAULT,
49
+ abi: LX_VAULT_ABI,
50
+ functionName: 'getPosition',
51
+ args: address ? [buildAccount(address, subaccountId), marketId] : undefined,
52
+ query: { enabled: !!address },
53
+ })
54
+
55
+ return {
56
+ position: data as LXPosition | undefined,
57
+ isLoading,
58
+ error,
59
+ refetch,
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Hook to get margin info (free margin, used margin, etc.)
65
+ */
66
+ export function useLXVaultMargin(subaccountId: number = 0): any {
67
+ const { address } = useAccount()
68
+
69
+ const { data, isLoading, error, refetch } = useReadContract({
70
+ address: LX.LX_VAULT,
71
+ abi: LX_VAULT_ABI,
72
+ functionName: 'getMargin',
73
+ args: address ? [buildAccount(address, subaccountId)] : undefined,
74
+ query: { enabled: !!address },
75
+ })
76
+
77
+ return {
78
+ margin: data as LXMarginInfo | undefined,
79
+ isLoading,
80
+ error,
81
+ refetch,
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Hook to check if account is liquidatable
87
+ */
88
+ export function useLXVaultLiquidatable(account?: Address, subaccountId: number = 0): any {
89
+ const { address: connectedAddress } = useAccount()
90
+ const targetAddress = account ?? connectedAddress
91
+
92
+ const { data, isLoading, error, refetch } = useReadContract({
93
+ address: LX.LX_VAULT,
94
+ abi: LX_VAULT_ABI,
95
+ functionName: 'isLiquidatable',
96
+ args: targetAddress ? [buildAccount(targetAddress, subaccountId)] : undefined,
97
+ query: { enabled: !!targetAddress },
98
+ })
99
+
100
+ const result = data as [boolean, bigint] | undefined
101
+
102
+ return {
103
+ liquidatable: result?.[0],
104
+ shortfall: result?.[1],
105
+ isLoading,
106
+ error,
107
+ refetch,
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Hook to get funding rate for a market
113
+ */
114
+ export function useLXVaultFundingRate(marketId: number): any {
115
+ const { data, isLoading, error, refetch } = useReadContract({
116
+ address: LX.LX_VAULT,
117
+ abi: LX_VAULT_ABI,
118
+ functionName: 'getFundingRate',
119
+ args: [marketId],
120
+ })
121
+
122
+ const result = data as [bigint, bigint] | undefined
123
+
124
+ return {
125
+ rateX18: result?.[0],
126
+ nextFundingTime: result?.[1],
127
+ isLoading,
128
+ error,
129
+ refetch,
130
+ }
131
+ }
132
+
133
+ interface UseLXVaultDepositResult {
134
+ deposit: (token: Address, amount: bigint, subaccountId?: number) => void
135
+ hash: `0x${string}` | undefined
136
+ isPending: boolean
137
+ isConfirming: boolean
138
+ isSuccess: boolean
139
+ error: Error | null
140
+ }
141
+
142
+ /**
143
+ * Hook for depositing tokens into vault
144
+ */
145
+ export function useLXVaultDeposit(): UseLXVaultDepositResult {
146
+ const { writeContract, data: hash, isPending, error } = useWriteContract()
147
+ const { isLoading: isConfirming, isSuccess } = useWaitForTransactionReceipt({ hash })
148
+
149
+ const deposit = useCallback(
150
+ (token: Address, amount: bigint, subaccountId: number = 0) => {
151
+ writeContract({
152
+ address: LX.LX_VAULT,
153
+ abi: LX_VAULT_ABI,
154
+ functionName: 'deposit',
155
+ args: [token, amount, subaccountId],
156
+ })
157
+ },
158
+ [writeContract]
159
+ )
160
+
161
+ return {
162
+ deposit,
163
+ hash,
164
+ isPending,
165
+ isConfirming,
166
+ isSuccess,
167
+ error,
168
+ }
169
+ }
170
+
171
+ interface UseLXVaultWithdrawResult {
172
+ withdraw: (token: Address, amount: bigint, subaccountId?: number) => void
173
+ hash: `0x${string}` | undefined
174
+ isPending: boolean
175
+ isConfirming: boolean
176
+ isSuccess: boolean
177
+ error: Error | null
178
+ }
179
+
180
+ /**
181
+ * Hook for withdrawing tokens from vault
182
+ */
183
+ export function useLXVaultWithdraw(): UseLXVaultWithdrawResult {
184
+ const { writeContract, data: hash, isPending, error } = useWriteContract()
185
+ const { isLoading: isConfirming, isSuccess } = useWaitForTransactionReceipt({ hash })
186
+
187
+ const withdraw = useCallback(
188
+ (token: Address, amount: bigint, subaccountId: number = 0) => {
189
+ writeContract({
190
+ address: LX.LX_VAULT,
191
+ abi: LX_VAULT_ABI,
192
+ functionName: 'withdraw',
193
+ args: [token, amount, subaccountId],
194
+ })
195
+ },
196
+ [writeContract]
197
+ )
198
+
199
+ return {
200
+ withdraw,
201
+ hash,
202
+ isPending,
203
+ isConfirming,
204
+ isSuccess,
205
+ error,
206
+ }
207
+ }
208
+
209
+ interface UseLXVaultTransferResult {
210
+ transfer: (token: Address, amount: bigint, fromSubaccount: number, toSubaccount: number) => void
211
+ hash: `0x${string}` | undefined
212
+ isPending: boolean
213
+ isConfirming: boolean
214
+ isSuccess: boolean
215
+ error: Error | null
216
+ }
217
+
218
+ /**
219
+ * Hook for transferring between subaccounts
220
+ */
221
+ export function useLXVaultTransfer(): UseLXVaultTransferResult {
222
+ const { writeContract, data: hash, isPending, error } = useWriteContract()
223
+ const { isLoading: isConfirming, isSuccess } = useWaitForTransactionReceipt({ hash })
224
+
225
+ const transfer = useCallback(
226
+ (
227
+ token: Address,
228
+ amount: bigint,
229
+ fromSubaccount: number,
230
+ toSubaccount: number
231
+ ) => {
232
+ writeContract({
233
+ address: LX.LX_VAULT,
234
+ abi: LX_VAULT_ABI,
235
+ functionName: 'transfer',
236
+ args: [token, amount, fromSubaccount, toSubaccount],
237
+ })
238
+ },
239
+ [writeContract]
240
+ )
241
+
242
+ return {
243
+ transfer,
244
+ hash,
245
+ isPending,
246
+ isConfirming,
247
+ isSuccess,
248
+ error,
249
+ }
250
+ }
251
+
252
+ interface UseLXVaultLiquidateResult {
253
+ liquidate: (targetAccount: Address, targetSubaccount: number, marketId: number, sizeX18: bigint) => void
254
+ hash: `0x${string}` | undefined
255
+ isPending: boolean
256
+ isConfirming: boolean
257
+ isSuccess: boolean
258
+ error: Error | null
259
+ }
260
+
261
+ /**
262
+ * Hook for liquidating underwater positions
263
+ */
264
+ export function useLXVaultLiquidate(): UseLXVaultLiquidateResult {
265
+ const { writeContract, data: hash, isPending, error } = useWriteContract()
266
+ const { isLoading: isConfirming, isSuccess } = useWaitForTransactionReceipt({ hash })
267
+
268
+ const liquidate = useCallback(
269
+ (
270
+ targetAccount: Address,
271
+ targetSubaccount: number,
272
+ marketId: number,
273
+ sizeX18: bigint
274
+ ) => {
275
+ writeContract({
276
+ address: LX.LX_VAULT,
277
+ abi: LX_VAULT_ABI,
278
+ functionName: 'liquidate',
279
+ args: [buildAccount(targetAccount, targetSubaccount), marketId, sizeX18],
280
+ })
281
+ },
282
+ [writeContract]
283
+ )
284
+
285
+ return {
286
+ liquidate,
287
+ hash,
288
+ isPending,
289
+ isConfirming,
290
+ isSuccess,
291
+ error,
292
+ }
293
+ }
294
+
295
+ /**
296
+ * Combined hook for common vault operations
297
+ */
298
+ export function useLXVault(subaccountId: number = 0): any {
299
+ const { address } = useAccount()
300
+ const margin = useLXVaultMargin(subaccountId)
301
+ const { deposit, isPending: isDepositing } = useLXVaultDeposit()
302
+ const { withdraw, isPending: isWithdrawing } = useLXVaultWithdraw()
303
+ const { transfer, isPending: isTransferring } = useLXVaultTransfer()
304
+
305
+ return {
306
+ address,
307
+ subaccountId,
308
+ margin: margin.margin,
309
+ isLoadingMargin: margin.isLoading,
310
+ deposit,
311
+ withdraw,
312
+ transfer,
313
+ isDepositing,
314
+ isWithdrawing,
315
+ isTransferring,
316
+ refetchMargin: margin.refetch,
317
+ }
318
+ }
@@ -0,0 +1,92 @@
1
+ 'use client'
2
+
3
+ import { useState, useCallback, useEffect, useRef } from 'react'
4
+ import type { Address } from 'viem'
5
+ import { usePublicClient } from 'wagmi'
6
+ import { OmnichainRouter, type Quote, type QuoteRequest } from '../router'
7
+
8
+ interface UseQuoteOptions {
9
+ refreshInterval?: number // ms
10
+ enabled?: boolean
11
+ }
12
+
13
+ interface UseQuoteResult {
14
+ quote: Quote | null
15
+ isLoading: boolean
16
+ error: Error | null
17
+ refetch: () => Promise<void>
18
+ }
19
+
20
+ /**
21
+ * Hook to get swap quotes from the omnichain router
22
+ */
23
+ export function useQuote(
24
+ tokenIn: Address | undefined,
25
+ tokenOut: Address | undefined,
26
+ amountIn: bigint | undefined,
27
+ options: UseQuoteOptions = {}
28
+ ): UseQuoteResult {
29
+ const { refreshInterval = 10000, enabled = true } = options
30
+ const publicClient = usePublicClient()
31
+ const routerRef = useRef<OmnichainRouter | null>(null)
32
+
33
+ const [quote, setQuote] = useState<Quote | null>(null)
34
+ const [isLoading, setIsLoading] = useState(false)
35
+ const [error, setError] = useState<Error | null>(null)
36
+
37
+ // Initialize router
38
+ useEffect(() => {
39
+ if (!routerRef.current) {
40
+ routerRef.current = new OmnichainRouter()
41
+ }
42
+ if (publicClient) {
43
+ routerRef.current.setPublicClient(publicClient)
44
+ }
45
+ }, [publicClient])
46
+
47
+ const fetchQuote = useCallback(async () => {
48
+ if (!tokenIn || !tokenOut || !amountIn || amountIn === 0n || !enabled) {
49
+ setQuote(null)
50
+ return
51
+ }
52
+
53
+ setIsLoading(true)
54
+ setError(null)
55
+
56
+ try {
57
+ const request: QuoteRequest = {
58
+ tokenIn,
59
+ tokenOut,
60
+ amountIn,
61
+ }
62
+
63
+ const newQuote = await routerRef.current!.getQuote(request)
64
+ setQuote(newQuote)
65
+ } catch (err) {
66
+ setError(err instanceof Error ? err : new Error('Failed to get quote'))
67
+ setQuote(null)
68
+ } finally {
69
+ setIsLoading(false)
70
+ }
71
+ }, [tokenIn, tokenOut, amountIn, enabled])
72
+
73
+ // Fetch on mount and when inputs change
74
+ useEffect(() => {
75
+ fetchQuote()
76
+ }, [fetchQuote])
77
+
78
+ // Auto-refresh
79
+ useEffect(() => {
80
+ if (!enabled || refreshInterval <= 0) return
81
+
82
+ const interval = setInterval(fetchQuote, refreshInterval)
83
+ return () => clearInterval(interval)
84
+ }, [fetchQuote, enabled, refreshInterval])
85
+
86
+ return {
87
+ quote,
88
+ isLoading,
89
+ error,
90
+ refetch: fetchQuote,
91
+ }
92
+ }
@@ -0,0 +1,103 @@
1
+ 'use client'
2
+
3
+ import { useState, useCallback } from 'react'
4
+ import type { Address } from 'viem'
5
+ import { useWriteContract, useWaitForTransactionReceipt } from 'wagmi'
6
+ import { DEX_PRECOMPILES } from '../precompile/addresses'
7
+ import { SWAP_ROUTER_ABI } from '../precompile/abis'
8
+ import { createPoolKey } from '../precompile/types'
9
+ import type { Quote } from '../router'
10
+
11
+ interface UseSwapResult {
12
+ swap: (quote: Quote, recipient: Address) => Promise<void>
13
+ isPending: boolean
14
+ isConfirming: boolean
15
+ isSuccess: boolean
16
+ error: Error | null
17
+ txHash: `0x${string}` | undefined
18
+ reset: () => void
19
+ }
20
+
21
+ /**
22
+ * Hook to execute swaps via the DEX precompiles
23
+ */
24
+ export function useSwap(): UseSwapResult {
25
+ const [error, setError] = useState<Error | null>(null)
26
+
27
+ const {
28
+ data: txHash,
29
+ writeContractAsync,
30
+ isPending,
31
+ reset: resetWrite,
32
+ } = useWriteContract()
33
+
34
+ const {
35
+ isLoading: isConfirming,
36
+ isSuccess,
37
+ } = useWaitForTransactionReceipt({
38
+ hash: txHash,
39
+ })
40
+
41
+ const swap = useCallback(async (quote: Quote, recipient: Address) => {
42
+ setError(null)
43
+
44
+ if (!quote || quote.route.length === 0) {
45
+ setError(new Error('Invalid quote'))
46
+ return
47
+ }
48
+
49
+ const step = quote.route[0]
50
+
51
+ if (step.source === 'amm') {
52
+ try {
53
+ // Execute AMM swap via precompile
54
+ const poolKey = createPoolKey(quote.tokenIn, quote.tokenOut)
55
+ const zeroForOne = quote.tokenIn.toLowerCase() < quote.tokenOut.toLowerCase()
56
+
57
+ await writeContractAsync({
58
+ address: DEX_PRECOMPILES.SWAP_ROUTER,
59
+ abi: SWAP_ROUTER_ABI,
60
+ functionName: 'exactInputSingle',
61
+ args: [{
62
+ poolKey,
63
+ zeroForOne,
64
+ amountIn: quote.amountIn,
65
+ amountOutMinimum: quote.minimumAmountOut,
66
+ sqrtPriceLimitX96: 0n,
67
+ hookData: '0x',
68
+ }],
69
+ // Include native value if swapping from native LUX
70
+ value: quote.tokenIn === '0x0000000000000000000000000000000000000000'
71
+ ? quote.amountIn
72
+ : 0n,
73
+ })
74
+ } catch (err) {
75
+ setError(err instanceof Error ? err : new Error('Swap failed'))
76
+ throw err
77
+ }
78
+ } else if (step.source === 'clob') {
79
+ // CLOB swaps are handled off-chain
80
+ // The frontend should use the CLOB client directly
81
+ setError(new Error('CLOB swaps should be executed via CLOB client'))
82
+ throw new Error('CLOB swaps not supported in this hook')
83
+ } else {
84
+ setError(new Error(`Unknown route source: ${step.source}`))
85
+ throw new Error(`Unknown route source: ${step.source}`)
86
+ }
87
+ }, [writeContractAsync])
88
+
89
+ const reset = useCallback(() => {
90
+ setError(null)
91
+ resetWrite()
92
+ }, [resetWrite])
93
+
94
+ return {
95
+ swap,
96
+ isPending,
97
+ isConfirming,
98
+ isSuccess,
99
+ error,
100
+ txHash,
101
+ reset,
102
+ }
103
+ }