@sodax/dapp-kit 1.3.1-beta-rc2 → 1.3.1-beta

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 (38) hide show
  1. package/README.md +36 -0
  2. package/dist/index.d.mts +650 -12
  3. package/dist/index.d.ts +650 -12
  4. package/dist/index.js +741 -62
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +720 -62
  7. package/dist/index.mjs.map +1 -1
  8. package/package.json +3 -3
  9. package/src/hooks/backend/index.ts +4 -0
  10. package/src/hooks/backend/useBackendSubmitSwapTx.ts +55 -0
  11. package/src/hooks/backend/useBackendSubmitSwapTxStatus.ts +79 -0
  12. package/src/hooks/bitcoin/index.ts +1 -0
  13. package/src/hooks/bitcoin/useRadfiAuth.ts +7 -25
  14. package/src/hooks/bitcoin/useRadfiSession.ts +25 -47
  15. package/src/hooks/bitcoin/useRadfiWithdraw.ts +85 -0
  16. package/src/hooks/bitcoin/useRenewUtxos.ts +1 -1
  17. package/src/hooks/dex/index.ts +16 -0
  18. package/src/hooks/dex/useClaimRewards.ts +68 -0
  19. package/src/hooks/dex/useCreateDecreaseLiquidityParams.ts +41 -0
  20. package/src/hooks/dex/useCreateDepositParams.ts +43 -0
  21. package/src/hooks/dex/useCreateSupplyLiquidityParams.ts +84 -0
  22. package/src/hooks/dex/useCreateWithdrawParams.ts +44 -0
  23. package/src/hooks/dex/useDecreaseLiquidity.ts +78 -0
  24. package/src/hooks/dex/useDexAllowance.ts +87 -0
  25. package/src/hooks/dex/useDexApprove.ts +55 -0
  26. package/src/hooks/dex/useDexDeposit.ts +64 -0
  27. package/src/hooks/dex/useDexWithdraw.ts +54 -0
  28. package/src/hooks/dex/useLiquidityAmounts.ts +187 -0
  29. package/src/hooks/dex/usePoolBalances.ts +90 -0
  30. package/src/hooks/dex/usePoolData.ts +57 -0
  31. package/src/hooks/dex/usePools.ts +48 -0
  32. package/src/hooks/dex/usePositionInfo.ts +88 -0
  33. package/src/hooks/dex/useSupplyLiquidity.ts +91 -0
  34. package/src/hooks/index.ts +1 -0
  35. package/src/index.ts +1 -0
  36. package/src/utils/dex-utils.ts +177 -0
  37. package/src/utils/index.ts +1 -0
  38. package/src/hooks/bitcoin/radfiConstants.ts +0 -2
package/dist/index.js CHANGED
@@ -220,12 +220,6 @@ function useSpokeProvider(spokeChainId, walletProvider) {
220
220
  }, [spokeChainId, xChainType, walletProvider, rpcConfig]);
221
221
  return spokeProvider;
222
222
  }
223
-
224
- // src/hooks/bitcoin/radfiConstants.ts
225
- var ACCESS_TOKEN_TTL = 10 * 60 * 1e3;
226
- var REFRESH_TOKEN_TTL = 7 * 24 * 60 * 60 * 1e3;
227
-
228
- // src/hooks/bitcoin/useRadfiAuth.ts
229
223
  var SESSION_KEY = (address) => `radfi_session_${address}`;
