@turtleclub/hooks 0.5.0-beta.41 → 0.5.0-beta.43

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/index.cjs CHANGED
@@ -140,7 +140,10 @@ __export(index_exports, {
140
140
  productsQueries: () => productsQueries,
141
141
  queries: () => queries,
142
142
  requestStreamSignature: () => requestStreamSignature,
143
+ routeMetadataSchema: () => routeMetadataSchema,
144
+ routeStepSchema: () => routeStepSchema,
143
145
  routeToken: () => routeToken,
146
+ routeTokenSchema: () => routeTokenSchema,
144
147
  routerStep: () => routerStep,
145
148
  routerSubstep: () => routerSubstep,
146
149
  snapshotSchema: () => snapshotSchema,
@@ -165,7 +168,7 @@ __export(index_exports, {
165
168
  transactionSchema: () => transactionSchema,
166
169
  txResponseItemSchema: () => txResponseItemSchema,
167
170
  useAttributeAction: () => useAttributeAction,
168
- useBalance: () => useBalance,
171
+ useBalance: () => useBalance2,
169
172
  useCancelDepositAction: () => useCancelDepositAction,
170
173
  useCancelWithdrawAction: () => useCancelWithdrawAction,
171
174
  useCheckMembership: () => useCheckMembership,
@@ -179,7 +182,11 @@ __export(index_exports, {
179
182
  useCreateWithdrawInteraction: () => useCreateWithdrawInteraction,
180
183
  useDeleteProduct: () => useDeleteProduct,
181
184
  useDepositAction: () => useDepositAction,
185
+ useDepositFlow: () => useDepositFlow,
186
+ useDepositSelection: () => useDepositSelection,
187
+ useDepositValidation: () => useDepositValidation,
182
188
  useDeposits: () => useDeposits,
189
+ useEarnDeposit: () => useEarnDeposit,
183
190
  useEarnOpportunities: () => useEarnOpportunities,
184
191
  useEarnRoute: () => useEarnRoute,
185
192
  useEnsoBalances: () => useEnsoBalances,
@@ -204,6 +211,7 @@ __export(index_exports, {
204
211
  useSupportedTokens: () => useSupportedTokens,
205
212
  useSwapRoute: () => useSwapRoute,
206
213
  useTokenBalance: () => useTokenBalance,
214
+ useTurtleMembershipFlow: () => useTurtleMembershipFlow,
207
215
  useUpdateProduct: () => useUpdateProduct,
208
216
  useUploadProductLogo: () => useUploadProductLogo,
209
217
  useUserById: () => useUserById,
@@ -384,6 +392,14 @@ var vaultConfigSchema = import_zod.z.object({
384
392
  managementFee: import_zod.z.number().min(0).max(100).optional().nullable(),
385
393
  depositFee: import_zod.z.number().min(0).max(100).optional().nullable(),
386
394
  withdrawalFee: import_zod.z.number().min(0).max(100).optional().nullable(),
395
+ minDepositAmount: import_zod.z.number().optional().nullable(),
396
+ minDepositValueUSD: import_zod.z.number().optional().nullable(),
397
+ depositCapAmount: import_zod.z.number().optional().nullable(),
398
+ depositFillSecs: import_zod.z.number().int().optional().nullable(),
399
+ lockupPeriodSecs: import_zod.z.number().int().optional().nullable(),
400
+ asyncDeposit: import_zod.z.boolean().optional().nullable(),
401
+ asyncWithdraw: import_zod.z.boolean().optional().nullable(),
402
+ secondaryOnly: import_zod.z.boolean().optional().nullable(),
387
403
  createdAt: import_zod.z.string().datetime().optional(),
388
404
  updatedAt: import_zod.z.string().datetime().optional()
389
405
  });
@@ -1880,15 +1896,259 @@ function useCreateMembership() {
1880
1896
  }
1881
1897
 
1882
1898
  // src/v2/earn-deposits/hooks.ts
1883
- var import_react_query4 = require("@tanstack/react-query");
1884
- function useDeposits({ params, enabled = true }) {
1885
- return (0, import_react_query4.useQuery)({
1886
- ...earnDepositsQueries.byParams(params),
1887
- ...queryDefaults,
1888
- enabled
1889
- });
1899
+ var import_react_query6 = require("@tanstack/react-query");
1900
+
1901
+ // src/v2/earn-deposits/hooks/useDepositValidation.ts
1902
+ var import_react = require("react");
1903
+ var import_viem = require("viem");
1904
+ function calculateUsdValue(amount, token) {
1905
+ if (!token.priceUsd) return null;
1906
+ const formatted = parseFloat((0, import_viem.formatUnits)(amount, token.decimals));
1907
+ return formatted * token.priceUsd;
1908
+ }
1909
+ function useDepositValidation({
1910
+ opportunity,
1911
+ selectedTokenBalance,
1912
+ amountBigInt,
1913
+ isPending = false,
1914
+ isConfirming = false,
1915
+ walletChainId
1916
+ }) {
1917
+ return (0, import_react.useMemo)(() => {
1918
+ if (!opportunity) {
1919
+ return {
1920
+ canDeposit: false,
1921
+ isBelowMinimum: false,
1922
+ isAboveMaximum: false,
1923
+ hasInsufficientBalance: false,
1924
+ isDepositDisabled: false,
1925
+ isZeroAmount: true,
1926
+ isNoTokenSelected: true,
1927
+ minDepositUSD: 0,
1928
+ maxDepositUSD: null,
1929
+ depositDisabledReason: null,
1930
+ depositFee: null,
1931
+ performanceFee: null,
1932
+ managementFee: null,
1933
+ withdrawalFee: null,
1934
+ withdrawalCooldownSecs: null,
1935
+ inputAmountUSD: null,
1936
+ balanceUSD: null,
1937
+ hasAsyncDeposit: false,
1938
+ isSecondaryOnly: false,
1939
+ isWrongChain: false,
1940
+ requiredChainId: null,
1941
+ buttonText: "Select opportunity",
1942
+ validationMessage: "Please select an opportunity"
1943
+ };
1944
+ }
1945
+ const vaultConfig = opportunity.vaultConfig;
1946
+ const depositDisabled = opportunity.depositDisabled ?? false;
1947
+ const depositDisabledReason = opportunity.depositDisabledReason || null;
1948
+ const depositFee = vaultConfig?.depositFee ?? null;
1949
+ const performanceFee = vaultConfig?.performanceFee ?? null;
1950
+ const managementFee = vaultConfig?.managementFee ?? null;
1951
+ const withdrawalFee = vaultConfig?.withdrawalFee ?? null;
1952
+ const withdrawalCooldownSecs = vaultConfig?.withdrawalCooldownSecs ?? null;
1953
+ const hasAsyncDeposit = vaultConfig?.asyncDeposit === true;
1954
+ const isSecondaryOnly = vaultConfig?.secondaryOnly === true;
1955
+ const requiredChainId = Number(opportunity.receiptToken.chain.chainId);
1956
+ const isWrongChain = walletChainId !== void 0 && walletChainId !== requiredChainId;
1957
+ const isNoTokenSelected = !selectedTokenBalance;
1958
+ const isZeroAmount = !amountBigInt || amountBigInt <= 0n;
1959
+ const depositTokenPrice = selectedTokenBalance?.token.priceUsd ?? null;
1960
+ let inputAmountUSD = null;
1961
+ let balanceUSD = null;
1962
+ if (selectedTokenBalance && amountBigInt) {
1963
+ inputAmountUSD = calculateUsdValue(amountBigInt, selectedTokenBalance.token);
1964
+ }
1965
+ if (selectedTokenBalance) {
1966
+ const balanceAmount = BigInt(selectedTokenBalance.amount);
1967
+ balanceUSD = calculateUsdValue(balanceAmount, selectedTokenBalance.token);
1968
+ }
1969
+ const minDepositAmount = vaultConfig?.minDepositAmount ?? 0;
1970
+ const minDepositValueUSD = vaultConfig?.minDepositValueUSD ?? 0;
1971
+ const minDepositUSD = Math.max(
1972
+ minDepositAmount * (depositTokenPrice ?? 0),
1973
+ minDepositValueUSD
1974
+ );
1975
+ const depositCapAmount = vaultConfig?.depositCapAmount;
1976
+ const maxDepositUSD = depositCapAmount && depositTokenPrice ? depositCapAmount * depositTokenPrice : null;
1977
+ let hasInsufficientBalance = false;
1978
+ if (selectedTokenBalance && amountBigInt) {
1979
+ const balanceAmount = BigInt(selectedTokenBalance.amount);
1980
+ hasInsufficientBalance = amountBigInt > balanceAmount;
1981
+ }
1982
+ const isBelowMinimum = !!(inputAmountUSD !== null && minDepositUSD > 0 && inputAmountUSD < minDepositUSD);
1983
+ const isAboveMaximum = !!(inputAmountUSD !== null && maxDepositUSD !== null && inputAmountUSD > maxDepositUSD);
1984
+ let buttonText;
1985
+ let validationMessage = null;
1986
+ if (isWrongChain) {
1987
+ buttonText = "Switch chain";
1988
+ } else if (isPending) {
1989
+ buttonText = "Confirming...";
1990
+ } else if (isConfirming) {
1991
+ buttonText = "Processing...";
1992
+ } else if (depositDisabled) {
1993
+ buttonText = depositDisabledReason || "Deposits disabled";
1994
+ validationMessage = depositDisabledReason || "Deposits are currently disabled for this opportunity";
1995
+ } else if (isNoTokenSelected) {
1996
+ buttonText = "Select token";
1997
+ validationMessage = "Please select a token to deposit";
1998
+ } else if (isZeroAmount) {
1999
+ buttonText = "Enter amount";
2000
+ } else if (hasInsufficientBalance) {
2001
+ buttonText = "Insufficient balance";
2002
+ validationMessage = "Your balance is insufficient for this deposit amount";
2003
+ } else if (isBelowMinimum) {
2004
+ buttonText = `Minimum $${minDepositUSD.toLocaleString()}`;
2005
+ validationMessage = `Minimum deposit is $${minDepositUSD.toLocaleString()}`;
2006
+ } else if (isAboveMaximum && maxDepositUSD != null) {
2007
+ buttonText = `Maximum $${maxDepositUSD.toLocaleString()}`;
2008
+ validationMessage = `Maximum deposit is $${maxDepositUSD.toLocaleString()}`;
2009
+ } else if (isSecondaryOnly) {
2010
+ buttonText = "Buy";
2011
+ } else if (hasAsyncDeposit) {
2012
+ buttonText = "Request deposit";
2013
+ } else {
2014
+ buttonText = "Deposit";
2015
+ }
2016
+ const isDepositing = isPending || isConfirming;
2017
+ const canDeposit = !depositDisabled && !isDepositing && !isNoTokenSelected && !isZeroAmount && !hasInsufficientBalance && !isBelowMinimum && !isAboveMaximum;
2018
+ return {
2019
+ canDeposit,
2020
+ isBelowMinimum,
2021
+ isAboveMaximum,
2022
+ hasInsufficientBalance,
2023
+ isDepositDisabled: depositDisabled,
2024
+ isZeroAmount,
2025
+ isNoTokenSelected,
2026
+ minDepositUSD,
2027
+ maxDepositUSD,
2028
+ depositDisabledReason,
2029
+ depositFee,
2030
+ performanceFee,
2031
+ managementFee,
2032
+ withdrawalFee,
2033
+ withdrawalCooldownSecs,
2034
+ inputAmountUSD,
2035
+ balanceUSD,
2036
+ hasAsyncDeposit,
2037
+ isSecondaryOnly,
2038
+ isWrongChain,
2039
+ requiredChainId,
2040
+ buttonText,
2041
+ validationMessage
2042
+ };
2043
+ }, [opportunity, selectedTokenBalance, amountBigInt, isPending, isConfirming, walletChainId]);
1890
2044
  }
1891
2045
 
2046
+ // src/v2/earn-deposits/hooks/useDepositSelection.ts
2047
+ var import_react3 = require("react");
2048
+
2049
+ // src/v2/balance/hooks/useTokenBalance.ts
2050
+ var import_react2 = require("react");
2051
+ var import_viem2 = require("viem");
2052
+ var import_utils2 = require("@turtleclub/utils");
2053
+ function checkInsufficientBalance(tokenBalance, amount) {
2054
+ if (!tokenBalance || !amount) return false;
2055
+ try {
2056
+ const balance = BigInt(tokenBalance.amount);
2057
+ const amountBigInt = (0, import_viem2.parseUnits)(amount, tokenBalance.token.decimals);
2058
+ return balance < amountBigInt;
2059
+ } catch (error) {
2060
+ console.error("[Balance Check Error]", error, { tokenBalance, amount });
2061
+ return true;
2062
+ }
2063
+ }
2064
+ function useTokenBalance({ tokenBalance, amount, setAmount }) {
2065
+ const token = tokenBalance?.token;
2066
+ const usdValue = (0, import_react2.useMemo)(
2067
+ () => (0, import_utils2.calculateUsdValue)(amount, token?.priceUsd),
2068
+ [amount, token?.priceUsd]
2069
+ );
2070
+ const hasInsufficientBalance = (0, import_react2.useMemo)(
2071
+ () => checkInsufficientBalance(tokenBalance, amount),
2072
+ [tokenBalance, amount]
2073
+ );
2074
+ const handleMaxClick = (0, import_react2.useCallback)(() => {
2075
+ if (!tokenBalance?.token || !tokenBalance.amount) return;
2076
+ const maxAmount = (0, import_utils2.calculateMaxAmount)(tokenBalance.amount, tokenBalance.token.decimals);
2077
+ setAmount(maxAmount);
2078
+ }, [tokenBalance, setAmount]);
2079
+ const amountBigInt = (0, import_react2.useMemo)(() => {
2080
+ if (!token || !amount) return void 0;
2081
+ try {
2082
+ return (0, import_viem2.parseUnits)(amount, token.decimals);
2083
+ } catch {
2084
+ return void 0;
2085
+ }
2086
+ }, [amount, token]);
2087
+ return {
2088
+ usdValue,
2089
+ hasInsufficientBalance,
2090
+ handleMaxClick,
2091
+ amountBigInt
2092
+ };
2093
+ }
2094
+
2095
+ // src/v2/earn-deposits/hooks/useDepositSelection.ts
2096
+ function useDepositSelection({
2097
+ balances,
2098
+ opportunityId
2099
+ }) {
2100
+ const [selectedTokenAddress, setSelectedTokenAddress] = (0, import_react3.useState)();
2101
+ const [amount, setAmount] = (0, import_react3.useState)();
2102
+ (0, import_react3.useEffect)(() => {
2103
+ setSelectedTokenAddress(void 0);
2104
+ setAmount(void 0);
2105
+ }, [opportunityId]);
2106
+ (0, import_react3.useEffect)(() => {
2107
+ if (balances.length === 0) return;
2108
+ const tokenExistsInBalances = balances.some(
2109
+ (b) => b.token.address === selectedTokenAddress
2110
+ );
2111
+ if (!selectedTokenAddress || !tokenExistsInBalances) {
2112
+ setSelectedTokenAddress(balances[0].token.address);
2113
+ }
2114
+ }, [selectedTokenAddress, balances]);
2115
+ const selectedTokenBalance = (0, import_react3.useMemo)(
2116
+ () => balances.find((b) => b.token.address === selectedTokenAddress) ?? null,
2117
+ [balances, selectedTokenAddress]
2118
+ );
2119
+ const { handleMaxClick, amountBigInt, usdValue, hasInsufficientBalance } = useTokenBalance({
2120
+ tokenBalance: selectedTokenBalance,
2121
+ amount,
2122
+ setAmount
2123
+ });
2124
+ const reset = (0, import_react3.useCallback)(() => {
2125
+ setSelectedTokenAddress(void 0);
2126
+ setAmount(void 0);
2127
+ }, []);
2128
+ return {
2129
+ selectedTokenAddress,
2130
+ setSelectedTokenAddress,
2131
+ amount,
2132
+ setAmount,
2133
+ selectedTokenBalance,
2134
+ amountBigInt,
2135
+ usdValue,
2136
+ hasInsufficientBalance,
2137
+ handleMaxClick,
2138
+ reset
2139
+ };
2140
+ }
2141
+
2142
+ // src/v2/earn-deposits/hooks/useDepositFlow.ts
2143
+ var import_react5 = require("react");
2144
+
2145
+ // src/v2/earn-actions/useEarnDeposit.ts
2146
+ var import_react4 = require("react");
2147
+ var import_react_query5 = require("@tanstack/react-query");
2148
+
2149
+ // src/v2/earn-actions/hooks.ts
2150
+ var import_react_query4 = require("@tanstack/react-query");
2151
+
1892
2152
  // src/v2/earn-actions/schema.ts
1893
2153
  var import_zod14 = require("zod");
1894
2154
  var transactionSchema = import_zod14.z.object({
@@ -1898,10 +2158,29 @@ var transactionSchema = import_zod14.z.object({
1898
2158
  value: import_zod14.z.string(),
1899
2159
  gasLimit: import_zod14.z.string().optional()
1900
2160
  });
2161
+ var routeTokenSchema = import_zod14.z.object({
2162
+ address: import_zod14.z.string(),
2163
+ symbol: import_zod14.z.string(),
2164
+ decimals: import_zod14.z.number().int(),
2165
+ logoUrl: import_zod14.z.string()
2166
+ });
2167
+ var routeStepSchema = import_zod14.z.object({
2168
+ action: import_zod14.z.string(),
2169
+ from: routeTokenSchema,
2170
+ to: routeTokenSchema
2171
+ });
2172
+ var routeMetadataSchema = import_zod14.z.object({
2173
+ provider: import_zod14.z.string(),
2174
+ providerImg: import_zod14.z.string(),
2175
+ amountOut: import_zod14.z.string(),
2176
+ gas: import_zod14.z.string(),
2177
+ route: import_zod14.z.array(routeStepSchema)
2178
+ });
1901
2179
  var txResponseItemSchema = import_zod14.z.object({
1902
2180
  type: import_zod14.z.string().optional(),
1903
2181
  description: import_zod14.z.string().optional(),
1904
- transaction: transactionSchema
2182
+ transaction: transactionSchema,
2183
+ metadata: routeMetadataSchema.optional()
1905
2184
  });
1906
2185
  var actionResponseSchema = import_zod14.z.object({
1907
2186
  actionId: import_zod14.z.string().uuid().optional(),
@@ -1975,10 +2254,9 @@ var createWithdrawInteraction = createWithdrawAction;
1975
2254
  var createClaimWithdrawInteraction = createClaimWithdrawAction;
1976
2255
 
1977
2256
  // src/v2/earn-actions/hooks.ts
1978
- var import_react_query5 = require("@tanstack/react-query");
1979
2257
  function createActionHook(mutationFn) {
1980
2258
  return function useAction(options) {
1981
- return (0, import_react_query5.useMutation)({
2259
+ return (0, import_react_query4.useMutation)({
1982
2260
  mutationFn,
1983
2261
  ...options
1984
2262
  });
@@ -1991,7 +2269,7 @@ var useClaimDepositAction = createActionHook(createClaimDepositAction);
1991
2269
  var useCancelDepositAction = createActionHook(createCancelDepositAction);
1992
2270
  var useCancelWithdrawAction = createActionHook(createCancelWithdrawAction);
1993
2271
  function useAttributeAction(options) {
1994
- return (0, import_react_query5.useMutation)({
2272
+ return (0, import_react_query4.useMutation)({
1995
2273
  mutationFn: attributeAction,
1996
2274
  ...options
1997
2275
  });
@@ -2000,14 +2278,277 @@ var useCreateDepositInteraction = useDepositAction;
2000
2278
  var useCreateWithdrawInteraction = useWithdrawAction;
2001
2279
  var useCreateClaimWithdrawInteraction = useClaimWithdrawAction;
2002
2280
 
2281
+ // src/v2/balance/queries.ts
2282
+ var import_query_key_factory15 = require("@lukemorales/query-key-factory");
2283
+
2284
+ // src/v2/balance/schema.ts
2285
+ var import_zod15 = require("zod");
2286
+ var portfolioTokenSchema = import_zod15.z.object({
2287
+ id: import_zod15.z.string(),
2288
+ address: import_zod15.z.string(),
2289
+ name: import_zod15.z.string(),
2290
+ symbol: import_zod15.z.string(),
2291
+ decimals: import_zod15.z.number(),
2292
+ isNative: import_zod15.z.boolean(),
2293
+ logoUrl: import_zod15.z.string().nullable(),
2294
+ amount: import_zod15.z.string(),
2295
+ // Portfolio-specific field (decimal format)
2296
+ price: import_zod15.z.string().nullable().transform((val) => val ? parseFloat(val) : null),
2297
+ // Portfolio-specific field
2298
+ // Chain with optional fields to match Portfolio API response
2299
+ chain: chainSchema.partial().required({ chainId: true })
2300
+ });
2301
+ var portfolioWalletSchema = import_zod15.z.object({
2302
+ id: import_zod15.z.string().optional(),
2303
+ address: import_zod15.z.string(),
2304
+ blockchain: import_zod15.z.string().optional(),
2305
+ tokens: import_zod15.z.array(portfolioTokenSchema)
2306
+ });
2307
+ var portfolioHoldingsSchema = import_zod15.z.object({
2308
+ wallets: import_zod15.z.array(portfolioWalletSchema)
2309
+ });
2310
+ var portfolioBalanceResponseSchema = import_zod15.z.object({
2311
+ portfolio: import_zod15.z.object({
2312
+ holdings: portfolioHoldingsSchema
2313
+ })
2314
+ });
2315
+
2316
+ // src/v2/balance/api.ts
2317
+ async function getPortfolioBalance(address, options) {
2318
+ const data = await apiClient.fetch(`/wallet/${address}/balance`, {
2319
+ method: "GET",
2320
+ domain: "api",
2321
+ debug: options?.debug
2322
+ });
2323
+ const result = portfolioBalanceResponseSchema.safeParse(data);
2324
+ if (result.success === false) {
2325
+ console.log("[ZOD ERROR]", result.error);
2326
+ throw new Error(`Failed to parse portfolio balance: ${result.error.message}`);
2327
+ }
2328
+ return result.data;
2329
+ }
2330
+
2331
+ // src/v2/balance/queries.ts
2332
+ var balanceQueries = (0, import_query_key_factory15.createQueryKeys)("balance", {
2333
+ // Portfolio balance by address
2334
+ portfolio: (address) => ({
2335
+ queryKey: [address],
2336
+ queryFn: () => getPortfolioBalance(address)
2337
+ })
2338
+ });
2339
+
2340
+ // src/v2/earn-actions/useEarnDeposit.ts
2341
+ var DEFAULT_SLIPPAGE_BPS = 50;
2342
+ function useEarnDeposit(options) {
2343
+ const { opportunity, userAddress, distributorId, executeTransaction, onSuccess, referralCode } = options;
2344
+ const queryClient = (0, import_react_query5.useQueryClient)();
2345
+ const [isConfirming, setIsConfirming] = (0, import_react4.useState)(false);
2346
+ const [error, setError] = (0, import_react4.useState)(null);
2347
+ const [metadata, setMetadata] = (0, import_react4.useState)(null);
2348
+ const [hasApprove, setHasApprove] = (0, import_react4.useState)(false);
2349
+ const depositAction = useDepositAction();
2350
+ const attributeAction2 = useAttributeAction();
2351
+ const toTransactionRequest = (0, import_react4.useCallback)((txItem) => {
2352
+ return {
2353
+ to: txItem.transaction.to,
2354
+ data: txItem.transaction.data,
2355
+ value: txItem.transaction.value,
2356
+ gasLimit: txItem.transaction.gasLimit
2357
+ };
2358
+ }, []);
2359
+ const executeTransactionsSequentially = (0, import_react4.useCallback)(
2360
+ async (transactions) => {
2361
+ let lastTxHash;
2362
+ for (const txItem of transactions) {
2363
+ const txRequest = toTransactionRequest(txItem);
2364
+ const txHash = await executeTransaction(txRequest);
2365
+ if (!txHash) {
2366
+ throw new Error(`Transaction failed: ${txItem.description || "Unknown transaction"}`);
2367
+ }
2368
+ lastTxHash = txHash;
2369
+ }
2370
+ return lastTxHash;
2371
+ },
2372
+ [executeTransaction, toTransactionRequest]
2373
+ );
2374
+ const attributeTransactionSafely = (0, import_react4.useCallback)(
2375
+ async (actionId, txHash) => {
2376
+ try {
2377
+ await attributeAction2.mutateAsync({ actionId, txHash });
2378
+ } catch (attributeError) {
2379
+ console.warn("[useEarnDeposit] Attribution failed (non-blocking):", attributeError);
2380
+ }
2381
+ },
2382
+ [attributeAction2]
2383
+ );
2384
+ const deposit = (0, import_react4.useCallback)(
2385
+ async (amount, tokenAddress, slippage = DEFAULT_SLIPPAGE_BPS) => {
2386
+ setError(null);
2387
+ if (!opportunity?.id) {
2388
+ const err = new Error("No opportunity selected");
2389
+ setError(err);
2390
+ throw err;
2391
+ }
2392
+ if (!userAddress) {
2393
+ const err = new Error("No wallet connected");
2394
+ setError(err);
2395
+ throw err;
2396
+ }
2397
+ if (amount <= 0n) {
2398
+ const err = new Error("Amount must be greater than 0");
2399
+ setError(err);
2400
+ throw err;
2401
+ }
2402
+ try {
2403
+ const actionResponse = await depositAction.mutateAsync({
2404
+ opportunityId: opportunity.id,
2405
+ userAddress,
2406
+ tokenIn: tokenAddress,
2407
+ amount: amount.toString(),
2408
+ distributorId,
2409
+ referralCode,
2410
+ slippageBps: slippage
2411
+ });
2412
+ const { actionId, transactions } = actionResponse;
2413
+ if (!transactions || transactions.length === 0) {
2414
+ throw new Error("No transactions returned from deposit action");
2415
+ }
2416
+ const txWithMetadata = transactions.find((tx) => tx.metadata);
2417
+ if (txWithMetadata?.metadata) {
2418
+ setMetadata(txWithMetadata.metadata);
2419
+ }
2420
+ const hasApproveTx = transactions.some((tx) => tx.type === "approve");
2421
+ setHasApprove(hasApproveTx);
2422
+ setIsConfirming(true);
2423
+ const finalTxHash = await executeTransactionsSequentially(transactions);
2424
+ if (actionId && finalTxHash) {
2425
+ await attributeTransactionSafely(actionId, finalTxHash);
2426
+ }
2427
+ if (userAddress) {
2428
+ queryClient.invalidateQueries({
2429
+ queryKey: balanceQueries.portfolio(userAddress).queryKey
2430
+ });
2431
+ }
2432
+ onSuccess?.();
2433
+ return finalTxHash;
2434
+ } catch (err) {
2435
+ const error2 = err instanceof Error ? err : new Error(String(err));
2436
+ setError(error2);
2437
+ throw error2;
2438
+ } finally {
2439
+ setIsConfirming(false);
2440
+ }
2441
+ },
2442
+ [
2443
+ opportunity?.id,
2444
+ userAddress,
2445
+ distributorId,
2446
+ referralCode,
2447
+ depositAction,
2448
+ executeTransactionsSequentially,
2449
+ attributeTransactionSafely,
2450
+ queryClient,
2451
+ onSuccess
2452
+ ]
2453
+ );
2454
+ const resetMetadata = (0, import_react4.useCallback)(() => {
2455
+ setMetadata(null);
2456
+ setHasApprove(false);
2457
+ }, []);
2458
+ return {
2459
+ deposit,
2460
+ isPending: depositAction.isPending,
2461
+ isConfirming,
2462
+ error,
2463
+ metadata,
2464
+ hasApprove,
2465
+ resetMetadata
2466
+ };
2467
+ }
2468
+
2469
+ // src/v2/earn-deposits/hooks/useDepositFlow.ts
2470
+ function useDepositFlow({
2471
+ opportunity,
2472
+ userAddress,
2473
+ distributorId,
2474
+ balances,
2475
+ executeTransaction,
2476
+ onDepositSuccess,
2477
+ refetchBalances,
2478
+ slippageBps,
2479
+ walletChainId
2480
+ }) {
2481
+ const selection = useDepositSelection({
2482
+ balances,
2483
+ opportunityId: opportunity?.id
2484
+ });
2485
+ const {
2486
+ deposit: executeDeposit,
2487
+ isPending,
2488
+ isConfirming,
2489
+ error,
2490
+ metadata,
2491
+ hasApprove,
2492
+ resetMetadata
2493
+ } = useEarnDeposit({
2494
+ opportunity,
2495
+ userAddress,
2496
+ distributorId,
2497
+ executeTransaction,
2498
+ onSuccess: () => {
2499
+ selection.setAmount(void 0);
2500
+ refetchBalances?.();
2501
+ onDepositSuccess?.();
2502
+ }
2503
+ });
2504
+ const isDepositing = isPending || isConfirming;
2505
+ const validation = useDepositValidation({
2506
+ opportunity,
2507
+ selectedTokenBalance: selection.selectedTokenBalance,
2508
+ amountBigInt: selection.amountBigInt,
2509
+ isPending,
2510
+ isConfirming,
2511
+ walletChainId
2512
+ });
2513
+ const execute = (0, import_react5.useCallback)(async () => {
2514
+ if (!selection.amountBigInt || !selection.selectedTokenAddress) {
2515
+ return void 0;
2516
+ }
2517
+ return executeDeposit(selection.amountBigInt, selection.selectedTokenAddress, slippageBps);
2518
+ }, [selection.amountBigInt, selection.selectedTokenAddress, executeDeposit, slippageBps]);
2519
+ return {
2520
+ selection,
2521
+ validation,
2522
+ deposit: {
2523
+ execute,
2524
+ isPending,
2525
+ isConfirming,
2526
+ isDepositing,
2527
+ error,
2528
+ metadata,
2529
+ hasApprove,
2530
+ resetMetadata
2531
+ }
2532
+ };
2533
+ }
2534
+
2535
+ // src/v2/earn-deposits/hooks.ts
2536
+ function useDeposits({ params, enabled = true }) {
2537
+ return (0, import_react_query6.useQuery)({
2538
+ ...earnDepositsQueries.byParams(params),
2539
+ ...queryDefaults,
2540
+ enabled
2541
+ });
2542
+ }
2543
+
2003
2544
  // src/v2/enso-balances/hooks.ts
2004
- var import_react = require("react");
2005
- var import_react_query6 = require("@tanstack/react-query");
2545
+ var import_react6 = require("react");
2546
+ var import_react_query7 = require("@tanstack/react-query");
2006
2547
  function useMultiChainBalances({
2007
2548
  chainIds,
2008
2549
  address
2009
2550
  }) {
2010
- const queries2 = (0, import_react_query6.useQueries)({
2551
+ const queries2 = (0, import_react_query7.useQueries)({
2011
2552
  queries: chainIds.map((chainId) => ({
2012
2553
  ...ensoBalancesQueries.byParams({ user: address || "", chain: chainId }),
2013
2554
  enabled: !!address,
@@ -2024,7 +2565,7 @@ function useMultiChainBalances({
2024
2565
  query.refetch();
2025
2566
  });
2026
2567
  };
2027
- const balances = (0, import_react.useMemo)(() => {
2568
+ const balances = (0, import_react6.useMemo)(() => {
2028
2569
  const balanceMap = {};
2029
2570
  queries2.forEach((query, index) => {
2030
2571
  const chainId = chainIds[index];
@@ -2043,9 +2584,9 @@ function useMultiChainBalances({
2043
2584
  }
2044
2585
 
2045
2586
  // src/v2/opportunities/hooks.ts
2046
- var import_react_query7 = require("@tanstack/react-query");
2587
+ var import_react_query8 = require("@tanstack/react-query");
2047
2588
  function useOpportunities(options) {
2048
- return (0, import_react_query7.useQuery)({
2589
+ return (0, import_react_query8.useQuery)({
2049
2590
  ...opportunitiesQueries.all,
2050
2591
  ...queryDefaults,
2051
2592
  select: (data) => {
@@ -2061,7 +2602,7 @@ function useOpportunities(options) {
2061
2602
  });
2062
2603
  }
2063
2604
  function useOpportunity({ id, ...options }) {
2064
- return (0, import_react_query7.useQuery)({
2605
+ return (0, import_react_query8.useQuery)({
2065
2606
  ...opportunitiesQueries.byId(id),
2066
2607
  ...queryDefaults,
2067
2608
  select: (data) => {
@@ -2076,7 +2617,7 @@ function useOpportunitiesPaginated({
2076
2617
  params,
2077
2618
  enabled = true
2078
2619
  } = {}) {
2079
- return (0, import_react_query7.useQuery)({
2620
+ return (0, import_react_query8.useQuery)({
2080
2621
  ...opportunitiesQueries.paginated(params),
2081
2622
  ...queryDefaults,
2082
2623
  enabled
@@ -2085,7 +2626,7 @@ function useOpportunitiesPaginated({
2085
2626
  function useOpportunitiesFilterOptions({
2086
2627
  enabled = true
2087
2628
  } = {}) {
2088
- return (0, import_react_query7.useQuery)({
2629
+ return (0, import_react_query8.useQuery)({
2089
2630
  ...opportunitiesQueries.filterOptions,
2090
2631
  ...queryDefaults,
2091
2632
  enabled
@@ -2093,92 +2634,46 @@ function useOpportunitiesFilterOptions({
2093
2634
  }
2094
2635
 
2095
2636
  // src/v2/products/hooks.ts
2096
- var import_react_query8 = require("@tanstack/react-query");
2637
+ var import_react_query9 = require("@tanstack/react-query");
2097
2638
  function useProducts({ filters, enabled = true }) {
2098
- return (0, import_react_query8.useQuery)({
2639
+ return (0, import_react_query9.useQuery)({
2099
2640
  ...productsQueries.list(filters),
2100
2641
  ...queryDefaults,
2101
2642
  enabled
2102
2643
  });
2103
2644
  }
2104
2645
  function useProduct({ id, enabled = true }) {
2105
- return (0, import_react_query8.useQuery)({
2646
+ return (0, import_react_query9.useQuery)({
2106
2647
  ...productsQueries.byId(id),
2107
2648
  ...queryDefaults,
2108
2649
  enabled
2109
2650
  });
2110
2651
  }
2111
2652
  function useCreateProduct(options) {
2112
- return (0, import_react_query8.useMutation)({
2653
+ return (0, import_react_query9.useMutation)({
2113
2654
  mutationFn: (input) => createProduct(input),
2114
2655
  ...options
2115
2656
  });
2116
2657
  }
2117
2658
  function useUpdateProduct(options) {
2118
- return (0, import_react_query8.useMutation)({
2659
+ return (0, import_react_query9.useMutation)({
2119
2660
  mutationFn: (input) => updateProduct(input),
2120
2661
  ...options
2121
2662
  });
2122
2663
  }
2123
2664
  function useDeleteProduct(options) {
2124
- return (0, import_react_query8.useMutation)({
2665
+ return (0, import_react_query9.useMutation)({
2125
2666
  mutationFn: (id) => deleteProduct(id),
2126
2667
  ...options
2127
2668
  });
2128
2669
  }
2129
2670
  function useUploadProductLogo(options) {
2130
- return (0, import_react_query8.useMutation)({
2671
+ return (0, import_react_query9.useMutation)({
2131
2672
  mutationFn: (request) => uploadProductLogo(request),
2132
2673
  ...options
2133
2674
  });
2134
2675
  }
2135
2676
 
2136
- // src/v2/balance/hooks/useTokenBalance.ts
2137
- var import_react2 = require("react");
2138
- var import_viem = require("viem");
2139
- var import_utils2 = require("@turtleclub/utils");
2140
- function checkInsufficientBalance(tokenBalance, amount) {
2141
- if (!tokenBalance || !amount) return false;
2142
- try {
2143
- const balance = BigInt(tokenBalance.amount);
2144
- const amountBigInt = (0, import_viem.parseUnits)(amount, tokenBalance.token.decimals);
2145
- return balance < amountBigInt;
2146
- } catch (error) {
2147
- console.error("[Balance Check Error]", error, { tokenBalance, amount });
2148
- return true;
2149
- }
2150
- }
2151
- function useTokenBalance({ tokenBalance, amount, setAmount }) {
2152
- const token = tokenBalance?.token;
2153
- const usdValue = (0, import_react2.useMemo)(
2154
- () => (0, import_utils2.calculateUsdValue)(amount, token?.priceUsd),
2155
- [amount, token?.priceUsd]
2156
- );
2157
- const hasInsufficientBalance = (0, import_react2.useMemo)(
2158
- () => checkInsufficientBalance(tokenBalance, amount),
2159
- [tokenBalance, amount]
2160
- );
2161
- const handleMaxClick = (0, import_react2.useCallback)(() => {
2162
- if (!tokenBalance?.token || !tokenBalance.amount) return;
2163
- const maxAmount = (0, import_utils2.calculateMaxAmount)(tokenBalance.amount, tokenBalance.token.decimals);
2164
- setAmount(maxAmount);
2165
- }, [tokenBalance, setAmount]);
2166
- const amountBigInt = (0, import_react2.useMemo)(() => {
2167
- if (!token || !amount) return void 0;
2168
- try {
2169
- return (0, import_viem.parseUnits)(amount, token.decimals);
2170
- } catch {
2171
- return void 0;
2172
- }
2173
- }, [amount, token]);
2174
- return {
2175
- usdValue,
2176
- hasInsufficientBalance,
2177
- handleMaxClick,
2178
- amountBigInt
2179
- };
2180
- }
2181
-
2182
2677
  // src/v2/balance/types.ts
2183
2678
  var BalanceSourcePriority = /* @__PURE__ */ ((BalanceSourcePriority2) => {
2184
2679
  BalanceSourcePriority2[BalanceSourcePriority2["ONCHAIN"] = 1] = "ONCHAIN";
@@ -2187,115 +2682,116 @@ var BalanceSourcePriority = /* @__PURE__ */ ((BalanceSourcePriority2) => {
2187
2682
  return BalanceSourcePriority2;
2188
2683
  })(BalanceSourcePriority || {});
2189
2684
 
2190
- // src/v2/balance/schema.ts
2191
- var import_zod15 = require("zod");
2192
- var portfolioTokenSchema = import_zod15.z.object({
2193
- id: import_zod15.z.string(),
2194
- address: import_zod15.z.string(),
2195
- name: import_zod15.z.string(),
2196
- symbol: import_zod15.z.string(),
2197
- decimals: import_zod15.z.number(),
2198
- isNative: import_zod15.z.boolean(),
2199
- logoUrl: import_zod15.z.string().nullable(),
2200
- amount: import_zod15.z.string(),
2201
- // Portfolio-specific field (decimal format)
2202
- price: import_zod15.z.string().nullable().transform((val) => val ? parseFloat(val) : null),
2203
- // Portfolio-specific field
2204
- // Chain with optional fields to match Portfolio API response
2205
- chain: chainSchema.partial().required({ chainId: true })
2206
- });
2207
- var portfolioWalletSchema = import_zod15.z.object({
2208
- id: import_zod15.z.string().optional(),
2209
- address: import_zod15.z.string(),
2210
- blockchain: import_zod15.z.string().optional(),
2211
- tokens: import_zod15.z.array(portfolioTokenSchema)
2212
- });
2213
- var portfolioHoldingsSchema = import_zod15.z.object({
2214
- wallets: import_zod15.z.array(portfolioWalletSchema)
2215
- });
2216
- var portfolioBalanceResponseSchema = import_zod15.z.object({
2217
- portfolio: import_zod15.z.object({
2218
- holdings: portfolioHoldingsSchema
2219
- })
2220
- });
2221
-
2222
- // src/v2/balance/api.ts
2223
- async function getPortfolioBalance(address, options) {
2224
- const data = await apiClient.fetch(`/wallet/${address}/balance`, {
2225
- method: "GET",
2226
- domain: "api",
2227
- debug: options?.debug
2228
- });
2229
- const result = portfolioBalanceResponseSchema.safeParse(data);
2230
- if (result.success === false) {
2231
- console.log("[ZOD ERROR]", result.error);
2232
- throw new Error(`Failed to parse portfolio balance: ${result.error.message}`);
2233
- }
2234
- return result.data;
2235
- }
2236
-
2237
- // src/v2/balance/queries.ts
2238
- var import_query_key_factory15 = require("@lukemorales/query-key-factory");
2239
- var balanceQueries = (0, import_query_key_factory15.createQueryKeys)("balance", {
2240
- // Portfolio balance by address
2241
- portfolio: (address) => ({
2242
- queryKey: [address],
2243
- queryFn: () => getPortfolioBalance(address)
2244
- })
2245
- });
2246
-
2247
2685
  // src/v2/balance/hooks/useBalance.ts
2248
- var import_react7 = require("react");
2686
+ var import_react10 = require("react");
2249
2687
 
2250
2688
  // src/v2/balance/hooks/useGetOnChainBalance.ts
2251
2689
  var import_wagmi = require("wagmi");
2252
- var import_viem2 = require("viem");
2253
- var import_react3 = require("react");
2690
+ var import_viem3 = require("viem");
2691
+ var import_react7 = require("react");
2692
+ var NATIVE_TOKEN_ADDRESSES = [
2693
+ "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
2694
+ "0x0000000000000000000000000000000000000000"
2695
+ ];
2696
+ var QUERY_REFETCH_INTERVAL = 5e3;
2697
+ function isNativeToken(token) {
2698
+ return token.isNative || NATIVE_TOKEN_ADDRESSES.includes(token.address.toLowerCase());
2699
+ }
2254
2700
  function useGetOnChainBalance({
2255
2701
  tokens,
2256
2702
  chainId,
2257
2703
  address,
2258
2704
  enabled = true
2259
2705
  }) {
2260
- const contracts = (0, import_react3.useMemo)(() => {
2706
+ const { nativeTokens, erc20Tokens } = (0, import_react7.useMemo)(() => {
2707
+ const native = [];
2708
+ const erc20 = [];
2709
+ for (const token of tokens) {
2710
+ if (isNativeToken(token)) {
2711
+ native.push(token);
2712
+ } else {
2713
+ erc20.push(token);
2714
+ }
2715
+ }
2716
+ return { nativeTokens: native, erc20Tokens: erc20 };
2717
+ }, [tokens]);
2718
+ const nativeToken = nativeTokens[0];
2719
+ const {
2720
+ data: nativeBalanceData,
2721
+ isLoading: isNativeLoading,
2722
+ error: nativeError,
2723
+ refetch: refetchNative
2724
+ } = (0, import_wagmi.useBalance)({
2725
+ address,
2726
+ chainId,
2727
+ query: {
2728
+ ...queryDefaults,
2729
+ enabled: enabled && !!address && nativeTokens.length > 0,
2730
+ refetchInterval: QUERY_REFETCH_INTERVAL,
2731
+ refetchOnWindowFocus: true
2732
+ }
2733
+ });
2734
+ const contracts = (0, import_react7.useMemo)(() => {
2261
2735
  if (!address || !enabled) return [];
2262
- return tokens.map((token) => ({
2263
- address: token.address,
2264
- abi: import_viem2.erc20Abi,
2265
- functionName: "balanceOf",
2266
- args: [address],
2267
- chainId
2268
- }));
2269
- }, [tokens, address, chainId, enabled]);
2736
+ return erc20Tokens.map(
2737
+ (token) => ({
2738
+ address: token.address,
2739
+ abi: import_viem3.erc20Abi,
2740
+ functionName: "balanceOf",
2741
+ args: [address],
2742
+ chainId
2743
+ })
2744
+ );
2745
+ }, [erc20Tokens, address, chainId, enabled]);
2270
2746
  const {
2271
- data: results,
2272
- isLoading,
2273
- error,
2274
- refetch
2747
+ data: erc20Results,
2748
+ isLoading: isErc20Loading,
2749
+ error: erc20Error,
2750
+ refetch: refetchErc20
2275
2751
  } = (0, import_wagmi.useReadContracts)({
2276
2752
  contracts,
2277
2753
  query: {
2278
2754
  ...queryDefaults,
2279
- enabled: enabled && !!address && tokens.length > 0,
2280
- refetchInterval: 5e3,
2755
+ enabled: enabled && !!address && erc20Tokens.length > 0,
2756
+ refetchInterval: QUERY_REFETCH_INTERVAL,
2281
2757
  refetchOnWindowFocus: true
2282
2758
  }
2283
2759
  });
2284
- const balances = (0, import_react3.useMemo)(() => {
2285
- if (!results || results.length === 0) return [];
2286
- return tokens.map((token, index) => {
2287
- const result = results[index];
2288
- let balance = "0";
2289
- if (result?.status === "success" && typeof result.result === "bigint") {
2290
- balance = result.result.toString();
2291
- }
2292
- return {
2293
- token,
2294
- amount: balance,
2760
+ const balances = (0, import_react7.useMemo)(() => {
2761
+ const result = [];
2762
+ if (nativeToken && nativeBalanceData) {
2763
+ result.push({
2764
+ token: nativeToken,
2765
+ amount: nativeBalanceData.value.toString(),
2295
2766
  source: "onchain"
2296
- };
2297
- });
2298
- }, [results, tokens]);
2767
+ });
2768
+ }
2769
+ if (erc20Results && erc20Results.length > 0) {
2770
+ erc20Tokens.forEach((token, index) => {
2771
+ const erc20Result = erc20Results[index];
2772
+ let balance = "0";
2773
+ if (erc20Result?.status === "success" && typeof erc20Result.result === "bigint") {
2774
+ balance = erc20Result.result.toString();
2775
+ }
2776
+ result.push({
2777
+ token,
2778
+ amount: balance,
2779
+ source: "onchain"
2780
+ });
2781
+ });
2782
+ }
2783
+ return result;
2784
+ }, [nativeToken, nativeBalanceData, erc20Results, erc20Tokens]);
2785
+ const isLoading = nativeTokens.length > 0 && isNativeLoading || erc20Tokens.length > 0 && isErc20Loading;
2786
+ const error = nativeError || erc20Error;
2787
+ const refetch = (0, import_react7.useCallback)(() => {
2788
+ if (nativeTokens.length > 0) {
2789
+ refetchNative();
2790
+ }
2791
+ if (erc20Tokens.length > 0) {
2792
+ refetchErc20();
2793
+ }
2794
+ }, [nativeTokens.length, erc20Tokens.length, refetchNative, refetchErc20]);
2299
2795
  return {
2300
2796
  balances,
2301
2797
  isLoading,
@@ -2305,13 +2801,13 @@ function useGetOnChainBalance({
2305
2801
  }
2306
2802
 
2307
2803
  // src/v2/balance/hooks/usePortfolioBalance.ts
2308
- var import_react_query11 = require("@tanstack/react-query");
2309
- var import_react5 = require("react");
2804
+ var import_react_query12 = require("@tanstack/react-query");
2805
+ var import_react9 = require("react");
2310
2806
 
2311
2807
  // src/v2/supported-chains/hooks.ts
2312
- var import_react_query9 = require("@tanstack/react-query");
2808
+ var import_react_query10 = require("@tanstack/react-query");
2313
2809
  function useSupportedChains() {
2314
- const { data, isLoading, error, refetch } = (0, import_react_query9.useQuery)({
2810
+ const { data, isLoading, error, refetch } = (0, import_react_query10.useQuery)({
2315
2811
  ...supportedChainsQueries.all,
2316
2812
  ...queryDefaults
2317
2813
  });
@@ -2326,15 +2822,15 @@ function useSupportedChains() {
2326
2822
  }
2327
2823
 
2328
2824
  // src/v2/supported-tokens/hooks.ts
2329
- var import_react_query10 = require("@tanstack/react-query");
2330
- var import_react4 = require("react");
2825
+ var import_react_query11 = require("@tanstack/react-query");
2826
+ var import_react8 = require("react");
2331
2827
  function useSupportedTokens({
2332
2828
  page = 0,
2333
2829
  limit = 20,
2334
2830
  search,
2335
2831
  enabled = true
2336
2832
  } = {}) {
2337
- const { data, isLoading, error, refetch } = (0, import_react_query10.useQuery)({
2833
+ const { data, isLoading, error, refetch } = (0, import_react_query11.useQuery)({
2338
2834
  ...supportedTokensQueries.list({ page, limit, search }),
2339
2835
  ...queryDefaults,
2340
2836
  staleTime: 5 * 60 * 1e3,
@@ -2345,7 +2841,7 @@ function useSupportedTokens({
2345
2841
  // Don't refetch on tab focus
2346
2842
  enabled
2347
2843
  });
2348
- const tokens = (0, import_react4.useMemo)(() => {
2844
+ const tokens = (0, import_react8.useMemo)(() => {
2349
2845
  if (!data?.tokens) return [];
2350
2846
  return data.tokens.map(({ active, ...token }) => token);
2351
2847
  }, [data?.tokens]);
@@ -2365,7 +2861,7 @@ function useSupportedTokens({
2365
2861
  }
2366
2862
 
2367
2863
  // src/v2/balance/hooks/usePortfolioBalance.ts
2368
- var import_viem3 = require("viem");
2864
+ var import_viem4 = require("viem");
2369
2865
  function usePortfolioBalance({
2370
2866
  address
2371
2867
  }) {
@@ -2376,14 +2872,14 @@ function usePortfolioBalance({
2376
2872
  isLoading,
2377
2873
  error,
2378
2874
  refetch
2379
- } = (0, import_react_query11.useQuery)({
2875
+ } = (0, import_react_query12.useQuery)({
2380
2876
  ...balanceQueries.portfolio(address || ""),
2381
2877
  ...queryDefaults,
2382
2878
  enabled: !!address,
2383
2879
  refetchInterval: 1 * 60 * 1e3
2384
2880
  // 1 minute
2385
2881
  });
2386
- const balances = (0, import_react5.useMemo)(() => {
2882
+ const balances = (0, import_react9.useMemo)(() => {
2387
2883
  if (!portfolioData) return [];
2388
2884
  const tokenBalances = [];
2389
2885
  portfolioData.portfolio.holdings.wallets.forEach((wallet) => {
@@ -2412,7 +2908,7 @@ function usePortfolioBalance({
2412
2908
  };
2413
2909
  let amountInWei;
2414
2910
  try {
2415
- amountInWei = (0, import_viem3.parseUnits)(portfolioToken.amount, token.decimals).toString();
2911
+ amountInWei = (0, import_viem4.parseUnits)(portfolioToken.amount, token.decimals).toString();
2416
2912
  } catch (error2) {
2417
2913
  console.error("[Portfolio Balance] Failed to parse amount:", {
2418
2914
  amount: portfolioToken.amount,
@@ -2438,49 +2934,8 @@ function usePortfolioBalance({
2438
2934
  };
2439
2935
  }
2440
2936
 
2441
- // src/v2/balance/hooks/useEnsoBalances.ts
2442
- var import_react6 = require("react");
2443
- function useEnsoBalances({
2444
- address,
2445
- chainIds
2446
- }) {
2447
- const { getToken, isLoading: isSupportedTokensLoading } = useSupportedTokens();
2448
- const {
2449
- balances: ensoBalances,
2450
- isLoading,
2451
- error,
2452
- refetchAll
2453
- } = useMultiChainBalances({
2454
- chainIds,
2455
- address
2456
- });
2457
- const balances = (0, import_react6.useMemo)(() => {
2458
- if (isSupportedTokensLoading || isLoading) return [];
2459
- const tokenBalances = [];
2460
- Object.entries(ensoBalances).forEach(([, chainBalances]) => {
2461
- chainBalances.forEach((walletBalance) => {
2462
- const chainId = walletBalance.token.chain.toString();
2463
- const token = getToken(walletBalance.token.address, chainId);
2464
- if (!token) return;
2465
- tokenBalances.push({
2466
- token,
2467
- amount: walletBalance.amount,
2468
- source: "enso"
2469
- });
2470
- });
2471
- });
2472
- return tokenBalances;
2473
- }, [ensoBalances, getToken, isSupportedTokensLoading, isLoading]);
2474
- return {
2475
- balances,
2476
- isLoading,
2477
- error,
2478
- refetch: refetchAll
2479
- };
2480
- }
2481
-
2482
2937
  // src/v2/balance/utils.ts
2483
- var import_viem4 = require("viem");
2938
+ var import_viem5 = require("viem");
2484
2939
 
2485
2940
  // src/v2/balance/constants.ts
2486
2941
  var EXCLUDE_TOKEN_ADDRESS_LIST = [
@@ -2534,8 +2989,8 @@ function mergeBalancesByPriority(sources, receiptToken) {
2534
2989
  if (a.token.chain.chainId !== b.token.chain.chainId) {
2535
2990
  return Number(a.token.chain.chainId) - Number(b.token.chain.chainId);
2536
2991
  }
2537
- const balanceA = Number((0, import_viem4.formatUnits)(BigInt(a.amount), a.token.decimals));
2538
- const balanceB = Number((0, import_viem4.formatUnits)(BigInt(b.amount), b.token.decimals));
2992
+ const balanceA = Number((0, import_viem5.formatUnits)(BigInt(a.amount), a.token.decimals));
2993
+ const balanceB = Number((0, import_viem5.formatUnits)(BigInt(b.amount), b.token.decimals));
2539
2994
  return balanceB - balanceA;
2540
2995
  });
2541
2996
  }
@@ -2558,7 +3013,7 @@ function filterExcludedTokens(balances) {
2558
3013
  }
2559
3014
 
2560
3015
  // src/v2/balance/hooks/useBalance.ts
2561
- function useBalance({
3016
+ function useBalance2({
2562
3017
  address,
2563
3018
  chainIds,
2564
3019
  depositOpportunity
@@ -2582,16 +3037,7 @@ function useBalance({
2582
3037
  } = usePortfolioBalance({
2583
3038
  address
2584
3039
  });
2585
- const {
2586
- balances: ensoBalances,
2587
- isLoading: isEnsoLoading,
2588
- error: ensoError,
2589
- refetch: refetchEnso
2590
- } = useEnsoBalances({
2591
- address,
2592
- chainIds
2593
- });
2594
- const consolidatedBalances = (0, import_react7.useMemo)(() => {
3040
+ const consolidatedBalances = (0, import_react10.useMemo)(() => {
2595
3041
  const sources = [];
2596
3042
  if (depositOpportunity && onChainBalances.length > 0) {
2597
3043
  sources.push(onChainBalances);
@@ -2599,21 +3045,17 @@ function useBalance({
2599
3045
  if (portfolioBalances.length > 0) {
2600
3046
  sources.push(portfolioBalances);
2601
3047
  }
2602
- if (ensoBalances.length > 0) {
2603
- sources.push(ensoBalances);
2604
- }
2605
3048
  const merged = mergeBalancesByPriority(sources, depositOpportunity?.receiptToken);
2606
3049
  const nonZero = filterNonZeroBalances(merged);
2607
3050
  return filterExcludedTokens(nonZero);
2608
- }, [onChainBalances, portfolioBalances, ensoBalances, depositOpportunity]);
2609
- const isLoading = isOnChainLoading || isPortfolioLoading || isEnsoLoading;
2610
- const error = onChainError || portfolioError || ensoError;
3051
+ }, [onChainBalances, portfolioBalances, depositOpportunity]);
3052
+ const isLoading = isOnChainLoading || isPortfolioLoading;
3053
+ const error = onChainError || portfolioError;
2611
3054
  const refetchAll = () => {
2612
3055
  if (depositOpportunity) {
2613
3056
  refetchOnChain();
2614
3057
  }
2615
3058
  refetchPortfolio();
2616
- refetchEnso();
2617
3059
  };
2618
3060
  return {
2619
3061
  balances: consolidatedBalances,
@@ -2623,10 +3065,51 @@ function useBalance({
2623
3065
  };
2624
3066
  }
2625
3067
 
3068
+ // src/v2/balance/hooks/useEnsoBalances.ts
3069
+ var import_react11 = require("react");
3070
+ function useEnsoBalances({
3071
+ address,
3072
+ chainIds
3073
+ }) {
3074
+ const { getToken, isLoading: isSupportedTokensLoading } = useSupportedTokens();
3075
+ const {
3076
+ balances: ensoBalances,
3077
+ isLoading,
3078
+ error,
3079
+ refetchAll
3080
+ } = useMultiChainBalances({
3081
+ chainIds,
3082
+ address
3083
+ });
3084
+ const balances = (0, import_react11.useMemo)(() => {
3085
+ if (isSupportedTokensLoading || isLoading) return [];
3086
+ const tokenBalances = [];
3087
+ Object.entries(ensoBalances).forEach(([, chainBalances]) => {
3088
+ chainBalances.forEach((walletBalance) => {
3089
+ const chainId = walletBalance.token.chain.toString();
3090
+ const token = getToken(walletBalance.token.address, chainId);
3091
+ if (!token) return;
3092
+ tokenBalances.push({
3093
+ token,
3094
+ amount: walletBalance.amount,
3095
+ source: "enso"
3096
+ });
3097
+ });
3098
+ });
3099
+ return tokenBalances;
3100
+ }, [ensoBalances, getToken, isSupportedTokensLoading, isLoading]);
3101
+ return {
3102
+ balances,
3103
+ isLoading,
3104
+ error,
3105
+ refetch: refetchAll
3106
+ };
3107
+ }
3108
+
2626
3109
  // src/v2/widget/hooks.ts
2627
- var import_react_query12 = require("@tanstack/react-query");
3110
+ var import_react_query13 = require("@tanstack/react-query");
2628
3111
  function useWidgetOpportunities(distributorId) {
2629
- return (0, import_react_query12.useQuery)({
3112
+ return (0, import_react_query13.useQuery)({
2630
3113
  ...widgetQueries.opportunities(distributorId),
2631
3114
  ...queryDefaults,
2632
3115
  select: (data) => {
@@ -2650,7 +3133,7 @@ function useWidgetOpportunities(distributorId) {
2650
3133
  }
2651
3134
 
2652
3135
  // src/v2/geocheck/useGeocheck.ts
2653
- var import_react_query13 = require("@tanstack/react-query");
3136
+ var import_react_query14 = require("@tanstack/react-query");
2654
3137
  var INDEXER_ENDPOINT = "https://api.turtle.xyz";
2655
3138
  async function fetchGeocheck() {
2656
3139
  const url = `${INDEXER_ENDPOINT}/turtle/geocheck`;
@@ -2666,13 +3149,13 @@ async function fetchGeocheck() {
2666
3149
  }
2667
3150
  return data;
2668
3151
  }
2669
- var geocheckQueryOptions = () => (0, import_react_query13.queryOptions)({
3152
+ var geocheckQueryOptions = () => (0, import_react_query14.queryOptions)({
2670
3153
  queryKey: ["geocheck"],
2671
3154
  queryFn: fetchGeocheck
2672
3155
  });
2673
3156
  function useGeocheck(options = {}) {
2674
3157
  const { enabled = true, staleTime, gcTime } = options;
2675
- return (0, import_react_query13.useQuery)({
3158
+ return (0, import_react_query14.useQuery)({
2676
3159
  ...geocheckQueryOptions(),
2677
3160
  enabled,
2678
3161
  staleTime: staleTime ?? 5 * 60 * 1e3,
@@ -2685,39 +3168,39 @@ function useGeocheck(options = {}) {
2685
3168
  }
2686
3169
 
2687
3170
  // src/v2/streams/hooks.ts
2688
- var import_react_query14 = require("@tanstack/react-query");
3171
+ var import_react_query15 = require("@tanstack/react-query");
2689
3172
  function useStreams({
2690
3173
  query,
2691
3174
  options
2692
3175
  } = {}) {
2693
- return (0, import_react_query14.useQuery)(createQueryOptions(streamsQueries.list(query), options));
3176
+ return (0, import_react_query15.useQuery)(createQueryOptions(streamsQueries.list(query), options));
2694
3177
  }
2695
3178
  function useStreamPoints({
2696
3179
  query,
2697
3180
  options
2698
3181
  } = {}) {
2699
- return (0, import_react_query14.useQuery)(createQueryOptions(streamsQueries.points(query), options));
3182
+ return (0, import_react_query15.useQuery)(createQueryOptions(streamsQueries.points(query), options));
2700
3183
  }
2701
3184
  function useStreamWallets({
2702
3185
  query,
2703
3186
  options
2704
3187
  }) {
2705
- return (0, import_react_query14.useQuery)(createQueryOptions(streamsQueries.wallets(query), options));
3188
+ return (0, import_react_query15.useQuery)(createQueryOptions(streamsQueries.wallets(query), options));
2706
3189
  }
2707
3190
  function useStreamWalletDetails({
2708
3191
  query,
2709
3192
  options
2710
3193
  }) {
2711
- return (0, import_react_query14.useQuery)(createQueryOptions(streamsQueries.walletDetails(query), options));
3194
+ return (0, import_react_query15.useQuery)(createQueryOptions(streamsQueries.walletDetails(query), options));
2712
3195
  }
2713
3196
  function useStreamSupportedChains({
2714
3197
  options
2715
3198
  } = {}) {
2716
- return (0, import_react_query14.useQuery)(createQueryOptions(streamsQueries.supportedChains, options));
3199
+ return (0, import_react_query15.useQuery)(createQueryOptions(streamsQueries.supportedChains, options));
2717
3200
  }
2718
3201
 
2719
3202
  // src/v2/swap/useSwapRoute.ts
2720
- var import_react8 = require("react");
3203
+ var import_react12 = require("react");
2721
3204
 
2722
3205
  // src/v2/swap/route-processor.ts
2723
3206
  var import_utils4 = require("@turtleclub/utils");
@@ -2776,7 +3259,7 @@ function toEnsoTokenAddress(address) {
2776
3259
  return address;
2777
3260
  }
2778
3261
  function useSwapRoute(isEnabled, userAddress, distributorId, options, referralCode) {
2779
- const params = (0, import_react8.useMemo)(() => {
3262
+ const params = (0, import_react12.useMemo)(() => {
2780
3263
  if (!options || !isEnabled) return void 0;
2781
3264
  return {
2782
3265
  ...options,
@@ -2785,7 +3268,7 @@ function useSwapRoute(isEnabled, userAddress, distributorId, options, referralCo
2785
3268
  referral_code: referralCode
2786
3269
  };
2787
3270
  }, [options, userAddress, distributorId, referralCode]);
2788
- const hasRequiredParams = (0, import_react8.useMemo)(() => {
3271
+ const hasRequiredParams = (0, import_react12.useMemo)(() => {
2789
3272
  return !!(userAddress && params?.token_in && params?.token_out && params?.amount && params?.chain && params?.slippage && params?.distributor_id);
2790
3273
  }, [options]);
2791
3274
  const { data, isLoading, error } = useEarnRoute({
@@ -2802,7 +3285,7 @@ function useSwapRoute(isEnabled, userAddress, distributorId, options, referralCo
2802
3285
  },
2803
3286
  enabled: hasRequiredParams && isEnabled
2804
3287
  });
2805
- const routeDetails = (0, import_react8.useMemo)(() => processRouteDetails(data ?? null), [data]);
3288
+ const routeDetails = (0, import_react12.useMemo)(() => processRouteDetails(data ?? null), [data]);
2806
3289
  return {
2807
3290
  fetchedRoute: data ?? null,
2808
3291
  outputAmount: data?.amount_out ?? void 0,
@@ -2815,9 +3298,9 @@ function useSwapRoute(isEnabled, userAddress, distributorId, options, referralCo
2815
3298
  }
2816
3299
 
2817
3300
  // src/v2/users/hooks.ts
2818
- var import_react_query15 = require("@tanstack/react-query");
3301
+ var import_react_query16 = require("@tanstack/react-query");
2819
3302
  function useUserById({ userId, enabled = true }) {
2820
- return (0, import_react_query15.useQuery)({
3303
+ return (0, import_react_query16.useQuery)({
2821
3304
  ...usersQueries.byId({ userId }),
2822
3305
  ...queryDefaults,
2823
3306
  enabled
@@ -2825,7 +3308,7 @@ function useUserById({ userId, enabled = true }) {
2825
3308
  }
2826
3309
  function useUserPortfolio({ userId, enabled = true }) {
2827
3310
  const input = { userId };
2828
- return (0, import_react_query15.useQuery)({
3311
+ return (0, import_react_query16.useQuery)({
2829
3312
  ...usersQueries.portfolio(input),
2830
3313
  ...queryDefaults,
2831
3314
  enabled
@@ -2833,17 +3316,17 @@ function useUserPortfolio({ userId, enabled = true }) {
2833
3316
  }
2834
3317
 
2835
3318
  // src/v2/nfts/hooks.ts
2836
- var import_react_query16 = require("@tanstack/react-query");
3319
+ var import_react_query17 = require("@tanstack/react-query");
2837
3320
  function useUserNfts({ userAddress, chain, tokenAddress }) {
2838
- return (0, import_react_query16.useQuery)(
3321
+ return (0, import_react_query17.useQuery)(
2839
3322
  userAddress ? createQueryOptions(nftsQueries.byUser(userAddress, chain), {
2840
3323
  select: (data) => tokenAddress ? data.filter((nft) => nft.token.toLowerCase() === tokenAddress.toLowerCase()) : data
2841
- }) : { queryKey: ["nfts", "byUser", "skip"], queryFn: import_react_query16.skipToken }
3324
+ }) : { queryKey: ["nfts", "byUser", "skip"], queryFn: import_react_query17.skipToken }
2842
3325
  );
2843
3326
  }
2844
3327
 
2845
3328
  // src/v2/covers/hooks.ts
2846
- var import_react_query17 = require("@tanstack/react-query");
3329
+ var import_react_query18 = require("@tanstack/react-query");
2847
3330
 
2848
3331
  // src/v2/covers/schema.ts
2849
3332
  var import_zod16 = require("zod");
@@ -2875,7 +3358,7 @@ async function submitCoverRequest(data) {
2875
3358
 
2876
3359
  // src/v2/covers/hooks.ts
2877
3360
  function useSubmitCoverRequest(options) {
2878
- return (0, import_react_query17.useMutation)({
3361
+ return (0, import_react_query18.useMutation)({
2879
3362
  mutationFn: submitCoverRequest,
2880
3363
  onSuccess: () => {
2881
3364
  options?.onSuccess?.("Cover request submitted successfully!");
@@ -2887,6 +3370,124 @@ function useSubmitCoverRequest(options) {
2887
3370
  });
2888
3371
  }
2889
3372
 
3373
+ // src/v2/membership-flow/hooks.ts
3374
+ var import_react13 = require("react");
3375
+ var useTurtleMembershipFlow = ({
3376
+ address,
3377
+ walletEcosystem = "evm",
3378
+ signMessage,
3379
+ chainId = "1",
3380
+ url,
3381
+ enabled = true,
3382
+ onError
3383
+ }) => {
3384
+ const previousAddressRef = (0, import_react13.useRef)(void 0);
3385
+ const isProcessingRef = (0, import_react13.useRef)(false);
3386
+ const {
3387
+ data: membershipData,
3388
+ isLoading: isCheckingMembership
3389
+ } = useCheckMembership({
3390
+ params: {
3391
+ address: address || "",
3392
+ walletEcosystem
3393
+ },
3394
+ enabled: !!address
3395
+ });
3396
+ const {
3397
+ mutateAsync: createAgreement,
3398
+ isPending: isCreatingAgreement,
3399
+ error: agreementError
3400
+ } = useCreateMembershipAgreement();
3401
+ const {
3402
+ mutateAsync: createMembership2,
3403
+ isPending: isCreatingMembership,
3404
+ error: membershipError
3405
+ } = useCreateMembership();
3406
+ const handleMembershipFlow = (0, import_react13.useCallback)(async (memberAddress) => {
3407
+ if (isProcessingRef.current) return;
3408
+ isProcessingRef.current = true;
3409
+ try {
3410
+ const agreementResult = await createAgreement({
3411
+ address: memberAddress,
3412
+ walletEcosystem,
3413
+ url: url || (typeof window !== "undefined" ? window.location.href : ""),
3414
+ chainId
3415
+ });
3416
+ let signature;
3417
+ try {
3418
+ signature = await signMessage(agreementResult.message);
3419
+ } catch (signError) {
3420
+ const errorMessage = signError?.message || "User rejected signature";
3421
+ if (onError) {
3422
+ await onError({
3423
+ type: "signature_rejected",
3424
+ message: errorMessage
3425
+ });
3426
+ }
3427
+ return;
3428
+ }
3429
+ const membershipResult = await createMembership2({
3430
+ address: memberAddress,
3431
+ walletEcosystem,
3432
+ signature,
3433
+ nonce: agreementResult.nonce
3434
+ });
3435
+ if (!membershipResult.isMember && membershipResult.error) {
3436
+ const errorMessage = membershipResult.error;
3437
+ if (onError) {
3438
+ await onError({
3439
+ type: "membership_failed",
3440
+ message: errorMessage
3441
+ });
3442
+ }
3443
+ }
3444
+ } catch (error2) {
3445
+ const errorMessage = error2?.message || "Unknown error during membership flow";
3446
+ if (onError) {
3447
+ await onError({
3448
+ type: "membership_failed",
3449
+ message: errorMessage
3450
+ });
3451
+ }
3452
+ } finally {
3453
+ isProcessingRef.current = false;
3454
+ }
3455
+ }, [createAgreement, walletEcosystem, url, chainId, signMessage, createMembership2, onError]);
3456
+ (0, import_react13.useEffect)(() => {
3457
+ if (!enabled) return;
3458
+ const currentAddress = address;
3459
+ if (!currentAddress) {
3460
+ if (previousAddressRef.current !== void 0) {
3461
+ previousAddressRef.current = void 0;
3462
+ }
3463
+ return;
3464
+ }
3465
+ if (isCheckingMembership) {
3466
+ return;
3467
+ }
3468
+ if (currentAddress !== previousAddressRef.current) {
3469
+ previousAddressRef.current = currentAddress;
3470
+ if (membershipData?.isMember) {
3471
+ return;
3472
+ }
3473
+ handleMembershipFlow(currentAddress);
3474
+ }
3475
+ }, [address, enabled, isCheckingMembership, membershipData, handleMembershipFlow]);
3476
+ const refetch = async () => {
3477
+ if (address) {
3478
+ await handleMembershipFlow(address);
3479
+ }
3480
+ };
3481
+ const isLoading = isCheckingMembership || isCreatingAgreement || isCreatingMembership;
3482
+ const error = agreementError?.message || membershipError?.message || null;
3483
+ return {
3484
+ isMember: membershipData?.isMember,
3485
+ isLoading,
3486
+ error,
3487
+ refetch
3488
+ };
3489
+ };
3490
+
2890
3491
  // src/v2/organizations/schema.ts
2891
3492
  var import_zod17 = require("zod");
2892
3493
  var LeaveOrganizationInputSchema = import_zod17.z.object({
@@ -2912,9 +3513,9 @@ async function leaveOrganization(input) {
2912
3513
  }
2913
3514
 
2914
3515
  // src/v2/organizations/hooks.ts
2915
- var import_react_query18 = require("@tanstack/react-query");
3516
+ var import_react_query19 = require("@tanstack/react-query");
2916
3517
  function useLeaveOrganization(options) {
2917
- return (0, import_react_query18.useMutation)({
3518
+ return (0, import_react_query19.useMutation)({
2918
3519
  mutationFn: leaveOrganization,
2919
3520
  ...options
2920
3521
  });
@@ -3077,7 +3678,10 @@ var queries = (0, import_query_key_factory16.mergeQueryKeys)(
3077
3678
  productsQueries,
3078
3679
  queries,
3079
3680
  requestStreamSignature,
3681
+ routeMetadataSchema,
3682
+ routeStepSchema,
3080
3683
  routeToken,
3684
+ routeTokenSchema,
3081
3685
  routerStep,
3082
3686
  routerSubstep,
3083
3687
  snapshotSchema,
@@ -3116,7 +3720,11 @@ var queries = (0, import_query_key_factory16.mergeQueryKeys)(
3116
3720
  useCreateWithdrawInteraction,
3117
3721
  useDeleteProduct,
3118
3722
  useDepositAction,
3723
+ useDepositFlow,
3724
+ useDepositSelection,
3725
+ useDepositValidation,
3119
3726
  useDeposits,
3727
+ useEarnDeposit,
3120
3728
  useEarnOpportunities,
3121
3729
  useEarnRoute,
3122
3730
  useEnsoBalances,
@@ -3141,6 +3749,7 @@ var queries = (0, import_query_key_factory16.mergeQueryKeys)(
3141
3749
  useSupportedTokens,
3142
3750
  useSwapRoute,
3143
3751
  useTokenBalance,
3752
+ useTurtleMembershipFlow,
3144
3753
  useUpdateProduct,
3145
3754
  useUploadProductLogo,
3146
3755
  useUserById,