230
224
  function saveRadfiSession(address, session) {
231
225
  try {
@@ -247,16 +241,6 @@ function clearRadfiSession(address) {
247
241
  } catch {
248
242
  }
249
243
  }
250
- function isAccessTokenExpired(address) {
251
- const session = loadRadfiSession(address);
252
- if (!session) return true;
253
- return Date.now() >= session.accessTokenExpiry;
254
- }
255
- function isRefreshTokenExpired(address) {
256
- const session = loadRadfiSession(address);
257
- if (!session) return true;
258
- return Date.now() >= session.refreshTokenExpiry;
259
- }
260
244
  function useRadfiAuth(spokeProvider) {
261
245
  return reactQuery.useMutation({
262
246
  mutationFn: async () => {
@@ -272,27 +256,25 @@ function useRadfiAuth(spokeProvider) {
272
256
  accessToken,
273
257
  refreshToken,
274
258
  tradingAddress,
275
- publicKey,
276
- accessTokenExpiry: Date.now() + ACCESS_TOKEN_TTL,
277
- refreshTokenExpiry: Date.now() + REFRESH_TOKEN_TTL
259
+ publicKey
278
260
  };
279
261
  saveRadfiSession(walletAddress, session);
280
262
  return { accessToken, refreshToken, tradingAddress };
281
263
  } catch (err) {
282
264
  const isAlreadyRegistered = err instanceof Error && (err.message.includes("duplicatedPubKey") || err.message.includes("4008"));
283
- if (isAlreadyRegistered) {
284
- if (existingSession && !isRefreshTokenExpired(walletAddress)) {
265
+ if (isAlreadyRegistered && existingSession?.refreshToken) {
266
+ try {
285
267
  const refreshed = await spokeProvider.radfi.refreshAccessToken(existingSession.refreshToken);
286
268
  const session = {
287
269
  ...existingSession,
288
270
  accessToken: refreshed.accessToken,
289
- refreshToken: refreshed.refreshToken,
290
- accessTokenExpiry: Date.now() + ACCESS_TOKEN_TTL,
291
- refreshTokenExpiry: Date.now() + REFRESH_TOKEN_TTL
271
+ refreshToken: refreshed.refreshToken
292
272
  };
293
- spokeProvider.setRadfiAccessToken(refreshed.accessToken);
273
+ spokeProvider.setRadfiAccessToken(refreshed.accessToken, refreshed.refreshToken);
294
274
  saveRadfiSession(walletAddress, session);
295
275
  return { accessToken: refreshed.accessToken, refreshToken: refreshed.refreshToken, tradingAddress: existingSession.tradingAddress };
276
+ } catch {
277
+ clearRadfiSession(walletAddress);
296
278
  }
297
279
  throw new Error(
298
280
  "This wallet is already registered with Radfi from another session. Please clear your browser storage for this site and try again, or wait for the previous session to expire."
@@ -303,7 +285,7 @@ function useRadfiAuth(spokeProvider) {
303
285
  }
304
286
  });
305
287
  }
306
- var POLL_INTERVAL = 3e4;
288
+ var REFRESH_INTERVAL = 5 * 60 * 1e3;
307
289
  function useRadfiSession(spokeProvider) {
308
290
  const [walletAddress, setWalletAddress] = React.useState();
309
291
  const [isAuthed, setIsAuthed] = React.useState(false);
@@ -322,17 +304,15 @@ function useRadfiSession(spokeProvider) {
322
304
  const updated = {
323
305
  ...session,
324
306
  accessToken,
325
- refreshToken,
326
- accessTokenExpiry: Date.now() + ACCESS_TOKEN_TTL
327
- // Keep the original refreshTokenExpiry — don't roll it forward on every silent refresh
307
+ refreshToken
328
308
  };
329
309
  saveRadfiSession(address, updated);
330
- spokeProvider.setRadfiAccessToken(accessToken);
310
+ spokeProvider.setRadfiAccessToken(accessToken, refreshToken);
331
311
  setIsAuthed(true);
332
312
  setTradingAddress(updated.tradingAddress || void 0);
333
313
  } catch {
334
314
  clearRadfiSession(address);
335
- spokeProvider.setRadfiAccessToken("");
315
+ spokeProvider.setRadfiAccessToken("", "");
336
316
  setIsAuthed(false);
337
317
  setTradingAddress(void 0);
338
318
  } finally {
@@ -341,39 +321,22 @@ function useRadfiSession(spokeProvider) {
341
321
  }, [spokeProvider]);
342
322
  React.useEffect(() => {
343
323
  if (!spokeProvider) return;
344
- const fetchAndRestore = () => {
345
- spokeProvider.walletProvider.getWalletAddress().then((addr) => {
346
- setWalletAddress(addr);
347
- const session = loadRadfiSession(addr);
348
- if (!session || isRefreshTokenExpired(addr)) return;
349
- if (!isAccessTokenExpired(addr)) {
350
- spokeProvider.setRadfiAccessToken(session.accessToken);
351
- setIsAuthed(true);
352
- setTradingAddress(session.tradingAddress || void 0);
353
- } else {
354
- silentRefresh(addr);
355
- }
356
- }).catch(() => {
357
- });
358
- };
359
- fetchAndRestore();
360
- const id = setInterval(fetchAndRestore, 3e3);
361
- return () => clearInterval(id);
324
+ setIsAuthed(false);
325
+ setTradingAddress(void 0);
326
+ setWalletAddress(void 0);
327
+ spokeProvider.walletProvider.getWalletAddress().then((addr) => {
328
+ setWalletAddress(addr);
329
+ const session = loadRadfiSession(addr);
330
+ if (!session?.refreshToken) return;
331
+ silentRefresh(addr);
332
+ }).catch(() => {
333
+ });
362
334
  }, [spokeProvider, silentRefresh]);
363
335
  React.useEffect(() => {
364
336
  if (!walletAddress || !spokeProvider) return;
365
337
  const id = setInterval(() => {
366
- if (isRefreshTokenExpired(walletAddress)) {
367
- clearRadfiSession(walletAddress);
368
- spokeProvider.setRadfiAccessToken("");
369
- setIsAuthed(false);
370
- setTradingAddress(void 0);
371
- return;
372
- }
373
- if (isAccessTokenExpired(walletAddress)) {
374
- silentRefresh(walletAddress);
375
- }
376
- }, POLL_INTERVAL);
338
+ silentRefresh(walletAddress);
339
+ }, REFRESH_INTERVAL);
377
340
  return () => clearInterval(id);
378
341
  }, [walletAddress, spokeProvider, silentRefresh]);
379
342
  const { mutateAsync: loginMutate, isPending: isLoginPending } = useRadfiAuth(spokeProvider);
@@ -472,6 +435,41 @@ function useRenewUtxos(spokeProvider) {
472
435
  }
473
436
  });
474
437
  }
438
+ function useRadfiWithdraw(spokeProvider) {
439
+ const queryClient = reactQuery.useQueryClient();
440
+ return reactQuery.useMutation({
441
+ mutationFn: async ({ amount, tokenId, withdrawTo }) => {
442
+ if (!spokeProvider) {
443
+ throw new Error("Bitcoin spoke provider not found");
444
+ }
445
+ const userAddress = await spokeProvider.walletProvider.getWalletAddress();
446
+ const session = loadRadfiSession(userAddress);
447
+ const accessToken = session?.accessToken || spokeProvider.radfiAccessToken;
448
+ if (!accessToken) {
449
+ throw new Error("Radfi authentication required. Please login first.");
450
+ }
451
+ const buildResult = await spokeProvider.radfi.withdrawToUser(
452
+ { userAddress, amount, tokenId, withdrawTo },
453
+ accessToken
454
+ );
455
+ const signedTx = await spokeProvider.walletProvider.signTransaction(
456
+ buildResult.base64Psbt,
457
+ false
458
+ );
459
+ const signedBase64Tx = sdk.normalizePsbtToBase64(signedTx);
460
+ const txId = await spokeProvider.radfi.signAndBroadcastWithdraw(
461
+ { userAddress, signedBase64Tx },
462
+ accessToken
463
+ );
464
+ return { txId, fee: buildResult.fee.totalFee };
465
+ },
466
+ onSuccess: () => {
467
+ queryClient.invalidateQueries({ queryKey: ["trading-wallet-balance"] });
468
+ queryClient.invalidateQueries({ queryKey: ["btc-balance"] });
469
+ queryClient.invalidateQueries({ queryKey: ["xBalances"] });
470
+ }
471
+ });
472
+ }
475
473
  function useBorrow() {
476
474
  const { sodax } = useSodaxContext();
477
475
  return reactQuery.useMutation({
@@ -991,6 +989,54 @@ var useBackendUserIntents = ({
991
989
  }
992
990
  });
993
991
  };
992
+ var useBackendSubmitSwapTx = (params) => {
993
+ const { sodax } = useSodaxContext();
994
+ const defaultMutationOptions = {
995
+ retry: 3
996
+ };
997
+ const mutationOptions = {
998
+ ...defaultMutationOptions,
999
+ ...params?.mutationOptions
1000
+ };
1001
+ return reactQuery.useMutation({
1002
+ ...mutationOptions,
1003
+ mutationFn: async (request) => {
1004
+ return sodax.backendApi.submitSwapTx(request, params?.apiConfig);
1005
+ }
1006
+ });
1007
+ };
1008
+ var useBackendSubmitSwapTxStatus = (params) => {
1009
+ const { sodax } = useSodaxContext();
1010
+ const defaultQueryOptions = {
1011
+ queryKey: ["api", "swaps", "submit-tx", "status", params?.params?.txHash, params?.params?.srcChainId],
1012
+ enabled: !!params?.params?.txHash && params.params.txHash.length > 0,
1013
+ retry: 3,
1014
+ refetchInterval: (query) => {
1015
+ const status = query.state.data?.data?.status;
1016
+ if (status === "executed" || status === "failed") return false;
1017
+ return 1e3;
1018
+ }
1019
+ };
1020
+ const queryOptions = {
1021
+ ...defaultQueryOptions,
1022
+ ...params?.queryOptions
1023
+ };
1024
+ return reactQuery.useQuery({
1025
+ ...queryOptions,
1026
+ queryFn: async () => {
1027
+ if (!params?.params?.txHash) {
1028
+ return void 0;
1029
+ }
1030
+ return sodax.backendApi.getSubmitSwapTxStatus(
1031
+ {
1032
+ txHash: params.params.txHash,
1033
+ srcChainId: params.params.srcChainId
1034
+ },
1035
+ params.apiConfig
1036
+ );
1037
+ }
1038
+ });
1039
+ };
994
1040
  var useBackendOrderbook = (params) => {
995
1041
  const { sodax } = useSodaxContext();
996
1042
  const defaultQueryOptions = {
@@ -1780,6 +1826,618 @@ function useMigrationApprove(params, spokeProvider) {
1780
1826
  isApproved
1781
1827
  };
1782
1828
  }
1829
+ function usePools(params) {
1830
+ const { sodax } = useSodaxContext();
1831
+ const defaultQueryOptions = {
1832
+ queryKey: ["dex", "pools"],
1833
+ staleTime: Number.POSITIVE_INFINITY
1834
+ // Pools list is static, cache indefinitely
1835
+ };
1836
+ const queryOptions = { ...defaultQueryOptions, ...params?.queryOptions };
1837
+ return reactQuery.useQuery({
1838
+ ...queryOptions,
1839
+ queryFn: async () => {
1840
+ return sodax.dex.clService.getPools();
1841
+ }
1842
+ });
1843
+ }
1844
+ function usePoolData({
1845
+ poolKey,
1846
+ queryOptions = {
1847
+ queryKey: ["dex", "poolData", poolKey],
1848
+ enabled: poolKey !== null,
1849
+ staleTime: 1e4,
1850
+ refetchInterval: 3e4
1851
+ }
1852
+ }) {
1853
+ const { sodax } = useSodaxContext();
1854
+ return reactQuery.useQuery({
1855
+ ...queryOptions,
1856
+ queryFn: async () => {
1857
+ if (!poolKey) {
1858
+ throw new Error("Pool key is required");
1859
+ }
1860
+ return await sodax.dex.clService.getPoolData(poolKey, sodax.hubProvider.publicClient);
1861
+ },
1862
+ enabled: poolKey !== null
1863
+ });
1864
+ }
1865
+ function usePoolBalances({
1866
+ poolData,
1867
+ poolKey,
1868
+ spokeProvider,
1869
+ enabled = true,
1870
+ queryOptions = {
1871
+ queryKey: [
1872
+ "dex",
1873
+ "poolBalances",
1874
+ poolData?.poolKey,
1875
+ spokeProvider?.chainConfig.chain.id
1876
+ ],
1877
+ enabled: enabled && poolData !== null && poolKey !== null && spokeProvider !== null,
1878
+ staleTime: 5e3,
1879
+ // Consider data stale after 5 seconds
1880
+ refetchInterval: 1e4
1881
+ // Refetch every 10 seconds
1882
+ }
1883
+ }) {
1884
+ const { sodax } = useSodaxContext();
1885
+ return reactQuery.useQuery({
1886
+ ...queryOptions,
1887
+ queryFn: async () => {
1888
+ if (!poolData || !spokeProvider || !poolKey) {
1889
+ throw new Error("Pool data, pool key, and spoke provider are required");
1890
+ }
1891
+ const [balance0, balance1] = await Promise.all([
1892
+ sodax.dex.assetService.getDeposit(poolData.token0.address, spokeProvider),
1893
+ sodax.dex.assetService.getDeposit(poolData.token1.address, spokeProvider)
1894
+ ]);
1895
+ return {
1896
+ token0Balance: balance0,
1897
+ token1Balance: balance1
1898
+ };
1899
+ }
1900
+ });
1901
+ }
1902
+ function usePositionInfo({
1903
+ tokenId,
1904
+ poolKey,
1905
+ queryOptions = {
1906
+ queryKey: ["dex", "positionInfo", tokenId, poolKey],
1907
+ enabled: tokenId !== null && poolKey !== null && tokenId !== "",
1908
+ staleTime: 1e4
1909
+ // Consider data stale after 10 seconds
1910
+ }
1911
+ }) {
1912
+ const { sodax } = useSodaxContext();
1913
+ return reactQuery.useQuery({
1914
+ queryFn: async () => {
1915
+ if (!tokenId || !poolKey) {
1916
+ throw new Error("Token ID and pool key are required");
1917
+ }
1918
+ const tokenIdBigInt = BigInt(tokenId);
1919
+ const publicClient = sodax.hubProvider.publicClient;
1920
+ const info = await sodax.dex.clService.getPositionInfo(tokenIdBigInt, publicClient);
1921
+ const isValid = info.poolKey.currency0.toLowerCase() === poolKey.currency0.toLowerCase() && info.poolKey.currency1.toLowerCase() === poolKey.currency1.toLowerCase() && info.poolKey.fee === poolKey.fee;
1922
+ return {
1923
+ positionInfo: info,
1924
+ isValid
1925
+ };
1926
+ },
1927
+ ...queryOptions
1928
+ });
1929
+ }
1930
+ function useDexDeposit() {
1931
+ const { sodax } = useSodaxContext();
1932
+ const queryClient = reactQuery.useQueryClient();
1933
+ return reactQuery.useMutation({
1934
+ mutationFn: async ({ params, spokeProvider }) => {
1935
+ if (!spokeProvider) {
1936
+ throw new Error("Spoke provider is required");
1937
+ }
1938
+ if (!params) {
1939
+ throw new Error("Deposit params are required");
1940
+ }
1941
+ const depositResult = await sodax.dex.assetService.deposit({
1942
+ params,
1943
+ spokeProvider
1944
+ });
1945
+ if (!depositResult.ok) {
1946
+ throw new Error(`Deposit failed: ${depositResult.error?.code || "Unknown error"}`);
1947
+ }
1948
+ return depositResult.value;
1949
+ },
1950
+ onSuccess: () => {
1951
+ queryClient.invalidateQueries({ queryKey: ["dex", "poolBalances"] });
1952
+ }
1953
+ });
1954
+ }
1955
+ function useDexWithdraw() {
1956
+ const { sodax } = useSodaxContext();
1957
+ const queryClient = reactQuery.useQueryClient();
1958
+ return reactQuery.useMutation({
1959
+ mutationFn: async ({ params, spokeProvider }) => {
1960
+ if (!spokeProvider) {
1961
+ throw new Error("Spoke provider is required");
1962
+ }
1963
+ const withdrawResult = await sodax.dex.assetService.withdraw({
1964
+ params,
1965
+ spokeProvider
1966
+ });
1967
+ if (!withdrawResult.ok) {
1968
+ throw new Error(`Withdraw failed: ${withdrawResult.error.code}`);
1969
+ }
1970
+ return withdrawResult.value;
1971
+ },
1972
+ onSuccess: () => {
1973
+ queryClient.invalidateQueries({ queryKey: ["dex", "poolBalances"] });
1974
+ }
1975
+ });
1976
+ }
1977
+ function useDexAllowance({
1978
+ params,
1979
+ spokeProvider,
1980
+ queryOptions = {
1981
+ queryKey: [
1982
+ "dex",
1983
+ "allowance",
1984
+ params?.asset,
1985
+ params?.poolToken,
1986
+ params?.amount.toString(),
1987
+ spokeProvider?.chainConfig.chain.id
1988
+ ],
1989
+ enabled: !!params && !!spokeProvider
1990
+ }
1991
+ }) {
1992
+ const { sodax } = useSodaxContext();
1993
+ return reactQuery.useQuery({
1994
+ ...queryOptions,
1995
+ queryFn: async () => {
1996
+ if (!params || !spokeProvider) {
1997
+ throw new Error("Params and spoke provider are required");
1998
+ }
1999
+ const allowanceResult = await sodax.dex.assetService.isAllowanceValid({
2000
+ params: {
2001
+ asset: params.asset,
2002
+ amount: params.amount,
2003
+ poolToken: params.poolToken
2004
+ },
2005
+ spokeProvider
2006
+ });
2007
+ if (!allowanceResult.ok) {
2008
+ return false;
2009
+ }
2010
+ return allowanceResult.value;
2011
+ }
2012
+ });
2013
+ }
2014
+ function useDexApprove() {
2015
+ const { sodax } = useSodaxContext();
2016
+ const queryClient = reactQuery.useQueryClient();
2017
+ return reactQuery.useMutation({
2018
+ mutationFn: async ({ params, spokeProvider }) => {
2019
+ const approveResult = await sodax.dex.assetService.approve({
2020
+ params,
2021
+ spokeProvider,
2022
+ raw: false
2023
+ });
2024
+ if (!approveResult.ok) {
2025
+ throw new Error("Approval failed");
2026
+ }
2027
+ return approveResult.value;
2028
+ },
2029
+ onSuccess: () => {
2030
+ queryClient.invalidateQueries({ queryKey: ["dex", "allowance"] });
2031
+ }
2032
+ });
2033
+ }
2034
+ function useLiquidityAmounts(minPrice, maxPrice, poolData) {
2035
+ const [liquidityToken0Amount, setLiquidityToken0Amount] = React.useState("");
2036
+ const [liquidityToken1Amount, setLiquidityToken1Amount] = React.useState("");
2037
+ const [lastEditedToken, setLastEditedToken] = React.useState(null);
2038
+ const { minPriceNum, maxPriceNum, isValidPriceRange } = React.useMemo(() => {
2039
+ const parsedMin = Number.parseFloat(minPrice);
2040
+ const parsedMax = Number.parseFloat(maxPrice);
2041
+ const isValid = parsedMin > 0 && parsedMax > 0 && parsedMin < parsedMax;
2042
+ return {
2043
+ minPriceNum: parsedMin,
2044
+ maxPriceNum: parsedMax,
2045
+ isValidPriceRange: isValid
2046
+ };
2047
+ }, [minPrice, maxPrice]);
2048
+ const { tickLower, tickUpper, currentTick } = React.useMemo(() => {
2049
+ if (!poolData || !isValidPriceRange) {
2050
+ return {
2051
+ tickLower: null,
2052
+ tickUpper: null,
2053
+ currentTick: null
2054
+ };
2055
+ }
2056
+ try {
2057
+ const lower = sdk.ClService.priceToTick(minPriceNum, poolData.token0, poolData.token1, poolData.tickSpacing);
2058
+ const upper = sdk.ClService.priceToTick(maxPriceNum, poolData.token0, poolData.token1, poolData.tickSpacing);
2059
+ return {
2060
+ tickLower: lower,
2061
+ tickUpper: upper,
2062
+ currentTick: BigInt(poolData.currentTick)
2063
+ };
2064
+ } catch (err) {
2065
+ console.error("Failed to calculate ticks:", err);
2066
+ return {
2067
+ tickLower: null,
2068
+ tickUpper: null,
2069
+ currentTick: null
2070
+ };
2071
+ }
2072
+ }, [minPriceNum, maxPriceNum, poolData, isValidPriceRange]);
2073
+ const handleToken0AmountChange = React.useCallback(
2074
+ (value) => {
2075
+ setLiquidityToken0Amount(value);
2076
+ setLastEditedToken("token0");
2077
+ if (!value || !poolData || !tickLower || !tickUpper || !currentTick) {
2078
+ return;
2079
+ }
2080
+ const amount0 = Number.parseFloat(value);
2081
+ if (amount0 <= 0 || !isValidPriceRange) {
2082
+ return;
2083
+ }
2084
+ try {
2085
+ const amount0BigInt = BigInt(Math.floor(amount0 * 10 ** poolData.token0.decimals));
2086
+ const amount1BigInt = sdk.ClService.calculateAmount1FromAmount0(amount0BigInt, tickLower, tickUpper, currentTick);
2087
+ const amount1 = Number(amount1BigInt) / 10 ** poolData.token1.decimals;
2088
+ setLiquidityToken1Amount(amount1.toFixed(6));
2089
+ } catch (err) {
2090
+ console.error("Failed to calculate token1 amount:", err);
2091
+ }
2092
+ },
2093
+ [poolData, tickLower, tickUpper, currentTick, isValidPriceRange]
2094
+ );
2095
+ const handleToken1AmountChange = React.useCallback(
2096
+ (value) => {
2097
+ setLiquidityToken1Amount(value);
2098
+ setLastEditedToken("token1");
2099
+ if (!value || !poolData || !tickLower || !tickUpper || !currentTick) {
2100
+ return;
2101
+ }
2102
+ const amount1 = Number.parseFloat(value);
2103
+ if (amount1 <= 0 || !isValidPriceRange) {
2104
+ return;
2105
+ }
2106
+ try {
2107
+ const amount1BigInt = BigInt(Math.floor(amount1 * 10 ** poolData.token1.decimals));
2108
+ const amount0BigInt = sdk.ClService.calculateAmount0FromAmount1(amount1BigInt, tickLower, tickUpper, currentTick);
2109
+ const amount0 = Number(amount0BigInt) / 10 ** poolData.token0.decimals;
2110
+ setLiquidityToken0Amount(amount0.toFixed(6));
2111
+ } catch (err) {
2112
+ console.error("Failed to calculate token0 amount:", err);
2113
+ }
2114
+ },
2115
+ [poolData, tickLower, tickUpper, currentTick, isValidPriceRange]
2116
+ );
2117
+ React.useEffect(() => {
2118
+ if (!poolData || !tickLower || !tickUpper || !lastEditedToken || !isValidPriceRange) {
2119
+ return;
2120
+ }
2121
+ if (lastEditedToken === "token0" && liquidityToken0Amount) {
2122
+ handleToken0AmountChange(liquidityToken0Amount);
2123
+ } else if (lastEditedToken === "token1" && liquidityToken1Amount) {
2124
+ handleToken1AmountChange(liquidityToken1Amount);
2125
+ }
2126
+ }, [
2127
+ poolData,
2128
+ lastEditedToken,
2129
+ liquidityToken0Amount,
2130
+ liquidityToken1Amount,
2131
+ handleToken0AmountChange,
2132
+ handleToken1AmountChange,
2133
+ tickLower,
2134
+ tickUpper,
2135
+ isValidPriceRange
2136
+ ]);
2137
+ return {
2138
+ liquidityToken0Amount,
2139
+ liquidityToken1Amount,
2140
+ lastEditedToken,
2141
+ setLiquidityToken0Amount,
2142
+ setLiquidityToken1Amount,
2143
+ handleToken0AmountChange,
2144
+ handleToken1AmountChange
2145
+ };
2146
+ }
2147
+ function useSupplyLiquidity() {
2148
+ const { sodax } = useSodaxContext();
2149
+ const queryClient = reactQuery.useQueryClient();
2150
+ return reactQuery.useMutation({
2151
+ mutationFn: async ({ params, spokeProvider }) => {
2152
+ if (params.tokenId && params.isValidPosition) {
2153
+ const increaseResult = await sodax.dex.clService.increaseLiquidity({
2154
+ params: {
2155
+ poolKey: params.poolKey,
2156
+ tokenId: BigInt(params.tokenId),
2157
+ tickLower: params.tickLower,
2158
+ tickUpper: params.tickUpper,
2159
+ liquidity: params.liquidity,
2160
+ amount0Max: params.amount0Max,
2161
+ amount1Max: params.amount1Max,
2162
+ sqrtPriceX96: params.sqrtPriceX96
2163
+ },
2164
+ spokeProvider
2165
+ });
2166
+ if (!increaseResult.ok) {
2167
+ throw new Error(`Increase liquidity failed: ${increaseResult.error?.code || "Unknown error"}`);
2168
+ }
2169
+ return increaseResult.value;
2170
+ }
2171
+ const supplyResult = await sodax.dex.clService.supplyLiquidity({
2172
+ params: {
2173
+ poolKey: params.poolKey,
2174
+ tickLower: params.tickLower,
2175
+ tickUpper: params.tickUpper,
2176
+ liquidity: params.liquidity,
2177
+ amount0Max: params.amount0Max,
2178
+ amount1Max: params.amount1Max,
2179
+ sqrtPriceX96: params.sqrtPriceX96
2180
+ },
2181
+ spokeProvider
2182
+ });
2183
+ if (!supplyResult.ok) {
2184
+ throw new Error(`Supply liquidity failed: ${supplyResult.error?.code || "Unknown error"}`);
2185
+ }
2186
+ return supplyResult.value;
2187
+ },
2188
+ onSuccess: () => {
2189
+ queryClient.invalidateQueries({ queryKey: ["dex", "poolBalances"] });
2190
+ queryClient.invalidateQueries({ queryKey: ["dex", "positionInfo"] });
2191
+ }
2192
+ });
2193
+ }
2194
+ function useDecreaseLiquidity() {
2195
+ const { sodax } = useSodaxContext();
2196
+ const queryClient = reactQuery.useQueryClient();
2197
+ return reactQuery.useMutation({
2198
+ mutationFn: async ({ params, spokeProvider }) => {
2199
+ if (!spokeProvider) {
2200
+ throw new Error("Spoke provider is required");
2201
+ }
2202
+ const decreaseResult = await sodax.dex.clService.decreaseLiquidity({
2203
+ params,
2204
+ spokeProvider
2205
+ });
2206
+ if (!decreaseResult.ok) {
2207
+ throw new Error(`Decrease liquidity failed: ${decreaseResult.error?.code || "Unknown error"}`);
2208
+ }
2209
+ return decreaseResult.value;
2210
+ },
2211
+ onSuccess: () => {
2212
+ queryClient.invalidateQueries({ queryKey: ["dex", "poolBalances"] });
2213
+ queryClient.invalidateQueries({ queryKey: ["dex", "positionInfo"] });
2214
+ }
2215
+ });
2216
+ }
2217
+ function createDecreaseLiquidityParamsProps({
2218
+ poolKey,
2219
+ tokenId,
2220
+ percentage,
2221
+ positionInfo,
2222
+ slippageTolerance
2223
+ }) {
2224
+ const percentageNum = Number.parseFloat(String(percentage));
2225
+ const slippage = Number.parseFloat(String(slippageTolerance));
2226
+ if (percentageNum <= 0 || percentageNum > 100) {
2227
+ throw new Error("Percentage must be between 0 and 100");
2228
+ }
2229
+ if (slippage <= 0 || slippage > 100) {
2230
+ throw new Error("Slippage must be between 0 and 100");
2231
+ }
2232
+ const liquidityToRemove = percentageNum === 100 ? positionInfo.liquidity : positionInfo.liquidity * BigInt(Math.floor(percentageNum * 100)) / 10000n;
2233
+ const expectedAmount0 = percentageNum === 100 ? positionInfo.amount0 : positionInfo.amount0 * BigInt(Math.floor(percentageNum * 100)) / 10000n;
2234
+ const expectedAmount1 = percentageNum === 100 ? positionInfo.amount1 : positionInfo.amount1 * BigInt(Math.floor(percentageNum * 100)) / 10000n;
2235
+ const slippageMultiplier = BigInt(Math.floor((100 - slippage) * 100));
2236
+ const amount0Min = expectedAmount0 * slippageMultiplier / 10000n;
2237
+ const amount1Min = expectedAmount1 * slippageMultiplier / 10000n;
2238
+ return {
2239
+ poolKey,
2240
+ tokenId: BigInt(tokenId),
2241
+ liquidity: liquidityToRemove,
2242
+ amount0Min,
2243
+ amount1Min
2244
+ };
2245
+ }
2246
+ function createDepositParamsProps({
2247
+ tokenIndex,
2248
+ amount,
2249
+ poolData,
2250
+ poolSpokeAssets
2251
+ }) {
2252
+ const amountNum = Number.parseFloat(String(amount));
2253
+ if (!amount || amountNum <= 0) {
2254
+ throw new Error("Amount must be greater than 0");
2255
+ }
2256
+ const token = tokenIndex === 0 ? poolData.token0 : poolData.token1;
2257
+ const originalAsset = tokenIndex === 0 ? poolSpokeAssets.token0 : poolSpokeAssets.token1;
2258
+ return {
2259
+ asset: originalAsset.address,
2260
+ amount: viem.parseUnits(String(amount), token.decimals),
2261
+ poolToken: token.address
2262
+ };
2263
+ }
2264
+ function createSupplyLiquidityParamsProps({
2265
+ poolData,
2266
+ poolKey,
2267
+ minPrice,
2268
+ maxPrice,
2269
+ liquidityToken0Amount,
2270
+ liquidityToken1Amount,
2271
+ slippageTolerance,
2272
+ positionId,
2273
+ isValidPosition
2274
+ }) {
2275
+ const slippage = Number.parseFloat(String(slippageTolerance));
2276
+ if (slippage <= 0 || slippage > 100) {
2277
+ throw new Error("Slippage must be between 0 and 100");
2278
+ }
2279
+ const minPriceNum = Number.parseFloat(minPrice);
2280
+ const maxPriceNum = Number.parseFloat(maxPrice);
2281
+ const amount0 = Number.parseFloat(liquidityToken0Amount);
2282
+ const amount1 = Number.parseFloat(liquidityToken1Amount);
2283
+ if (minPriceNum <= 0 || maxPriceNum <= 0 || amount0 <= 0 || amount1 <= 0) {
2284
+ throw new Error("All values must be greater than 0");
2285
+ }
2286
+ if (minPriceNum >= maxPriceNum) {
2287
+ throw new Error("Min price must be less than max price");
2288
+ }
2289
+ const amount0BigInt = viem.parseUnits(liquidityToken0Amount, poolData.token0.decimals);
2290
+ const amount1BigInt = viem.parseUnits(liquidityToken1Amount, poolData.token1.decimals);
2291
+ const token0 = poolData.token0;
2292
+ const token1 = poolData.token1;
2293
+ const tickSpacing = poolData.tickSpacing;
2294
+ const tickLower = sdk.ClService.priceToTick(minPriceNum, token0, token1, tickSpacing);
2295
+ const tickUpper = sdk.ClService.priceToTick(maxPriceNum, token0, token1, tickSpacing);
2296
+ const slippageMultiplier = BigInt(Math.floor((100 - slippage) * 100));
2297
+ const amount0ForLiquidity = amount0BigInt * slippageMultiplier / 10000n;
2298
+ const amount1ForLiquidity = amount1BigInt * slippageMultiplier / 10000n;
2299
+ const liquidity = sdk.ClService.calculateLiquidityFromAmounts(
2300
+ amount0ForLiquidity,
2301
+ amount1ForLiquidity,
2302
+ tickLower,
2303
+ tickUpper,
2304
+ BigInt(poolData.currentTick)
2305
+ );
2306
+ const tokenId = positionId ? BigInt(positionId) : void 0;
2307
+ return {
2308
+ poolKey,
2309
+ tickLower,
2310
+ tickUpper,
2311
+ liquidity,
2312
+ amount0Max: amount0BigInt,
2313
+ amount1Max: amount1BigInt,
2314
+ sqrtPriceX96: poolData.sqrtPriceX96,
2315
+ positionId,
2316
+ isValidPosition,
2317
+ tokenId
2318
+ };
2319
+ }
2320
+ function createWithdrawParamsProps({
2321
+ tokenIndex,
2322
+ amount,
2323
+ poolData,
2324
+ poolSpokeAssets,
2325
+ dst
2326
+ }) {
2327
+ const amountNum = Number.parseFloat(String(amount));
2328
+ if (!amount || amountNum <= 0) {
2329
+ throw new Error("Please enter a valid amount");
2330
+ }
2331
+ const token = tokenIndex === 0 ? poolData.token0 : poolData.token1;
2332
+ const originalAsset = tokenIndex === 0 ? poolSpokeAssets.token0 : poolSpokeAssets.token1;
2333
+ return {
2334
+ asset: originalAsset.address,
2335
+ amount: viem.parseUnits(String(amount), token.decimals),
2336
+ poolToken: token.address,
2337
+ dst
2338
+ };
2339
+ }
2340
+
2341
+ // src/hooks/dex/useCreateDepositParams.ts
2342
+ function useCreateDepositParams({
2343
+ tokenIndex,
2344
+ amount,
2345
+ poolData,
2346
+ poolSpokeAssets
2347
+ }) {
2348
+ return React.useMemo(() => {
2349
+ if (!amount || Number.parseFloat(String(amount)) <= 0) {
2350
+ return void 0;
2351
+ }
2352
+ return createDepositParamsProps({ tokenIndex, amount, poolData, poolSpokeAssets });
2353
+ }, [tokenIndex, amount, poolData, poolSpokeAssets]);
2354
+ }
2355
+ function useCreateSupplyLiquidityParams({
2356
+ poolData,
2357
+ poolKey,
2358
+ minPrice,
2359
+ maxPrice,
2360
+ liquidityToken0Amount,
2361
+ liquidityToken1Amount,
2362
+ slippageTolerance,
2363
+ positionId,
2364
+ isValidPosition
2365
+ }) {
2366
+ return React.useMemo(() => {
2367
+ return createSupplyLiquidityParamsProps({
2368
+ poolData,
2369
+ poolKey,
2370
+ minPrice,
2371
+ maxPrice,
2372
+ liquidityToken0Amount,
2373
+ liquidityToken1Amount,
2374
+ slippageTolerance,
2375
+ positionId,
2376
+ isValidPosition
2377
+ });
2378
+ }, [
2379
+ minPrice,
2380
+ maxPrice,
2381
+ liquidityToken0Amount,
2382
+ liquidityToken1Amount,
2383
+ slippageTolerance,
2384
+ poolData,
2385
+ poolKey,
2386
+ positionId,
2387
+ isValidPosition
2388
+ ]);
2389
+ }
2390
+ function useCreateDecreaseLiquidityParams({
2391
+ poolKey,
2392
+ tokenId,
2393
+ percentage,
2394
+ positionInfo,
2395
+ slippageTolerance
2396
+ }) {
2397
+ return React.useMemo(() => {
2398
+ return createDecreaseLiquidityParamsProps({ poolKey, tokenId, percentage, positionInfo, slippageTolerance });
2399
+ }, [poolKey, tokenId, percentage, positionInfo, slippageTolerance]);
2400
+ }
2401
+ function useCreateWithdrawParams({
2402
+ tokenIndex,
2403
+ amount,
2404
+ poolData,
2405
+ poolSpokeAssets,
2406
+ dst
2407
+ }) {
2408
+ return React.useMemo(() => {
2409
+ if (!amount || Number.parseFloat(String(amount)) <= 0) {
2410
+ return void 0;
2411
+ }
2412
+ return createWithdrawParamsProps({ tokenIndex, amount, poolData, poolSpokeAssets, dst });
2413
+ }, [tokenIndex, amount, poolData, poolSpokeAssets, dst]);
2414
+ }
2415
+ function useClaimRewards() {
2416
+ const { sodax } = useSodaxContext();
2417
+ const queryClient = reactQuery.useQueryClient();
2418
+ return reactQuery.useMutation({
2419
+ mutationFn: async ({ params, spokeProvider }) => {
2420
+ if (!spokeProvider) {
2421
+ throw new Error("Spoke provider is required");
2422
+ }
2423
+ const result = await sodax.dex.clService.claimRewards({
2424
+ params,
2425
+ spokeProvider
2426
+ });
2427
+ if (!result.ok) {
2428
+ throw new Error(`Claim rewards failed: ${result.error?.code || "Unknown error"}`);
2429
+ }
2430
+ return result.value;
2431
+ },
2432
+ onSuccess: (_, { params, spokeProvider }) => {
2433
+ queryClient.invalidateQueries({
2434
+ queryKey: ["dex", "poolBalances", params.poolKey, spokeProvider.chainConfig.chain.id]
2435
+ });
2436
+ queryClient.invalidateQueries({ queryKey: ["dex", "positionInfo", params.tokenId, params.poolKey] });
2437
+ queryClient.invalidateQueries({ queryKey: ["dex", "poolData", params.poolKey] });
2438
+ }
2439
+ });
2440
+ }
1783
2441
  var SodaxProvider = ({ children, testnet = false, config, rpcConfig }) => {
1784
2442
  const sodax = new sdk.Sodax(config);
1785
2443
  return /* @__PURE__ */ React__default.default.createElement(SodaxContext.Provider, { value: { sodax, testnet, rpcConfig } }, children);
@@ -1789,8 +2447,10 @@ exports.MIGRATION_MODE_BNUSD = MIGRATION_MODE_BNUSD;
1789
2447
  exports.MIGRATION_MODE_ICX_SODA = MIGRATION_MODE_ICX_SODA;
1790
2448
  exports.SodaxProvider = SodaxProvider;
1791
2449
  exports.clearRadfiSession = clearRadfiSession;
1792
- exports.isAccessTokenExpired = isAccessTokenExpired;
1793
- exports.isRefreshTokenExpired = isRefreshTokenExpired;
2450
+ exports.createDecreaseLiquidityParamsProps = createDecreaseLiquidityParamsProps;
2451
+ exports.createDepositParamsProps = createDepositParamsProps;
2452
+ exports.createSupplyLiquidityParamsProps = createSupplyLiquidityParamsProps;
2453
+ exports.createWithdrawParamsProps = createWithdrawParamsProps;
1794
2454
  exports.loadRadfiSession = loadRadfiSession;
1795
2455
  exports.saveRadfiSession = saveRadfiSession;
1796
2456
  exports.useAToken = useAToken;
@@ -1804,6 +2464,8 @@ exports.useBackendMoneyMarketAssetBorrowers = useBackendMoneyMarketAssetBorrower
1804
2464
  exports.useBackendMoneyMarketAssetSuppliers = useBackendMoneyMarketAssetSuppliers;
1805
2465
  exports.useBackendMoneyMarketPosition = useBackendMoneyMarketPosition;
1806
2466
  exports.useBackendOrderbook = useBackendOrderbook;
2467
+ exports.useBackendSubmitSwapTx = useBackendSubmitSwapTx;
2468
+ exports.useBackendSubmitSwapTxStatus = useBackendSubmitSwapTxStatus;
1807
2469
  exports.useBackendUserIntents = useBackendUserIntents;
1808
2470
  exports.useBitcoinBalance = useBitcoinBalance;
1809
2471
  exports.useBorrow = useBorrow;
@@ -1814,9 +2476,19 @@ exports.useCancelLimitOrder = useCancelLimitOrder;
1814
2476
  exports.useCancelSwap = useCancelSwap;
1815
2477
  exports.useCancelUnstake = useCancelUnstake;
1816
2478
  exports.useClaim = useClaim;
2479
+ exports.useClaimRewards = useClaimRewards;
1817
2480
  exports.useConvertedAssets = useConvertedAssets;
2481
+ exports.useCreateDecreaseLiquidityParams = useCreateDecreaseLiquidityParams;
2482
+ exports.useCreateDepositParams = useCreateDepositParams;
1818
2483
  exports.useCreateLimitOrder = useCreateLimitOrder;
2484
+ exports.useCreateSupplyLiquidityParams = useCreateSupplyLiquidityParams;
2485
+ exports.useCreateWithdrawParams = useCreateWithdrawParams;
2486
+ exports.useDecreaseLiquidity = useDecreaseLiquidity;
1819
2487
  exports.useDeriveUserWalletAddress = useDeriveUserWalletAddress;
2488
+ exports.useDexAllowance = useDexAllowance;
2489
+ exports.useDexApprove = useDexApprove;
2490
+ exports.useDexDeposit = useDexDeposit;
2491
+ exports.useDexWithdraw = useDexWithdraw;
1820
2492
  exports.useEstimateGas = useEstimateGas;
1821
2493
  exports.useExpiredUtxos = useExpiredUtxos;
1822
2494
  exports.useFundTradingWallet = useFundTradingWallet;
@@ -1828,14 +2500,20 @@ exports.useInstantUnstake = useInstantUnstake;
1828
2500
  exports.useInstantUnstakeAllowance = useInstantUnstakeAllowance;
1829
2501
  exports.useInstantUnstakeApprove = useInstantUnstakeApprove;
1830
2502
  exports.useInstantUnstakeRatio = useInstantUnstakeRatio;
2503
+ exports.useLiquidityAmounts = useLiquidityAmounts;
1831
2504
  exports.useMMAllowance = useMMAllowance;
1832
2505
  exports.useMMApprove = useMMApprove;
1833
2506
  exports.useMigrate = useMigrate;
1834
2507
  exports.useMigrationAllowance = useMigrationAllowance;
1835
2508
  exports.useMigrationApprove = useMigrationApprove;
2509
+ exports.usePoolBalances = usePoolBalances;
2510
+ exports.usePoolData = usePoolData;
2511
+ exports.usePools = usePools;
2512
+ exports.usePositionInfo = usePositionInfo;
1836
2513
  exports.useQuote = useQuote;
1837
2514
  exports.useRadfiAuth = useRadfiAuth;
1838
2515
  exports.useRadfiSession = useRadfiSession;
2516
+ exports.useRadfiWithdraw = useRadfiWithdraw;
1839
2517
  exports.useRenewUtxos = useRenewUtxos;
1840
2518
  exports.useRepay = useRepay;
1841
2519
  exports.useRequestTrustline = useRequestTrustline;
@@ -1852,6 +2530,7 @@ exports.useStakingInfo = useStakingInfo;
1852
2530
  exports.useStatus = useStatus;
1853
2531
  exports.useStellarTrustlineCheck = useStellarTrustlineCheck;
1854
2532
  exports.useSupply = useSupply;
2533
+ exports.useSupplyLiquidity = useSupplyLiquidity;
1855
2534
  exports.useSwap = useSwap;
1856
2535
  exports.useSwapAllowance = useSwapAllowance;
1857
2536
  exports.useSwapApprove = useSwapApprove;