From 636e7beb8e34c36b7a6af10a3b9f4790af84950b Mon Sep 17 00:00:00 2001 From: Moein Date: Sat, 15 Nov 2025 21:42:59 +0330 Subject: [PATCH 1/5] chore: create hooks --- .gitignore | 1 + src/useStellar/index.ts | 14 +++--- src/useStellar/useAccount.ts | 3 -- src/useStellar/useAccounts.ts | 51 ++++++++++++++++++++++ src/useStellar/useAssets.ts | 55 +++++++++++++++++++++++ src/useStellar/useBalances.ts | 57 ++++++++++++++++++++++++ src/useStellar/useClaimableBalances.ts | 60 ++++++++++++++++++++++++++ src/useStellar/useEffects.ts | 57 ++++++++++++++++++++++++ src/useStellar/useLedgers.ts | 47 ++++++++++++++++++++ src/useStellar/useLiquidityPools.ts | 58 +++++++++++++++++++++++++ 10 files changed, 393 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 8fd3f19..7cca5d1 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ dist dist-ssr *.tgz *.local +demo # Editor directories and files .vscode/* diff --git a/src/useStellar/index.ts b/src/useStellar/index.ts index b3fd011..b116af8 100644 --- a/src/useStellar/index.ts +++ b/src/useStellar/index.ts @@ -1,13 +1,13 @@ export { networks } from '@bluxcc/core'; export * from './useAccount'; export * from './useNetwork'; -// import useAccounts from './useAccounts'; -// import useAssets from './useAssets'; -// import useBalances from './useBalances'; -// import useClaimableBalances from './useClaimableBalances'; -// import useEffects from './useEffects'; -// import useLedgers from './useLedgers'; -// import useLiquidityPools from './useLiquidityPools'; +export * from './useAccounts'; +// export * from './useAssets'; +export * from './useBalances'; +export * from './useClaimableBalances'; +export * from './useEffects'; +export * from './useLedgers'; +export * from './useLiquidityPools'; // import useNetwork from './useNetwork'; // import useOffers from './useOffers'; // import useOperations from './useOperations'; diff --git a/src/useStellar/useAccount.ts b/src/useStellar/useAccount.ts index 142b9ab..6ebd90e 100644 --- a/src/useStellar/useAccount.ts +++ b/src/useStellar/useAccount.ts @@ -12,9 +12,6 @@ export type UseAccountResult = { }; export function useAccount(options: GetAccountOptions): UseAccountResult { - // TODO: we need the same exact function as the core function here. - // Take the options.address, options.network, pass it to it, and wait for changes - // In useEffect. const [result, setResult] = useState(null); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); diff --git a/src/useStellar/useAccounts.ts b/src/useStellar/useAccounts.ts index e69de29..002ae04 100644 --- a/src/useStellar/useAccounts.ts +++ b/src/useStellar/useAccounts.ts @@ -0,0 +1,51 @@ +import { useState, useEffect } from "react"; +import { getAccounts } from "@bluxcc/core"; // or your local path +import { + GetAccountsOptions, + GetAccountsResult, +} from "@bluxcc/core/dist/exports/core/getAccounts"; + +export type UseAccountsResult = { + loading: boolean; + error: Error | null; + result: GetAccountsResult | null; +}; + +export function useAccounts(options: GetAccountsOptions): UseAccountsResult { + const [result, setResult] = useState(null); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(false); + + useEffect(() => { + if (!options.network) return; + + const fetchAccounts = async () => { + setLoading(true); + setError(null); + + try { + const accounts = await getAccounts(options); + setResult(accounts); + } catch (e) { + setError(e instanceof Error ? e : new Error(String(e))); + setResult(null); + } finally { + setLoading(false); + } + }; + + fetchAccounts(); + }, [ + options.network, + options.forSigner, + options.forAsset?.code, + options.forAsset?.issuer, + options.forLiquidityPool, + options.sponsor, + options.cursor, + options.limit, + options.order, + ]); + + return { loading, error, result }; +} diff --git a/src/useStellar/useAssets.ts b/src/useStellar/useAssets.ts index e69de29..cd0f7e1 100644 --- a/src/useStellar/useAssets.ts +++ b/src/useStellar/useAssets.ts @@ -0,0 +1,55 @@ +// Upon testing, it either gives "Bad Request" or "Custom network has no transports." + +import { useEffect, useState } from "react"; +import { getAssets } from "@bluxcc/core"; + +import { + GetAssetsOptions, + GetAssetsResult, +} from "@bluxcc/core/dist/exports/core/getAssets"; + +export type UseAssetsResult = { + loading: boolean; + error: Error | null; + result: GetAssetsResult | null; +}; + +export function useAssets(options: GetAssetsOptions): UseAssetsResult { + const [result, setResult] = useState(null); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(false); + + useEffect(() => { + let cancelled = false; + + setLoading(true); + setError(null); + + getAssets(options) + .then((r) => { + if (!cancelled) { + setResult(r); + setLoading(false); + } + }) + .catch((err) => { + if (!cancelled) { + setError(err); + setLoading(false); + } + }); + + return () => { + cancelled = true; + }; + }, [ + options.network, + options.cursor, + options.limit, + options.order, + options.forCode, + options.forIssuer, + ]); + + return { loading, error, result }; +} \ No newline at end of file diff --git a/src/useStellar/useBalances.ts b/src/useStellar/useBalances.ts index e69de29..98772a7 100644 --- a/src/useStellar/useBalances.ts +++ b/src/useStellar/useBalances.ts @@ -0,0 +1,57 @@ +import { useEffect, useState } from "react"; +import { getBalances } from '@bluxcc/core'; + +import { GetBalancesOptions, GetBalancesResult } from '@bluxcc/core/dist/exports/core/getBalances'; + +export type UseBalancesResult = { + loading: boolean; + error: Error | null; + balances: GetBalancesResult; +}; + +export function useBalances(options: GetBalancesOptions | undefined): UseBalancesResult { + const [balances, setBalances] = useState([]); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(false); + + useEffect(() => { + if (!options?.address) { + setBalances([]); + setError(null); + setLoading(false); + return; + } + + let cancelled = false; + + const run = async () => { + try { + setLoading(true); + setError(null); + + const result = await getBalances(options); + + if (!cancelled) { + setBalances(result ?? []); + } + } catch (e) { + if (!cancelled) { + setError(e instanceof Error ? e : new Error(String(e))); + setBalances([]); + } + } finally { + if (!cancelled) setLoading(false); + } + }; + + run(); + + return () => { + cancelled = true; + }; + }, [options?.address, options?.network, options?.includeZeroBalances]); + + return { loading, error, balances }; +} + +export default useBalances; \ No newline at end of file diff --git a/src/useStellar/useClaimableBalances.ts b/src/useStellar/useClaimableBalances.ts index e69de29..ef6892d 100644 --- a/src/useStellar/useClaimableBalances.ts +++ b/src/useStellar/useClaimableBalances.ts @@ -0,0 +1,60 @@ +// Gives "Issuer is invalid" + +import { useEffect, useState } from "react"; +import { getClaimableBalances } from "@bluxcc/core"; + +import { + GetClaimableBalancesOptions, + GetClaimableBalancesResult, +} from "@bluxcc/core/dist/exports/core/getClaimableBalances"; + +export type UseClaimableBalancesResult = { + loading: boolean; + error: Error | null; + result: GetClaimableBalancesResult | null; +}; + +export function useClaimableBalances( + options: GetClaimableBalancesOptions +): UseClaimableBalancesResult { + const [result, setResult] = useState(null); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(false); + + useEffect(() => { + let cancelled = false; + + setLoading(true); + setError(null); + setResult(null); + + getClaimableBalances(options) + .then((r) => { + if (!cancelled) { + setResult(r); + setLoading(false); + } + }) + .catch((err) => { + if (!cancelled) { + setError(err); + setLoading(false); + } + }); + + return () => { + cancelled = true; + }; + }, [ + options.network, + options.cursor, + options.limit, + options.order, + + options.asset, + options.claimant, + options.sponsor, + ]); + + return { loading, error, result }; +} diff --git a/src/useStellar/useEffects.ts b/src/useStellar/useEffects.ts index e69de29..b6cb0ed 100644 --- a/src/useStellar/useEffects.ts +++ b/src/useStellar/useEffects.ts @@ -0,0 +1,57 @@ +import { useEffect, useState } from "react"; +import { getEffects } from "@bluxcc/core"; + +import { + GetEffectsOptions, + GetEffectsResult, +} from "@bluxcc/core/dist/exports/core/getEffects"; + +export type UseEffectsResult = { + loading: boolean; + error: Error | null; + result: GetEffectsResult | null; +}; + +export function useEffects(options: GetEffectsOptions): UseEffectsResult { + const [result, setResult] = useState(null); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(false); + + useEffect(() => { + let cancelled = false; + + setLoading(true); + setError(null); + setResult(null); + + getEffects(options) + .then((res) => { + if (!cancelled) { + setResult(res); + setLoading(false); + } + }) + .catch((err) => { + if (!cancelled) { + setError(err); + setLoading(false); + } + }); + + return () => { + cancelled = true; + }; + }, [ + options.network, + options.cursor, + options.limit, + options.order, + options.forAccount, + options.forLedger, + options.forTransaction, + options.forOperation, + options.forLiquidityPool, + ]); + + return { loading, error, result }; +} diff --git a/src/useStellar/useLedgers.ts b/src/useStellar/useLedgers.ts index e69de29..3ee25e0 100644 --- a/src/useStellar/useLedgers.ts +++ b/src/useStellar/useLedgers.ts @@ -0,0 +1,47 @@ +import { useEffect, useState } from "react"; +import { getLedgers } from "@bluxcc/core"; + +import { + GetLedgersOptions, + GetLedgersResult, +} from "@bluxcc/core/dist/exports/core/getLedgers"; + +export type UseLedgersResult = { + loading: boolean; + error: Error | null; + result: GetLedgersResult | null; +}; + +export function useLedgers(options: GetLedgersOptions): UseLedgersResult { + const [result, setResult] = useState(null); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(false); + + useEffect(() => { + let cancelled = false; + + setLoading(true); + setError(null); + setResult(null); + + getLedgers(options) + .then((r) => { + if (!cancelled) { + setResult(r); + setLoading(false); + } + }) + .catch((err) => { + if (!cancelled) { + setError(err); + setLoading(false); + } + }); + + return () => { + cancelled = true; + }; + }, [options.network, options.cursor, options.limit, options.order, options.ledger]); + + return { loading, error, result }; +} diff --git a/src/useStellar/useLiquidityPools.ts b/src/useStellar/useLiquidityPools.ts index e69de29..3fd2c4b 100644 --- a/src/useStellar/useLiquidityPools.ts +++ b/src/useStellar/useLiquidityPools.ts @@ -0,0 +1,58 @@ +// Gives "Issuer is invalid" + +import { useEffect, useState } from "react"; +import { getLiquidityPools } from "@bluxcc/core"; + +import { + GetLiquidityPoolsOptions, + GetLiquidityPoolsResult, +} from "@bluxcc/core/dist/exports/core/getLiquidityPools"; + +export type UseLiquidityPoolsResult = { + loading: boolean; + error: Error | null; + result: GetLiquidityPoolsResult | null; +}; + +export function useLiquidityPools( + options: GetLiquidityPoolsOptions +): UseLiquidityPoolsResult { + const [result, setResult] = useState(null); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(false); + + useEffect(() => { + let cancelled = false; + + setLoading(true); + setError(null); + setResult(null); + + getLiquidityPools(options) + .then((r) => { + if (!cancelled) { + setResult(r); + setLoading(false); + } + }) + .catch((err) => { + if (!cancelled) { + setError(err); + setLoading(false); + } + }); + + return () => { + cancelled = true; + }; + }, [ + options.network, + options.cursor, + options.limit, + options.order, + options.forAccount, + options.forAssets, + ]); + + return { loading, error, result }; +} From 244977284e1a8f0439cc8d8624d952382478982b Mon Sep 17 00:00:00 2001 From: Moein Date: Mon, 24 Nov 2025 21:26:52 +0330 Subject: [PATCH 2/5] chore: update the parameters of useTransaction --- src/useStellar/useTransactions.ts | 359 ++++++++++++++++++++++++++++++ 1 file changed, 359 insertions(+) diff --git a/src/useStellar/useTransactions.ts b/src/useStellar/useTransactions.ts index e69de29..132b641 100644 --- a/src/useStellar/useTransactions.ts +++ b/src/useStellar/useTransactions.ts @@ -0,0 +1,359 @@ +import { useCallback, useEffect, useRef, useState } from "react"; +import { getTransactions as coreGetTransactions } from "@bluxcc/core"; + +import type { + GetTransactionsOptions as CoreGetTransactionsOptions, + GetTransactionsResult as CoreGetTransactionsResult, +} from "@bluxcc/core/dist/exports/core/getTransactions"; + +export type QueryOptions = { + enabled?: boolean; + retry?: boolean | number | ((failureCount: number, error: Error) => boolean); + retryDelay?: number | ((retryAttempt: number, error: Error) => number); + initialData?: CoreGetTransactionsResult | (() => CoreGetTransactionsResult); + initialDataUpdatedAt?: number | (() => number | undefined); + placeholderData?: + | CoreGetTransactionsResult + | (( + previousValue: CoreGetTransactionsResult | undefined, + previousQuery: UseTransactionsBaseResult | undefined + ) => CoreGetTransactionsResult); + notifyOnChangeProps?: string[] | "all" | (() => string[] | "all"); + refetchInterval?: + | number + | false + | ((data: CoreGetTransactionsResult | undefined, query: UseTransactionsBaseResult) => number | false | undefined); + refetchIntervalInBackground?: boolean; + staleTime?: number | typeof Infinity | undefined; + refetchOnMount?: boolean; + refetchOnWindowFocus?: boolean; + refetchOnReconnect?: boolean; + select?: (data: CoreGetTransactionsResult) => TSelect; +}; + +export type UseTransactionsBaseResult = { + data: TSelect | null; + result: CoreGetTransactionsResult | null; + + loading: boolean; + error: Error | null; + updatedAt: number | null; + failureCount: number; + refetch: () => Promise; + cancel: () => void; + + isStale: boolean; +}; + +export function useTransactions( + options: CoreGetTransactionsOptions, + queryOptions?: QueryOptions +): UseTransactionsBaseResult { + const enabled = queryOptions?.enabled !== false; + + const hasInitialized = useRef(false); + const prevStateRef = useRef | null>(null); + const cancelledRef = useRef(false); + + const retryTimerRef = useRef | null>(null); + const failureCountRef = useRef(0); + + const runSelect = useCallback( + (res: CoreGetTransactionsResult): TSelect | null => { + if (!queryOptions?.select) { + return (res as unknown) as TSelect; + } + try { + return queryOptions.select(res); + } catch (e) { + console.error("select() threw an error:", e); + return null; + } + }, + [queryOptions?.select] + ); + + const [result, setResult] = useState(() => { + if (queryOptions?.initialData) { + hasInitialized.current = true; + return typeof queryOptions.initialData === "function" + ? (queryOptions.initialData as () => CoreGetTransactionsResult)() + : queryOptions.initialData; + } + if (queryOptions?.placeholderData) { + return typeof queryOptions.placeholderData === "function" + ? queryOptions.placeholderData(undefined, undefined) + : queryOptions.placeholderData; + } + return null; + }); + + const [data, setData] = useState(() => { + const initial = queryOptions?.initialData + ? typeof queryOptions.initialData === "function" + ? (queryOptions.initialData as () => CoreGetTransactionsResult)() + : queryOptions.initialData + : queryOptions?.placeholderData + ? typeof queryOptions.placeholderData === "function" + ? queryOptions.placeholderData(undefined, undefined) + : queryOptions.placeholderData + : null; + + if (!initial) return null; + return runSelect(initial); + }); + + const [updatedAt, setUpdatedAt] = useState(() => { + if (queryOptions?.initialData && queryOptions?.initialDataUpdatedAt) { + const val = + typeof queryOptions.initialDataUpdatedAt === "function" + ? queryOptions.initialDataUpdatedAt() + : queryOptions.initialDataUpdatedAt; + return typeof val === "number" ? val : null; + } + return null; + }); + + const [failureCount, setFailureCount] = useState(0); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(false); + + const shouldNotifyChange = useCallback( + (nextState: UseTransactionsBaseResult) => { + const rule = queryOptions?.notifyOnChangeProps; + if (!rule) return true; + + const prev = prevStateRef.current; + if (!prev) return true; + + const keys = typeof rule === "function" ? rule() : rule; + if (keys === "all") return true; + + for (const key of keys) { + if (prev[key as keyof UseTransactionsBaseResult] !== nextState[key as keyof UseTransactionsBaseResult]) { + return true; + } + } + return false; + }, + [queryOptions?.notifyOnChangeProps] + ); + + const clearRetryTimer = () => { + if (retryTimerRef.current) { + clearTimeout(retryTimerRef.current); + retryTimerRef.current = null; + } + }; + + const computeShouldRetry = (count: number, err: Error): boolean => { + const opt = queryOptions?.retry; + if (opt === undefined) { + return count < 3; + } + if (typeof opt === "boolean") { + return opt === true; + } + if (typeof opt === "number") { + return count < opt; + } + if (typeof opt === "function") { + try { + return Boolean(opt(count, err)); + } catch (e) { + console.warn("retry function threw", e); + return false; + } + } + return false; + }; + + const computeRetryDelayMs = (attempt: number, err?: Error): number => { + const opt = queryOptions?.retryDelay; + + const defaultDelay = Math.min(1000 * 2 ** (attempt - 1), 30000); + + if (opt === undefined) return defaultDelay; + if (typeof opt === "number") { + return Math.max(0, Math.floor(opt)); + } + if (typeof opt === "function") { + try { + const val = opt(attempt, err as Error); + return typeof val === "number" && !Number.isNaN(val) ? Math.max(0, Math.floor(val)) : defaultDelay; + } catch (e) { + console.warn("retryDelay function threw", e); + return defaultDelay; + } + } + return defaultDelay; + }; + + const isStale = useCallback((): boolean => { + const staleTimeVal = queryOptions?.staleTime ?? 0; + if (staleTimeVal === Infinity) return false; + if (updatedAt === null) return true; + return Date.now() - updatedAt >= (staleTimeVal || 0); + }, [queryOptions?.staleTime, updatedAt]); + + const runFetch = useCallback(async () => { + if (!enabled) return; + + clearRetryTimer(); + + setError(null); + setLoading(true); + cancelledRef.current = false; + + try { + const res = await coreGetTransactions(options); + if (cancelledRef.current) return; + + failureCountRef.current = 0; + setFailureCount(0); + clearRetryTimer(); + + const selected = runSelect(res); + + const now = Date.now(); + + const nextState: UseTransactionsBaseResult = { + data: selected, + result: res, + loading: false, + error: null, + updatedAt: now, + failureCount: 0, + refetch: async () => {}, + cancel: () => {}, + isStale: false, + }; + + nextState.refetch = refetch as any; + nextState.cancel = cancel as any; + + hasInitialized.current = true; + + if (shouldNotifyChange(nextState)) { + setResult(res); + setData(selected); + setError(null); + setUpdatedAt(now); + } + + prevStateRef.current = nextState; + } catch (err: any) { + if (cancelledRef.current) return; + const e = err instanceof Error ? err : new Error(String(err)); + + failureCountRef.current = (failureCountRef.current || 0) + 1; + setFailureCount(failureCountRef.current); + + setResult(null); + setData(null); + setError(e); + + const shouldRetry = computeShouldRetry(failureCountRef.current, e); + + if (shouldRetry) { + const delay = computeRetryDelayMs(failureCountRef.current, e); + clearRetryTimer(); + retryTimerRef.current = setTimeout(() => { + if (cancelledRef.current) return; + runFetch().catch(() => {}); + }, delay); + setLoading(false); + } else { + setLoading(false); + } + } + }, [options, enabled, shouldNotifyChange, runSelect, queryOptions?.retry, queryOptions?.retryDelay]); + + const refetch = useCallback(async () => { + clearRetryTimer(); + failureCountRef.current = 0; + setFailureCount(0); + cancelledRef.current = false; + await runFetch(); + }, [runFetch]); + + const cancel = useCallback(() => { + cancelledRef.current = true; + clearRetryTimer(); + setLoading(false); + }, []); + + const currentState: UseTransactionsBaseResult = { + data, + result, + loading, + error, + updatedAt, + failureCount, + refetch, + cancel, + isStale: isStale(), + }; + + prevStateRef.current = currentState; + + useEffect(() => { + if (!enabled) return; + + cancelledRef.current = false; + + const shouldInitialFetch = !hasInitialized.current || (hasInitialized.current && queryOptions?.refetchOnMount && isStale()); + + if (shouldInitialFetch) { + runFetch().catch(() => {}); + } + + return () => { + cancelledRef.current = true; + clearRetryTimer(); + }; + }, [runFetch, enabled, queryOptions?.refetchOnMount, queryOptions?.staleTime, updatedAt]); + + useEffect(() => { + if (!enabled) return; + + const onFocus = () => { + if (queryOptions?.refetchOnWindowFocus && isStale()) { + runFetch().catch(() => {}); + } + }; + + const onOnline = () => { + if (queryOptions?.refetchOnReconnect && isStale()) { + runFetch().catch(() => {}); + } + }; + + if (queryOptions?.refetchOnWindowFocus) { + window.addEventListener("focus", onFocus); + } + if (queryOptions?.refetchOnReconnect) { + window.addEventListener("online", onOnline); + } + + return () => { + if (queryOptions?.refetchOnWindowFocus) { + window.removeEventListener("focus", onFocus); + } + if (queryOptions?.refetchOnReconnect) { + window.removeEventListener("online", onOnline); + } + }; + }, [enabled, queryOptions?.refetchOnWindowFocus, queryOptions?.refetchOnReconnect, queryOptions?.staleTime, updatedAt, isStale, runFetch]); + + useEffect(() => { + return () => { + clearRetryTimer(); + cancelledRef.current = true; + }; + }, []); + + return currentState; +} + +export default useTransactions; \ No newline at end of file From 9e3f1908da9ee15dfc2dff61d447cab9f6eb7f32 Mon Sep 17 00:00:00 2001 From: Moein Date: Sat, 29 Nov 2025 16:44:06 +0330 Subject: [PATCH 3/5] chore: update the return types of useTransaction --- src/useStellar/useTransactions.ts | 250 +++++++++++++++++++++++++++--- 1 file changed, 232 insertions(+), 18 deletions(-) diff --git a/src/useStellar/useTransactions.ts b/src/useStellar/useTransactions.ts index 132b641..fe5a500 100644 --- a/src/useStellar/useTransactions.ts +++ b/src/useStellar/useTransactions.ts @@ -31,18 +31,40 @@ export type QueryOptions = { select?: (data: CoreGetTransactionsResult) => TSelect; }; +export type Status = "error" | "pending" | "success"; +export type FetchStatus = "fetching" | "idle" | "paused"; + export type UseTransactionsBaseResult = { data: TSelect | null; result: CoreGetTransactionsResult | null; loading: boolean; + isFetching: boolean; + fetchStatus: FetchStatus; + status: Status; error: Error | null; + updatedAt: number | null; + dataUpdatedAt: number | null; + errorUpdatedAt: number | null; failureCount: number; - refetch: () => Promise; + + refetch: () => Promise; cancel: () => void; isStale: boolean; + + isError: boolean; + isPending: boolean; + isSuccess: boolean; + isPaused: boolean; + isFetched: boolean; + isLoading: boolean; + isLoadingError: boolean; + isRefetchError: boolean; + isRefetching: boolean; + isFetchedAfterMount: boolean; + isPlaceholderData: boolean; }; export function useTransactions( @@ -58,6 +80,8 @@ export function useTransactions( const retryTimerRef = useRef | null>(null); const failureCountRef = useRef(0); + const mountedRef = useRef(false); + const runSelect = useCallback( (res: CoreGetTransactionsResult): TSelect | null => { if (!queryOptions?.select) { @@ -104,6 +128,10 @@ export function useTransactions( }); const [updatedAt, setUpdatedAt] = useState(() => { + return queryOptions?.initialData ? Date.now() : null; + }); + + const [dataUpdatedAt, setDataUpdatedAt] = useState(() => { if (queryOptions?.initialData && queryOptions?.initialDataUpdatedAt) { const val = typeof queryOptions.initialDataUpdatedAt === "function" @@ -114,10 +142,30 @@ export function useTransactions( return null; }); + const [errorUpdatedAt, setErrorUpdatedAt] = useState(null); + const [failureCount, setFailureCount] = useState(0); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); + const [fetchStatus, setFetchStatus] = useState(() => + enabled ? "idle" : "paused" + ); + + const [isFetched, setIsFetched] = useState(false); + + const [isLoading, setIsLoading] = useState(false); + + const [isLoadingError, setIsLoadingError] = useState(false); + + const [isRefetchError, setIsRefetchError] = useState(false); + + const [isPlaceholderData, setIsPlaceholderData] = useState(() => { + if (queryOptions?.initialData) return false; + if (queryOptions?.placeholderData) return true; + return false; + }); + const shouldNotifyChange = useCallback( (nextState: UseTransactionsBaseResult) => { const rule = queryOptions?.notifyOnChangeProps; @@ -192,17 +240,32 @@ export function useTransactions( const isStale = useCallback((): boolean => { const staleTimeVal = queryOptions?.staleTime ?? 0; if (staleTimeVal === Infinity) return false; - if (updatedAt === null) return true; - return Date.now() - updatedAt >= (staleTimeVal || 0); - }, [queryOptions?.staleTime, updatedAt]); + if (dataUpdatedAt === null) return true; + return Date.now() - dataUpdatedAt >= (staleTimeVal || 0); + }, [queryOptions?.staleTime, dataUpdatedAt]); - const runFetch = useCallback(async () => { - if (!enabled) return; + const [isFetchedAfterMount, setIsFetchedAfterMount] = useState(false); + + useEffect(() => { + mountedRef.current = true; + return () => { + mountedRef.current = false; + }; + }, []); + + const runFetch = useCallback(async (): Promise => { + if (!enabled) { + setFetchStatus("paused"); + return; + } clearRetryTimer(); setError(null); setLoading(true); + setFetchStatus("fetching"); + setIsLoadingError(false); + setIsRefetchError(false); cancelledRef.current = false; try { @@ -221,12 +284,28 @@ export function useTransactions( data: selected, result: res, loading: false, + isFetching: false, + fetchStatus: "idle", + isPaused: false, + status: "success", error: null, updatedAt: now, + dataUpdatedAt: now, + errorUpdatedAt: prevStateRef.current?.errorUpdatedAt ?? null, failureCount: 0, - refetch: async () => {}, + refetch: async () => res, cancel: () => {}, isStale: false, + isError: false, + isPending: false, + isSuccess: true, + isFetched: true, + isLoading: false, + isLoadingError: false, + isRefetchError: false, + isRefetching: false, + isFetchedAfterMount: mountedRef.current ? true : false, + isPlaceholderData: false, }; nextState.refetch = refetch as any; @@ -234,14 +313,36 @@ export function useTransactions( hasInitialized.current = true; + setIsFetched(true); + setIsLoadingError(false); + setIsRefetchError(false); + setIsPlaceholderData(false); + if (mountedRef.current) { + setIsFetchedAfterMount(true); + } + if (shouldNotifyChange(nextState)) { setResult(res); setData(selected); setError(null); setUpdatedAt(now); + setDataUpdatedAt(now); + setErrorUpdatedAt(nextState.errorUpdatedAt ?? null); + setFetchStatus("idle"); + setLoading(false); + } else { + setResult(res); + setData(selected); + setError(null); + setUpdatedAt(now); + setDataUpdatedAt(now); + setErrorUpdatedAt(nextState.errorUpdatedAt ?? null); + setFetchStatus("idle"); + setLoading(false); } prevStateRef.current = nextState; + return res; } catch (err: any) { if (cancelledRef.current) return; const e = err instanceof Error ? err : new Error(String(err)); @@ -249,9 +350,71 @@ export function useTransactions( failureCountRef.current = (failureCountRef.current || 0) + 1; setFailureCount(failureCountRef.current); - setResult(null); - setData(null); - setError(e); + const now = Date.now(); + + const firstFetchFailed = !hasInitialized.current; + const refetchFailed = !firstFetchFailed; + + const nextState: UseTransactionsBaseResult = { + data: null, + result: null, + loading: false, + isFetching: false, + fetchStatus: "idle", + isPaused: false, + status: "error", + error: e, + updatedAt: now, + dataUpdatedAt: dataUpdatedAt, + errorUpdatedAt: now, + failureCount: failureCountRef.current, + refetch: async () => undefined, + cancel: () => {}, + isStale: isStale(), + isError: true, + isPending: false, + isSuccess: false, + isFetched: true, + isLoading: false, + isLoadingError: firstFetchFailed, + isRefetchError: refetchFailed, + isRefetching: false, + isFetchedAfterMount: mountedRef.current ? true : false, + isPlaceholderData: false, + }; + + nextState.refetch = refetch as any; + nextState.cancel = cancel as any; + + setIsFetched(true); + if (firstFetchFailed) { + setIsLoadingError(true); + } + if (refetchFailed) { + setIsRefetchError(true); + } + setIsPlaceholderData(false); + if (mountedRef.current) { + setIsFetchedAfterMount(true); + } + + if (shouldNotifyChange(nextState)) { + setResult(null); + setData(null); + setError(e); + setUpdatedAt(now); + setErrorUpdatedAt(now); + setFetchStatus("idle"); + setLoading(false); + } else { + setError(e); + setUpdatedAt(now); + setErrorUpdatedAt(now); + setFetchStatus("idle"); + setLoading(false); + } + + prevStateRef.current = nextState; const shouldRetry = computeShouldRetry(failureCountRef.current, e); @@ -262,19 +425,20 @@ export function useTransactions( if (cancelledRef.current) return; runFetch().catch(() => {}); }, delay); - setLoading(false); - } else { - setLoading(false); } + + return undefined; } - }, [options, enabled, shouldNotifyChange, runSelect, queryOptions?.retry, queryOptions?.retryDelay]); + }, [options, enabled, shouldNotifyChange, runSelect, queryOptions?.retry, queryOptions?.retryDelay, dataUpdatedAt]); const refetch = useCallback(async () => { clearRetryTimer(); failureCountRef.current = 0; setFailureCount(0); cancelledRef.current = false; - await runFetch(); + setIsLoadingError(false); + setIsRefetchError(false); + return runFetch(); }, [runFetch]); const cancel = useCallback(() => { @@ -283,20 +447,62 @@ export function useTransactions( setLoading(false); }, []); + const status: Status = error ? "error" : !hasInitialized.current ? "pending" : "success"; + + const isError = status === "error"; + const isPending = status === "pending"; + const isSuccess = status === "success"; + + const derivedIsFetching = fetchStatus === "fetching"; + const derivedIsPaused = fetchStatus === "paused"; + + const derivedIsLoading = derivedIsFetching && isPending; + const derivedIsRefetching = derivedIsFetching && !isPending; + + useEffect(() => { + setIsLoading(derivedIsLoading); + }, [derivedIsLoading]); + const currentState: UseTransactionsBaseResult = { data, result, loading, + isFetching: derivedIsFetching, + fetchStatus, + isPaused: derivedIsPaused, + status, error, updatedAt, + dataUpdatedAt, + errorUpdatedAt, failureCount, refetch, cancel, isStale: isStale(), + + isError, + isPending, + isSuccess, + + isFetched, + isLoading, + isLoadingError, + isRefetchError, + isRefetching: derivedIsRefetching, + isFetchedAfterMount, + isPlaceholderData, }; prevStateRef.current = currentState; + useEffect(() => { + if (!enabled) { + setFetchStatus("paused"); + } else { + setFetchStatus((s) => (s === "fetching" ? s : "idle")); + } + }, [enabled]); + useEffect(() => { if (!enabled) return; @@ -312,7 +518,7 @@ export function useTransactions( cancelledRef.current = true; clearRetryTimer(); }; - }, [runFetch, enabled, queryOptions?.refetchOnMount, queryOptions?.staleTime, updatedAt]); + }, [runFetch, enabled, queryOptions?.refetchOnMount, queryOptions?.staleTime, dataUpdatedAt]); useEffect(() => { if (!enabled) return; @@ -344,7 +550,15 @@ export function useTransactions( window.removeEventListener("online", onOnline); } }; - }, [enabled, queryOptions?.refetchOnWindowFocus, queryOptions?.refetchOnReconnect, queryOptions?.staleTime, updatedAt, isStale, runFetch]); + }, [ + enabled, + queryOptions?.refetchOnWindowFocus, + queryOptions?.refetchOnReconnect, + queryOptions?.staleTime, + dataUpdatedAt, + isStale, + runFetch, + ]); useEffect(() => { return () => { @@ -356,4 +570,4 @@ export function useTransactions( return currentState; } -export default useTransactions; \ No newline at end of file +export default useTransactions; From 63ecb70068d794067e6526b2bb7e393bb94f7271 Mon Sep 17 00:00:00 2001 From: Moein Date: Tue, 2 Dec 2025 20:14:23 +0330 Subject: [PATCH 4/5] feat: implement getAddress and getNetwork --- package.json | 1 + src/useStellar/index.ts | 2 +- src/useStellar/useBalances.ts | 106 ++- src/useStellar/useTransactions.ts | 1146 ++++++++++++++--------------- src/utils.ts | 34 + 5 files changed, 660 insertions(+), 629 deletions(-) create mode 100644 src/utils.ts diff --git a/package.json b/package.json index b63fb71..037336d 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ }, "peerDependencies": { "@bluxcc/core": "^0.1.16", + "@tanstack/react-query": "^5.90.11", "react": ">=17.0.0", "react-dom": ">=17.0.0" }, diff --git a/src/useStellar/index.ts b/src/useStellar/index.ts index b116af8..ec54adf 100644 --- a/src/useStellar/index.ts +++ b/src/useStellar/index.ts @@ -17,5 +17,5 @@ export * from './useLiquidityPools'; // import useStrictSendPaths from './useStrictSendPaths'; // import useTradeAggregation from './useTradeAggregation'; // import useTrades from './useTrades'; -// import useTransactions from './useTransactions'; +// export * from './useTransactions'; export { useSwitchNetwork } from './useSwitchNetwork'; diff --git a/src/useStellar/useBalances.ts b/src/useStellar/useBalances.ts index 98772a7..e4ce8e6 100644 --- a/src/useStellar/useBalances.ts +++ b/src/useStellar/useBalances.ts @@ -1,57 +1,53 @@ -import { useEffect, useState } from "react"; -import { getBalances } from '@bluxcc/core'; - -import { GetBalancesOptions, GetBalancesResult } from '@bluxcc/core/dist/exports/core/getBalances'; - -export type UseBalancesResult = { - loading: boolean; - error: Error | null; - balances: GetBalancesResult; -}; - -export function useBalances(options: GetBalancesOptions | undefined): UseBalancesResult { - const [balances, setBalances] = useState([]); - const [error, setError] = useState(null); - const [loading, setLoading] = useState(false); - - useEffect(() => { - if (!options?.address) { - setBalances([]); - setError(null); - setLoading(false); - return; - } - - let cancelled = false; - - const run = async () => { - try { - setLoading(true); - setError(null); - - const result = await getBalances(options); - - if (!cancelled) { - setBalances(result ?? []); - } - } catch (e) { - if (!cancelled) { - setError(e instanceof Error ? e : new Error(String(e))); - setBalances([]); - } - } finally { - if (!cancelled) setLoading(false); - } - }; - - run(); - - return () => { - cancelled = true; - }; - }, [options?.address, options?.network, options?.includeZeroBalances]); - - return { loading, error, balances }; +import { useMemo } from "react"; +import { useQuery, UseQueryOptions, UseQueryResult } from "@tanstack/react-query"; +import { getBalances } from "@bluxcc/core"; +import type { + GetBalancesOptions, + GetBalancesResult, +} from "@bluxcc/core/dist/exports/core/getBalances"; +import { getAddress, getNetwork } from "../utils"; + +export function useBalances( + options?: GetBalancesOptions, + queryOptions?: UseQueryOptions +): UseQueryResult { + + const address = getAddress(options?.address); + const network = getNetwork(options?.network); + + const enabled = !!address && (queryOptions?.enabled ?? true); + + const queryKey = useMemo( + () => [ + "blux", + "balances", + address ?? null, + network ?? null, + Boolean(options?.includeZeroBalances), + ], + [address, network, options?.includeZeroBalances] + ); + + const queryFn = useMemo( + () => async () => { + const opts: GetBalancesOptions = { + address: options?.address, + network: options?.network, + includeZeroBalances: options?.includeZeroBalances, + }; + return getBalances(opts); + }, + [options?.address, options?.network, options?.includeZeroBalances] + ); + + const result = useQuery({ + queryKey, + queryFn, + enabled, + ...queryOptions, + }); + + return result; } -export default useBalances; \ No newline at end of file +export default useBalances; diff --git a/src/useStellar/useTransactions.ts b/src/useStellar/useTransactions.ts index fe5a500..3a41cc8 100644 --- a/src/useStellar/useTransactions.ts +++ b/src/useStellar/useTransactions.ts @@ -1,573 +1,573 @@ -import { useCallback, useEffect, useRef, useState } from "react"; -import { getTransactions as coreGetTransactions } from "@bluxcc/core"; - -import type { - GetTransactionsOptions as CoreGetTransactionsOptions, - GetTransactionsResult as CoreGetTransactionsResult, -} from "@bluxcc/core/dist/exports/core/getTransactions"; - -export type QueryOptions = { - enabled?: boolean; - retry?: boolean | number | ((failureCount: number, error: Error) => boolean); - retryDelay?: number | ((retryAttempt: number, error: Error) => number); - initialData?: CoreGetTransactionsResult | (() => CoreGetTransactionsResult); - initialDataUpdatedAt?: number | (() => number | undefined); - placeholderData?: - | CoreGetTransactionsResult - | (( - previousValue: CoreGetTransactionsResult | undefined, - previousQuery: UseTransactionsBaseResult | undefined - ) => CoreGetTransactionsResult); - notifyOnChangeProps?: string[] | "all" | (() => string[] | "all"); - refetchInterval?: - | number - | false - | ((data: CoreGetTransactionsResult | undefined, query: UseTransactionsBaseResult) => number | false | undefined); - refetchIntervalInBackground?: boolean; - staleTime?: number | typeof Infinity | undefined; - refetchOnMount?: boolean; - refetchOnWindowFocus?: boolean; - refetchOnReconnect?: boolean; - select?: (data: CoreGetTransactionsResult) => TSelect; -}; - -export type Status = "error" | "pending" | "success"; -export type FetchStatus = "fetching" | "idle" | "paused"; - -export type UseTransactionsBaseResult = { - data: TSelect | null; - result: CoreGetTransactionsResult | null; - - loading: boolean; - isFetching: boolean; - fetchStatus: FetchStatus; - status: Status; - error: Error | null; - - updatedAt: number | null; - dataUpdatedAt: number | null; - errorUpdatedAt: number | null; - failureCount: number; - - refetch: () => Promise; - cancel: () => void; - - isStale: boolean; - - isError: boolean; - isPending: boolean; - isSuccess: boolean; - isPaused: boolean; - isFetched: boolean; - isLoading: boolean; - isLoadingError: boolean; - isRefetchError: boolean; - isRefetching: boolean; - isFetchedAfterMount: boolean; - isPlaceholderData: boolean; -}; - -export function useTransactions( - options: CoreGetTransactionsOptions, - queryOptions?: QueryOptions -): UseTransactionsBaseResult { - const enabled = queryOptions?.enabled !== false; - - const hasInitialized = useRef(false); - const prevStateRef = useRef | null>(null); - const cancelledRef = useRef(false); - - const retryTimerRef = useRef | null>(null); - const failureCountRef = useRef(0); - - const mountedRef = useRef(false); - - const runSelect = useCallback( - (res: CoreGetTransactionsResult): TSelect | null => { - if (!queryOptions?.select) { - return (res as unknown) as TSelect; - } - try { - return queryOptions.select(res); - } catch (e) { - console.error("select() threw an error:", e); - return null; - } - }, - [queryOptions?.select] - ); - - const [result, setResult] = useState(() => { - if (queryOptions?.initialData) { - hasInitialized.current = true; - return typeof queryOptions.initialData === "function" - ? (queryOptions.initialData as () => CoreGetTransactionsResult)() - : queryOptions.initialData; - } - if (queryOptions?.placeholderData) { - return typeof queryOptions.placeholderData === "function" - ? queryOptions.placeholderData(undefined, undefined) - : queryOptions.placeholderData; - } - return null; - }); - - const [data, setData] = useState(() => { - const initial = queryOptions?.initialData - ? typeof queryOptions.initialData === "function" - ? (queryOptions.initialData as () => CoreGetTransactionsResult)() - : queryOptions.initialData - : queryOptions?.placeholderData - ? typeof queryOptions.placeholderData === "function" - ? queryOptions.placeholderData(undefined, undefined) - : queryOptions.placeholderData - : null; - - if (!initial) return null; - return runSelect(initial); - }); - - const [updatedAt, setUpdatedAt] = useState(() => { - return queryOptions?.initialData ? Date.now() : null; - }); - - const [dataUpdatedAt, setDataUpdatedAt] = useState(() => { - if (queryOptions?.initialData && queryOptions?.initialDataUpdatedAt) { - const val = - typeof queryOptions.initialDataUpdatedAt === "function" - ? queryOptions.initialDataUpdatedAt() - : queryOptions.initialDataUpdatedAt; - return typeof val === "number" ? val : null; - } - return null; - }); - - const [errorUpdatedAt, setErrorUpdatedAt] = useState(null); - - const [failureCount, setFailureCount] = useState(0); - const [error, setError] = useState(null); - const [loading, setLoading] = useState(false); - - const [fetchStatus, setFetchStatus] = useState(() => - enabled ? "idle" : "paused" - ); - - const [isFetched, setIsFetched] = useState(false); - - const [isLoading, setIsLoading] = useState(false); - - const [isLoadingError, setIsLoadingError] = useState(false); - - const [isRefetchError, setIsRefetchError] = useState(false); - - const [isPlaceholderData, setIsPlaceholderData] = useState(() => { - if (queryOptions?.initialData) return false; - if (queryOptions?.placeholderData) return true; - return false; - }); - - const shouldNotifyChange = useCallback( - (nextState: UseTransactionsBaseResult) => { - const rule = queryOptions?.notifyOnChangeProps; - if (!rule) return true; - - const prev = prevStateRef.current; - if (!prev) return true; - - const keys = typeof rule === "function" ? rule() : rule; - if (keys === "all") return true; - - for (const key of keys) { - if (prev[key as keyof UseTransactionsBaseResult] !== nextState[key as keyof UseTransactionsBaseResult]) { - return true; - } - } - return false; - }, - [queryOptions?.notifyOnChangeProps] - ); - - const clearRetryTimer = () => { - if (retryTimerRef.current) { - clearTimeout(retryTimerRef.current); - retryTimerRef.current = null; - } - }; - - const computeShouldRetry = (count: number, err: Error): boolean => { - const opt = queryOptions?.retry; - if (opt === undefined) { - return count < 3; - } - if (typeof opt === "boolean") { - return opt === true; - } - if (typeof opt === "number") { - return count < opt; - } - if (typeof opt === "function") { - try { - return Boolean(opt(count, err)); - } catch (e) { - console.warn("retry function threw", e); - return false; - } - } - return false; - }; - - const computeRetryDelayMs = (attempt: number, err?: Error): number => { - const opt = queryOptions?.retryDelay; - - const defaultDelay = Math.min(1000 * 2 ** (attempt - 1), 30000); - - if (opt === undefined) return defaultDelay; - if (typeof opt === "number") { - return Math.max(0, Math.floor(opt)); - } - if (typeof opt === "function") { - try { - const val = opt(attempt, err as Error); - return typeof val === "number" && !Number.isNaN(val) ? Math.max(0, Math.floor(val)) : defaultDelay; - } catch (e) { - console.warn("retryDelay function threw", e); - return defaultDelay; - } - } - return defaultDelay; - }; - - const isStale = useCallback((): boolean => { - const staleTimeVal = queryOptions?.staleTime ?? 0; - if (staleTimeVal === Infinity) return false; - if (dataUpdatedAt === null) return true; - return Date.now() - dataUpdatedAt >= (staleTimeVal || 0); - }, [queryOptions?.staleTime, dataUpdatedAt]); - - const [isFetchedAfterMount, setIsFetchedAfterMount] = useState(false); - - useEffect(() => { - mountedRef.current = true; - return () => { - mountedRef.current = false; - }; - }, []); - - const runFetch = useCallback(async (): Promise => { - if (!enabled) { - setFetchStatus("paused"); - return; - } - - clearRetryTimer(); - - setError(null); - setLoading(true); - setFetchStatus("fetching"); - setIsLoadingError(false); - setIsRefetchError(false); - cancelledRef.current = false; - - try { - const res = await coreGetTransactions(options); - if (cancelledRef.current) return; - - failureCountRef.current = 0; - setFailureCount(0); - clearRetryTimer(); - - const selected = runSelect(res); - - const now = Date.now(); - - const nextState: UseTransactionsBaseResult = { - data: selected, - result: res, - loading: false, - isFetching: false, - fetchStatus: "idle", - isPaused: false, - status: "success", - error: null, - updatedAt: now, - dataUpdatedAt: now, - errorUpdatedAt: prevStateRef.current?.errorUpdatedAt ?? null, - failureCount: 0, - refetch: async () => res, - cancel: () => {}, - isStale: false, - isError: false, - isPending: false, - isSuccess: true, - isFetched: true, - isLoading: false, - isLoadingError: false, - isRefetchError: false, - isRefetching: false, - isFetchedAfterMount: mountedRef.current ? true : false, - isPlaceholderData: false, - }; - - nextState.refetch = refetch as any; - nextState.cancel = cancel as any; - - hasInitialized.current = true; - - setIsFetched(true); - setIsLoadingError(false); - setIsRefetchError(false); - setIsPlaceholderData(false); - if (mountedRef.current) { - setIsFetchedAfterMount(true); - } - - if (shouldNotifyChange(nextState)) { - setResult(res); - setData(selected); - setError(null); - setUpdatedAt(now); - setDataUpdatedAt(now); - setErrorUpdatedAt(nextState.errorUpdatedAt ?? null); - setFetchStatus("idle"); - setLoading(false); - } else { - setResult(res); - setData(selected); - setError(null); - setUpdatedAt(now); - setDataUpdatedAt(now); - setErrorUpdatedAt(nextState.errorUpdatedAt ?? null); - setFetchStatus("idle"); - setLoading(false); - } - - prevStateRef.current = nextState; - return res; - } catch (err: any) { - if (cancelledRef.current) return; - const e = err instanceof Error ? err : new Error(String(err)); - - failureCountRef.current = (failureCountRef.current || 0) + 1; - setFailureCount(failureCountRef.current); - - const now = Date.now(); - - const firstFetchFailed = !hasInitialized.current; - const refetchFailed = !firstFetchFailed; - - const nextState: UseTransactionsBaseResult = { - data: null, - result: null, - loading: false, - isFetching: false, - fetchStatus: "idle", - isPaused: false, - status: "error", - error: e, - updatedAt: now, - dataUpdatedAt: dataUpdatedAt, - errorUpdatedAt: now, - failureCount: failureCountRef.current, - refetch: async () => undefined, - cancel: () => {}, - isStale: isStale(), - isError: true, - isPending: false, - isSuccess: false, - isFetched: true, - isLoading: false, - isLoadingError: firstFetchFailed, - isRefetchError: refetchFailed, - isRefetching: false, - isFetchedAfterMount: mountedRef.current ? true : false, - isPlaceholderData: false, - }; - - nextState.refetch = refetch as any; - nextState.cancel = cancel as any; - - setIsFetched(true); - if (firstFetchFailed) { - setIsLoadingError(true); - } - if (refetchFailed) { - setIsRefetchError(true); - } - setIsPlaceholderData(false); - if (mountedRef.current) { - setIsFetchedAfterMount(true); - } - - if (shouldNotifyChange(nextState)) { - setResult(null); - setData(null); - setError(e); - setUpdatedAt(now); - setErrorUpdatedAt(now); - setFetchStatus("idle"); - setLoading(false); - } else { - setError(e); - setUpdatedAt(now); - setErrorUpdatedAt(now); - setFetchStatus("idle"); - setLoading(false); - } - - prevStateRef.current = nextState; - - const shouldRetry = computeShouldRetry(failureCountRef.current, e); - - if (shouldRetry) { - const delay = computeRetryDelayMs(failureCountRef.current, e); - clearRetryTimer(); - retryTimerRef.current = setTimeout(() => { - if (cancelledRef.current) return; - runFetch().catch(() => {}); - }, delay); - } - - return undefined; - } - }, [options, enabled, shouldNotifyChange, runSelect, queryOptions?.retry, queryOptions?.retryDelay, dataUpdatedAt]); - - const refetch = useCallback(async () => { - clearRetryTimer(); - failureCountRef.current = 0; - setFailureCount(0); - cancelledRef.current = false; - setIsLoadingError(false); - setIsRefetchError(false); - return runFetch(); - }, [runFetch]); - - const cancel = useCallback(() => { - cancelledRef.current = true; - clearRetryTimer(); - setLoading(false); - }, []); - - const status: Status = error ? "error" : !hasInitialized.current ? "pending" : "success"; - - const isError = status === "error"; - const isPending = status === "pending"; - const isSuccess = status === "success"; - - const derivedIsFetching = fetchStatus === "fetching"; - const derivedIsPaused = fetchStatus === "paused"; - - const derivedIsLoading = derivedIsFetching && isPending; - const derivedIsRefetching = derivedIsFetching && !isPending; - - useEffect(() => { - setIsLoading(derivedIsLoading); - }, [derivedIsLoading]); - - const currentState: UseTransactionsBaseResult = { - data, - result, - loading, - isFetching: derivedIsFetching, - fetchStatus, - isPaused: derivedIsPaused, - status, - error, - updatedAt, - dataUpdatedAt, - errorUpdatedAt, - failureCount, - refetch, - cancel, - isStale: isStale(), - - isError, - isPending, - isSuccess, - - isFetched, - isLoading, - isLoadingError, - isRefetchError, - isRefetching: derivedIsRefetching, - isFetchedAfterMount, - isPlaceholderData, - }; - - prevStateRef.current = currentState; - - useEffect(() => { - if (!enabled) { - setFetchStatus("paused"); - } else { - setFetchStatus((s) => (s === "fetching" ? s : "idle")); - } - }, [enabled]); - - useEffect(() => { - if (!enabled) return; - - cancelledRef.current = false; - - const shouldInitialFetch = !hasInitialized.current || (hasInitialized.current && queryOptions?.refetchOnMount && isStale()); - - if (shouldInitialFetch) { - runFetch().catch(() => {}); - } - - return () => { - cancelledRef.current = true; - clearRetryTimer(); - }; - }, [runFetch, enabled, queryOptions?.refetchOnMount, queryOptions?.staleTime, dataUpdatedAt]); - - useEffect(() => { - if (!enabled) return; - - const onFocus = () => { - if (queryOptions?.refetchOnWindowFocus && isStale()) { - runFetch().catch(() => {}); - } - }; - - const onOnline = () => { - if (queryOptions?.refetchOnReconnect && isStale()) { - runFetch().catch(() => {}); - } - }; - - if (queryOptions?.refetchOnWindowFocus) { - window.addEventListener("focus", onFocus); - } - if (queryOptions?.refetchOnReconnect) { - window.addEventListener("online", onOnline); - } - - return () => { - if (queryOptions?.refetchOnWindowFocus) { - window.removeEventListener("focus", onFocus); - } - if (queryOptions?.refetchOnReconnect) { - window.removeEventListener("online", onOnline); - } - }; - }, [ - enabled, - queryOptions?.refetchOnWindowFocus, - queryOptions?.refetchOnReconnect, - queryOptions?.staleTime, - dataUpdatedAt, - isStale, - runFetch, - ]); - - useEffect(() => { - return () => { - clearRetryTimer(); - cancelledRef.current = true; - }; - }, []); - - return currentState; -} - -export default useTransactions; +// import { useCallback, useEffect, useRef, useState } from "react"; +// import { getTransactions as coreGetTransactions } from "@bluxcc/core"; + +// import type { +// GetTransactionsOptions as CoreGetTransactionsOptions, +// GetTransactionsResult as CoreGetTransactionsResult, +// } from "@bluxcc/core/dist/exports/core/getTransactions"; + +// export type QueryOptions = { +// enabled?: boolean; +// retry?: boolean | number | ((failureCount: number, error: Error) => boolean); +// retryDelay?: number | ((retryAttempt: number, error: Error) => number); +// initialData?: CoreGetTransactionsResult | (() => CoreGetTransactionsResult); +// initialDataUpdatedAt?: number | (() => number | undefined); +// placeholderData?: +// | CoreGetTransactionsResult +// | (( +// previousValue: CoreGetTransactionsResult | undefined, +// previousQuery: UseTransactionsBaseResult | undefined +// ) => CoreGetTransactionsResult); +// notifyOnChangeProps?: string[] | "all" | (() => string[] | "all"); +// refetchInterval?: +// | number +// | false +// | ((data: CoreGetTransactionsResult | undefined, query: UseTransactionsBaseResult) => number | false | undefined); +// refetchIntervalInBackground?: boolean; +// staleTime?: number | typeof Infinity | undefined; +// refetchOnMount?: boolean; +// refetchOnWindowFocus?: boolean; +// refetchOnReconnect?: boolean; +// select?: (data: CoreGetTransactionsResult) => TSelect; +// }; + +// export type Status = "error" | "pending" | "success"; +// export type FetchStatus = "fetching" | "idle" | "paused"; + +// export type UseTransactionsBaseResult = { +// data: TSelect | null; +// result: CoreGetTransactionsResult | null; + +// loading: boolean; +// isFetching: boolean; +// fetchStatus: FetchStatus; +// status: Status; +// error: Error | null; + +// updatedAt: number | null; +// dataUpdatedAt: number | null; +// errorUpdatedAt: number | null; +// failureCount: number; + +// refetch: () => Promise; +// cancel: () => void; + +// isStale: boolean; + +// isError: boolean; +// isPending: boolean; +// isSuccess: boolean; +// isPaused: boolean; +// isFetched: boolean; +// isLoading: boolean; +// isLoadingError: boolean; +// isRefetchError: boolean; +// isRefetching: boolean; +// isFetchedAfterMount: boolean; +// isPlaceholderData: boolean; +// }; + +// export function useTransactions( +// options: CoreGetTransactionsOptions, +// queryOptions?: QueryOptions +// ): UseTransactionsBaseResult { +// const enabled = queryOptions?.enabled !== false; + +// const hasInitialized = useRef(false); +// const prevStateRef = useRef | null>(null); +// const cancelledRef = useRef(false); + +// const retryTimerRef = useRef | null>(null); +// const failureCountRef = useRef(0); + +// const mountedRef = useRef(false); + +// const runSelect = useCallback( +// (res: CoreGetTransactionsResult): TSelect | null => { +// if (!queryOptions?.select) { +// return (res as unknown) as TSelect; +// } +// try { +// return queryOptions.select(res); +// } catch (e) { +// console.error("select() threw an error:", e); +// return null; +// } +// }, +// [queryOptions?.select] +// ); + +// const [result, setResult] = useState(() => { +// if (queryOptions?.initialData) { +// hasInitialized.current = true; +// return typeof queryOptions.initialData === "function" +// ? (queryOptions.initialData as () => CoreGetTransactionsResult)() +// : queryOptions.initialData; +// } +// if (queryOptions?.placeholderData) { +// return typeof queryOptions.placeholderData === "function" +// ? queryOptions.placeholderData(undefined, undefined) +// : queryOptions.placeholderData; +// } +// return null; +// }); + +// const [data, setData] = useState(() => { +// const initial = queryOptions?.initialData +// ? typeof queryOptions.initialData === "function" +// ? (queryOptions.initialData as () => CoreGetTransactionsResult)() +// : queryOptions.initialData +// : queryOptions?.placeholderData +// ? typeof queryOptions.placeholderData === "function" +// ? queryOptions.placeholderData(undefined, undefined) +// : queryOptions.placeholderData +// : null; + +// if (!initial) return null; +// return runSelect(initial); +// }); + +// const [updatedAt, setUpdatedAt] = useState(() => { +// return queryOptions?.initialData ? Date.now() : null; +// }); + +// const [dataUpdatedAt, setDataUpdatedAt] = useState(() => { +// if (queryOptions?.initialData && queryOptions?.initialDataUpdatedAt) { +// const val = +// typeof queryOptions.initialDataUpdatedAt === "function" +// ? queryOptions.initialDataUpdatedAt() +// : queryOptions.initialDataUpdatedAt; +// return typeof val === "number" ? val : null; +// } +// return null; +// }); + +// const [errorUpdatedAt, setErrorUpdatedAt] = useState(null); + +// const [failureCount, setFailureCount] = useState(0); +// const [error, setError] = useState(null); +// const [loading, setLoading] = useState(false); + +// const [fetchStatus, setFetchStatus] = useState(() => +// enabled ? "idle" : "paused" +// ); + +// const [isFetched, setIsFetched] = useState(false); + +// const [isLoading, setIsLoading] = useState(false); + +// const [isLoadingError, setIsLoadingError] = useState(false); + +// const [isRefetchError, setIsRefetchError] = useState(false); + +// const [isPlaceholderData, setIsPlaceholderData] = useState(() => { +// if (queryOptions?.initialData) return false; +// if (queryOptions?.placeholderData) return true; +// return false; +// }); + +// const shouldNotifyChange = useCallback( +// (nextState: UseTransactionsBaseResult) => { +// const rule = queryOptions?.notifyOnChangeProps; +// if (!rule) return true; + +// const prev = prevStateRef.current; +// if (!prev) return true; + +// const keys = typeof rule === "function" ? rule() : rule; +// if (keys === "all") return true; + +// for (const key of keys) { +// if (prev[key as keyof UseTransactionsBaseResult] !== nextState[key as keyof UseTransactionsBaseResult]) { +// return true; +// } +// } +// return false; +// }, +// [queryOptions?.notifyOnChangeProps] +// ); + +// const clearRetryTimer = () => { +// if (retryTimerRef.current) { +// clearTimeout(retryTimerRef.current); +// retryTimerRef.current = null; +// } +// }; + +// const computeShouldRetry = (count: number, err: Error): boolean => { +// const opt = queryOptions?.retry; +// if (opt === undefined) { +// return count < 3; +// } +// if (typeof opt === "boolean") { +// return opt === true; +// } +// if (typeof opt === "number") { +// return count < opt; +// } +// if (typeof opt === "function") { +// try { +// return Boolean(opt(count, err)); +// } catch (e) { +// console.warn("retry function threw", e); +// return false; +// } +// } +// return false; +// }; + +// const computeRetryDelayMs = (attempt: number, err?: Error): number => { +// const opt = queryOptions?.retryDelay; + +// const defaultDelay = Math.min(1000 * 2 ** (attempt - 1), 30000); + +// if (opt === undefined) return defaultDelay; +// if (typeof opt === "number") { +// return Math.max(0, Math.floor(opt)); +// } +// if (typeof opt === "function") { +// try { +// const val = opt(attempt, err as Error); +// return typeof val === "number" && !Number.isNaN(val) ? Math.max(0, Math.floor(val)) : defaultDelay; +// } catch (e) { +// console.warn("retryDelay function threw", e); +// return defaultDelay; +// } +// } +// return defaultDelay; +// }; + +// const isStale = useCallback((): boolean => { +// const staleTimeVal = queryOptions?.staleTime ?? 0; +// if (staleTimeVal === Infinity) return false; +// if (dataUpdatedAt === null) return true; +// return Date.now() - dataUpdatedAt >= (staleTimeVal || 0); +// }, [queryOptions?.staleTime, dataUpdatedAt]); + +// const [isFetchedAfterMount, setIsFetchedAfterMount] = useState(false); + +// useEffect(() => { +// mountedRef.current = true; +// return () => { +// mountedRef.current = false; +// }; +// }, []); + +// const runFetch = useCallback(async (): Promise => { +// if (!enabled) { +// setFetchStatus("paused"); +// return; +// } + +// clearRetryTimer(); + +// setError(null); +// setLoading(true); +// setFetchStatus("fetching"); +// setIsLoadingError(false); +// setIsRefetchError(false); +// cancelledRef.current = false; + +// try { +// const res = await coreGetTransactions(options); +// if (cancelledRef.current) return; + +// failureCountRef.current = 0; +// setFailureCount(0); +// clearRetryTimer(); + +// const selected = runSelect(res); + +// const now = Date.now(); + +// const nextState: UseTransactionsBaseResult = { +// data: selected, +// result: res, +// loading: false, +// isFetching: false, +// fetchStatus: "idle", +// isPaused: false, +// status: "success", +// error: null, +// updatedAt: now, +// dataUpdatedAt: now, +// errorUpdatedAt: prevStateRef.current?.errorUpdatedAt ?? null, +// failureCount: 0, +// refetch: async () => res, +// cancel: () => {}, +// isStale: false, +// isError: false, +// isPending: false, +// isSuccess: true, +// isFetched: true, +// isLoading: false, +// isLoadingError: false, +// isRefetchError: false, +// isRefetching: false, +// isFetchedAfterMount: mountedRef.current ? true : false, +// isPlaceholderData: false, +// }; + +// nextState.refetch = refetch as any; +// nextState.cancel = cancel as any; + +// hasInitialized.current = true; + +// setIsFetched(true); +// setIsLoadingError(false); +// setIsRefetchError(false); +// setIsPlaceholderData(false); +// if (mountedRef.current) { +// setIsFetchedAfterMount(true); +// } + +// if (shouldNotifyChange(nextState)) { +// setResult(res); +// setData(selected); +// setError(null); +// setUpdatedAt(now); +// setDataUpdatedAt(now); +// setErrorUpdatedAt(nextState.errorUpdatedAt ?? null); +// setFetchStatus("idle"); +// setLoading(false); +// } else { +// setResult(res); +// setData(selected); +// setError(null); +// setUpdatedAt(now); +// setDataUpdatedAt(now); +// setErrorUpdatedAt(nextState.errorUpdatedAt ?? null); +// setFetchStatus("idle"); +// setLoading(false); +// } + +// prevStateRef.current = nextState; +// return res; +// } catch (err: any) { +// if (cancelledRef.current) return; +// const e = err instanceof Error ? err : new Error(String(err)); + +// failureCountRef.current = (failureCountRef.current || 0) + 1; +// setFailureCount(failureCountRef.current); + +// const now = Date.now(); + +// const firstFetchFailed = !hasInitialized.current; +// const refetchFailed = !firstFetchFailed; + +// const nextState: UseTransactionsBaseResult = { +// data: null, +// result: null, +// loading: false, +// isFetching: false, +// fetchStatus: "idle", +// isPaused: false, +// status: "error", +// error: e, +// updatedAt: now, +// dataUpdatedAt: dataUpdatedAt, +// errorUpdatedAt: now, +// failureCount: failureCountRef.current, +// refetch: async () => undefined, +// cancel: () => {}, +// isStale: isStale(), +// isError: true, +// isPending: false, +// isSuccess: false, +// isFetched: true, +// isLoading: false, +// isLoadingError: firstFetchFailed, +// isRefetchError: refetchFailed, +// isRefetching: false, +// isFetchedAfterMount: mountedRef.current ? true : false, +// isPlaceholderData: false, +// }; + +// nextState.refetch = refetch as any; +// nextState.cancel = cancel as any; + +// setIsFetched(true); +// if (firstFetchFailed) { +// setIsLoadingError(true); +// } +// if (refetchFailed) { +// setIsRefetchError(true); +// } +// setIsPlaceholderData(false); +// if (mountedRef.current) { +// setIsFetchedAfterMount(true); +// } + +// if (shouldNotifyChange(nextState)) { +// setResult(null); +// setData(null); +// setError(e); +// setUpdatedAt(now); +// setErrorUpdatedAt(now); +// setFetchStatus("idle"); +// setLoading(false); +// } else { +// setError(e); +// setUpdatedAt(now); +// setErrorUpdatedAt(now); +// setFetchStatus("idle"); +// setLoading(false); +// } + +// prevStateRef.current = nextState; + +// const shouldRetry = computeShouldRetry(failureCountRef.current, e); + +// if (shouldRetry) { +// const delay = computeRetryDelayMs(failureCountRef.current, e); +// clearRetryTimer(); +// retryTimerRef.current = setTimeout(() => { +// if (cancelledRef.current) return; +// runFetch().catch(() => {}); +// }, delay); +// } + +// return undefined; +// } +// }, [options, enabled, shouldNotifyChange, runSelect, queryOptions?.retry, queryOptions?.retryDelay, dataUpdatedAt]); + +// const refetch = useCallback(async () => { +// clearRetryTimer(); +// failureCountRef.current = 0; +// setFailureCount(0); +// cancelledRef.current = false; +// setIsLoadingError(false); +// setIsRefetchError(false); +// return runFetch(); +// }, [runFetch]); + +// const cancel = useCallback(() => { +// cancelledRef.current = true; +// clearRetryTimer(); +// setLoading(false); +// }, []); + +// const status: Status = error ? "error" : !hasInitialized.current ? "pending" : "success"; + +// const isError = status === "error"; +// const isPending = status === "pending"; +// const isSuccess = status === "success"; + +// const derivedIsFetching = fetchStatus === "fetching"; +// const derivedIsPaused = fetchStatus === "paused"; + +// const derivedIsLoading = derivedIsFetching && isPending; +// const derivedIsRefetching = derivedIsFetching && !isPending; + +// useEffect(() => { +// setIsLoading(derivedIsLoading); +// }, [derivedIsLoading]); + +// const currentState: UseTransactionsBaseResult = { +// data, +// result, +// loading, +// isFetching: derivedIsFetching, +// fetchStatus, +// isPaused: derivedIsPaused, +// status, +// error, +// updatedAt, +// dataUpdatedAt, +// errorUpdatedAt, +// failureCount, +// refetch, +// cancel, +// isStale: isStale(), + +// isError, +// isPending, +// isSuccess, + +// isFetched, +// isLoading, +// isLoadingError, +// isRefetchError, +// isRefetching: derivedIsRefetching, +// isFetchedAfterMount, +// isPlaceholderData, +// }; + +// prevStateRef.current = currentState; + +// useEffect(() => { +// if (!enabled) { +// setFetchStatus("paused"); +// } else { +// setFetchStatus((s) => (s === "fetching" ? s : "idle")); +// } +// }, [enabled]); + +// useEffect(() => { +// if (!enabled) return; + +// cancelledRef.current = false; + +// const shouldInitialFetch = !hasInitialized.current || (hasInitialized.current && queryOptions?.refetchOnMount && isStale()); + +// if (shouldInitialFetch) { +// runFetch().catch(() => {}); +// } + +// return () => { +// cancelledRef.current = true; +// clearRetryTimer(); +// }; +// }, [runFetch, enabled, queryOptions?.refetchOnMount, queryOptions?.staleTime, dataUpdatedAt]); + +// useEffect(() => { +// if (!enabled) return; + +// const onFocus = () => { +// if (queryOptions?.refetchOnWindowFocus && isStale()) { +// runFetch().catch(() => {}); +// } +// }; + +// const onOnline = () => { +// if (queryOptions?.refetchOnReconnect && isStale()) { +// runFetch().catch(() => {}); +// } +// }; + +// if (queryOptions?.refetchOnWindowFocus) { +// window.addEventListener("focus", onFocus); +// } +// if (queryOptions?.refetchOnReconnect) { +// window.addEventListener("online", onOnline); +// } + +// return () => { +// if (queryOptions?.refetchOnWindowFocus) { +// window.removeEventListener("focus", onFocus); +// } +// if (queryOptions?.refetchOnReconnect) { +// window.removeEventListener("online", onOnline); +// } +// }; +// }, [ +// enabled, +// queryOptions?.refetchOnWindowFocus, +// queryOptions?.refetchOnReconnect, +// queryOptions?.staleTime, +// dataUpdatedAt, +// isStale, +// runFetch, +// ]); + +// useEffect(() => { +// return () => { +// clearRetryTimer(); +// cancelledRef.current = true; +// }; +// }, []); + +// return currentState; +// } + +// export default useTransactions; diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..408579d --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,34 @@ +import { getState } from '@bluxcc/core'; + +export type CallBuilderOptions = { + cursor?: string; + limit?: number; + network?: string; + order?: 'asc' | 'desc'; +}; + +export const checkConfigCreated = () => { + const { stellar } = getState(); + + return !!stellar; +}; + +export const getAddress = (address?: string) => { + const { user } = getState(); + + if (address) { + return address; + } + + return user?.address as string; +}; + +export const getNetwork = (network?: string) => { + const { stellar } = getState(); + + if (!network && stellar) { + return stellar.activeNetwork; + } + + return network; +}; \ No newline at end of file From 5d33d8e8c42865a9e80fd086c0d28e12dc6ad540 Mon Sep 17 00:00:00 2001 From: Moein Date: Fri, 5 Dec 2025 00:48:18 +0330 Subject: [PATCH 5/5] fix: added getAddress support for hooks and options from dependencies --- package.json | 1 + src/Provider.tsx | 9 +- src/index.ts | 1 + src/useStellar/index.ts | 25 +- src/useStellar/useAccount.ts | 80 +-- src/useStellar/useAccounts.ts | 108 ++-- src/useStellar/useAssets.ts | 102 ++-- src/useStellar/useBalances.ts | 61 ++- src/useStellar/useClaimableBalances.ts | 108 ++-- src/useStellar/useEffects.ts | 109 ++-- src/useStellar/useLedgers.ts | 95 ++-- src/useStellar/useLiquidityPools.ts | 103 ++-- src/useStellar/useOffers.ts | 63 +++ src/useStellar/useOperations.ts | 64 +++ src/useStellar/useOrderbook.ts | 59 +++ src/useStellar/usePayments.ts | 65 +++ src/useStellar/useStrictReceivePaths.ts | 66 +++ src/useStellar/useStrictSendPaths.ts | 66 +++ src/useStellar/useTradeAggregation.ts | 72 +++ src/useStellar/useTrades.ts | 63 +++ src/useStellar/useTransactions.ts | 635 +++--------------------- src/useStellar/utils.ts | 35 -- 22 files changed, 1016 insertions(+), 974 deletions(-) delete mode 100644 src/useStellar/utils.ts diff --git a/package.json b/package.json index 037336d..7feb727 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "peerDependencies": { "@bluxcc/core": "^0.1.16", "@tanstack/react-query": "^5.90.11", + "@stellar/stellar-sdk": "^14.1.1", "react": ">=17.0.0", "react-dom": ">=17.0.0" }, diff --git a/src/Provider.tsx b/src/Provider.tsx index 0e15d0b..d297d1b 100644 --- a/src/Provider.tsx +++ b/src/Provider.tsx @@ -2,12 +2,15 @@ import React, { useEffect, useMemo, useRef } from 'react'; import { createConfig, setAppearance } from '@bluxcc/core'; import { IConfig } from '@bluxcc/core/dist/types'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; type BluxProviderProps = { config: IConfig; children: React.ReactNode | any; }; +const queryClient = new QueryClient(); + export const BluxProvider = ({ config, children }: BluxProviderProps) => { const hostRef = useRef(null); @@ -29,5 +32,9 @@ export const BluxProvider = ({ config, children }: BluxProviderProps) => { } }, [hostRef, appearance]); - return
{children}
; + return ( + +
{children}
; +
+ ); }; diff --git a/src/index.ts b/src/index.ts index 9e58487..e9121be 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ export { setAppearance } from '@bluxcc/core'; +export { Asset } from '@stellar/stellar-sdk' export * from './useStellar'; export { useBlux } from './hooks/useBlux'; diff --git a/src/useStellar/index.ts b/src/useStellar/index.ts index ec54adf..22d881a 100644 --- a/src/useStellar/index.ts +++ b/src/useStellar/index.ts @@ -1,21 +1,20 @@ export { networks } from '@bluxcc/core'; export * from './useAccount'; -export * from './useNetwork'; export * from './useAccounts'; -// export * from './useAssets'; +export * from './useAssets'; export * from './useBalances'; export * from './useClaimableBalances'; export * from './useEffects'; export * from './useLedgers'; export * from './useLiquidityPools'; -// import useNetwork from './useNetwork'; -// import useOffers from './useOffers'; -// import useOperations from './useOperations'; -// import useOrderbook from './useOrderbook'; -// import usePayments from './usePayments'; -// import useStrictReceivePaths from './useStrictReceivePaths'; -// import useStrictSendPaths from './useStrictSendPaths'; -// import useTradeAggregation from './useTradeAggregation'; -// import useTrades from './useTrades'; -// export * from './useTransactions'; -export { useSwitchNetwork } from './useSwitchNetwork'; +export * from './useNetwork'; +export * from './useOffers'; +export * from './useOperations'; +export * from './useOrderbook'; +export * from './usePayments'; +export * from './useStrictReceivePaths'; +export * from './useStrictSendPaths'; +export * from './useTradeAggregation'; +export * from './useTrades'; +export * from './useTransactions'; +export * from './useSwitchNetwork'; \ No newline at end of file diff --git a/src/useStellar/useAccount.ts b/src/useStellar/useAccount.ts index 6ebd90e..e295d23 100644 --- a/src/useStellar/useAccount.ts +++ b/src/useStellar/useAccount.ts @@ -1,35 +1,57 @@ +import { useMemo } from 'react'; import { getAccount } from '@bluxcc/core'; -import { useEffect, useState } from 'react'; import { + useQuery, + UseQueryResult, + UseQueryOptions, +} from '@tanstack/react-query'; +import type { GetAccountResult, GetAccountOptions, } from '@bluxcc/core/dist/exports/core/getAccount'; -export type UseAccountResult = { - loading: boolean; - error: Error | null; - result: GetAccountResult; -}; - -export function useAccount(options: GetAccountOptions): UseAccountResult { - const [result, setResult] = useState(null); - const [error, setError] = useState(null); - const [loading, setLoading] = useState(false); - - useEffect(() => { - setLoading(true); - - getAccount(options) - .then((r) => { - setResult(r); - - setLoading(false); - }) - .catch((e) => { - setError(e); - setLoading(false); - }); - }, [options.address, options.network]); - - return { loading, error, result }; -} +import { getAddress, getNetwork } from '../utils'; + +type R = GetAccountResult; +type O = GetAccountOptions; + +export function useAccount( + options?: O, + queryOptions?: UseQueryOptions, +): UseQueryResult { + const address = getAddress(options?.address); + const network = getNetwork(options?.network); + const enabled = queryOptions?.enabled ?? true; + + const deps = [ + address, + network, + ]; + + const queryKey = useMemo( + () => ['blux', 'account', network, ...deps], + [network, ...deps], + ); + + const queryFn = useMemo( + () => async () => { + const opts: O = { + ...options, + address, + network, + }; + + return getAccount(opts); + }, + [network, ...deps], + ); + + const result = useQuery({ + queryKey, + queryFn, + enabled, + ...queryOptions, + }); + + return result; +} \ No newline at end of file diff --git a/src/useStellar/useAccounts.ts b/src/useStellar/useAccounts.ts index 002ae04..58c4507 100644 --- a/src/useStellar/useAccounts.ts +++ b/src/useStellar/useAccounts.ts @@ -1,51 +1,61 @@ -import { useState, useEffect } from "react"; -import { getAccounts } from "@bluxcc/core"; // or your local path +import { useMemo } from 'react'; +import { getAccounts } from '@bluxcc/core'; import { - GetAccountsOptions, + useQuery, + UseQueryResult, + UseQueryOptions, +} from '@tanstack/react-query'; +import type { GetAccountsResult, -} from "@bluxcc/core/dist/exports/core/getAccounts"; - -export type UseAccountsResult = { - loading: boolean; - error: Error | null; - result: GetAccountsResult | null; -}; - -export function useAccounts(options: GetAccountsOptions): UseAccountsResult { - const [result, setResult] = useState(null); - const [error, setError] = useState(null); - const [loading, setLoading] = useState(false); - - useEffect(() => { - if (!options.network) return; - - const fetchAccounts = async () => { - setLoading(true); - setError(null); - - try { - const accounts = await getAccounts(options); - setResult(accounts); - } catch (e) { - setError(e instanceof Error ? e : new Error(String(e))); - setResult(null); - } finally { - setLoading(false); - } - }; - - fetchAccounts(); - }, [ - options.network, - options.forSigner, - options.forAsset?.code, - options.forAsset?.issuer, - options.forLiquidityPool, - options.sponsor, - options.cursor, - options.limit, - options.order, - ]); - - return { loading, error, result }; -} + GetAccountsOptions, +} from '@bluxcc/core/dist/exports/core/getAccounts'; + +import { getNetwork } from '../utils'; + +type R = GetAccountsResult; +type O = GetAccountsOptions; + +export function useAccounts( + options?: O, + queryOptions?: UseQueryOptions, +): UseQueryResult { + const network = getNetwork(options?.network); + const enabled = queryOptions?.enabled ?? true; + + const deps = [ + options?.forSigner, + options?.forAsset, + options?.sponsor, + options?.forLiquidityPool, + options?.cursor, + options?.limit, + options?.network, + options?.order, + ]; + + const queryKey = useMemo( + () => ['blux', 'accounts', network, ...deps], + [network, ...deps], + ); + + const queryFn = useMemo( + () => async () => { + const opts: O = { + ...options, + network, + }; + + return getAccounts(opts); + }, + [network, ...deps], + ); + + const result = useQuery({ + queryKey, + queryFn, + enabled, + ...queryOptions, + }); + + return result; +} \ No newline at end of file diff --git a/src/useStellar/useAssets.ts b/src/useStellar/useAssets.ts index cd0f7e1..d5ddd7c 100644 --- a/src/useStellar/useAssets.ts +++ b/src/useStellar/useAssets.ts @@ -1,55 +1,59 @@ -// Upon testing, it either gives "Bad Request" or "Custom network has no transports." - -import { useEffect, useState } from "react"; +import { useMemo } from 'react'; import { getAssets } from "@bluxcc/core"; - import { - GetAssetsOptions, + useQuery, + UseQueryResult, + UseQueryOptions, +} from '@tanstack/react-query'; +import type { GetAssetsResult, + GetAssetsOptions, } from "@bluxcc/core/dist/exports/core/getAssets"; -export type UseAssetsResult = { - loading: boolean; - error: Error | null; - result: GetAssetsResult | null; -}; - -export function useAssets(options: GetAssetsOptions): UseAssetsResult { - const [result, setResult] = useState(null); - const [error, setError] = useState(null); - const [loading, setLoading] = useState(false); - - useEffect(() => { - let cancelled = false; - - setLoading(true); - setError(null); - - getAssets(options) - .then((r) => { - if (!cancelled) { - setResult(r); - setLoading(false); - } - }) - .catch((err) => { - if (!cancelled) { - setError(err); - setLoading(false); - } - }); - - return () => { - cancelled = true; - }; - }, [ - options.network, - options.cursor, - options.limit, - options.order, - options.forCode, - options.forIssuer, - ]); - - return { loading, error, result }; +import { getNetwork } from '../utils'; + +type R = GetAssetsResult; +type O = GetAssetsOptions; + +export function useAssets( + options?: O, + queryOptions?: UseQueryOptions, +): UseQueryResult { + const network = getNetwork(options?.network); + const enabled = queryOptions?.enabled ?? true; + + const deps = [ + options?.forCode, + options?.forIssuer, + options?.cursor, + options?.limit, + options?.network, + options?.order, + ]; + + const queryKey = useMemo( + () => ['blux', 'assets', network, ...deps], + [network, options, ...deps], + ); + + const queryFn = useMemo( + () => async () => { + const opts: O = { + ...options, + network, + }; + + return getAssets(opts); + }, + [network, options, ...deps], + ); + + const result = useQuery({ + queryKey, + queryFn, + enabled, + ...queryOptions, + }); + + return result; } \ No newline at end of file diff --git a/src/useStellar/useBalances.ts b/src/useStellar/useBalances.ts index e4ce8e6..15734a1 100644 --- a/src/useStellar/useBalances.ts +++ b/src/useStellar/useBalances.ts @@ -1,46 +1,55 @@ -import { useMemo } from "react"; -import { useQuery, UseQueryOptions, UseQueryResult } from "@tanstack/react-query"; +import { useMemo } from 'react'; import { getBalances } from "@bluxcc/core"; +import { + useQuery, + UseQueryResult, + UseQueryOptions, +} from '@tanstack/react-query'; import type { - GetBalancesOptions, GetBalancesResult, + GetBalancesOptions, } from "@bluxcc/core/dist/exports/core/getBalances"; -import { getAddress, getNetwork } from "../utils"; -export function useBalances( - options?: GetBalancesOptions, - queryOptions?: UseQueryOptions -): UseQueryResult { +import { getAddress, getNetwork } from '../utils'; + +type R = GetBalancesResult; +type O = GetBalancesOptions; +export function useBalances( + options?: O, + queryOptions?: UseQueryOptions, +): UseQueryResult { const address = getAddress(options?.address); const network = getNetwork(options?.network); - - const enabled = !!address && (queryOptions?.enabled ?? true); + const enabled = queryOptions?.enabled ?? true; + const includeZeroBalances = options?.includeZeroBalances ?? true + + const deps = [ + address, + network, + includeZeroBalances, + ]; const queryKey = useMemo( - () => [ - "blux", - "balances", - address ?? null, - network ?? null, - Boolean(options?.includeZeroBalances), - ], - [address, network, options?.includeZeroBalances] + () => ['blux', 'balances', network, ...deps], + [network, ...deps], ); const queryFn = useMemo( () => async () => { - const opts: GetBalancesOptions = { - address: options?.address, - network: options?.network, - includeZeroBalances: options?.includeZeroBalances, + const opts: O = { + ...options, + address, + includeZeroBalances, + network, }; + return getBalances(opts); }, - [options?.address, options?.network, options?.includeZeroBalances] + [network, ...deps], ); - const result = useQuery({ + const result = useQuery({ queryKey, queryFn, enabled, @@ -48,6 +57,4 @@ export function useBalances( }); return result; -} - -export default useBalances; +} \ No newline at end of file diff --git a/src/useStellar/useClaimableBalances.ts b/src/useStellar/useClaimableBalances.ts index ef6892d..e056f93 100644 --- a/src/useStellar/useClaimableBalances.ts +++ b/src/useStellar/useClaimableBalances.ts @@ -1,60 +1,62 @@ -// Gives "Issuer is invalid" - -import { useEffect, useState } from "react"; +import { useMemo } from 'react'; import { getClaimableBalances } from "@bluxcc/core"; - import { - GetClaimableBalancesOptions, + useQuery, + UseQueryResult, + UseQueryOptions, +} from '@tanstack/react-query'; +import type { GetClaimableBalancesResult, + GetClaimableBalancesOptions, } from "@bluxcc/core/dist/exports/core/getClaimableBalances"; -export type UseClaimableBalancesResult = { - loading: boolean; - error: Error | null; - result: GetClaimableBalancesResult | null; -}; +import { getAddress, getNetwork } from '../utils'; + +type R = GetClaimableBalancesResult; +type O = GetClaimableBalancesOptions; export function useClaimableBalances( - options: GetClaimableBalancesOptions -): UseClaimableBalancesResult { - const [result, setResult] = useState(null); - const [error, setError] = useState(null); - const [loading, setLoading] = useState(false); - - useEffect(() => { - let cancelled = false; - - setLoading(true); - setError(null); - setResult(null); - - getClaimableBalances(options) - .then((r) => { - if (!cancelled) { - setResult(r); - setLoading(false); - } - }) - .catch((err) => { - if (!cancelled) { - setError(err); - setLoading(false); - } - }); - - return () => { - cancelled = true; - }; - }, [ - options.network, - options.cursor, - options.limit, - options.order, - - options.asset, - options.claimant, - options.sponsor, - ]); - - return { loading, error, result }; -} + options: O, + queryOptions?: UseQueryOptions, +): UseQueryResult { + const claimant = getAddress(options.claimant); + const network = getNetwork(options?.network); + const enabled = queryOptions?.enabled ?? true; + + const deps = [ + claimant, + options?.asset, + options?.sponsor, + options?.cursor, + options?.limit, + options?.network, + options?.order, + ]; + + const queryKey = useMemo( + () => ['blux', 'claimableBalances', network, ...deps], + [network, ...deps], + ); + + const queryFn = useMemo( + () => async () => { + const opts: O = { + ...options, + claimant, + network, + }; + + return getClaimableBalances(opts); + }, + [network, ...deps], + ); + + const result = useQuery({ + queryKey, + queryFn, + enabled, + ...queryOptions, + }); + + return result; +} \ No newline at end of file diff --git a/src/useStellar/useEffects.ts b/src/useStellar/useEffects.ts index b6cb0ed..5d86514 100644 --- a/src/useStellar/useEffects.ts +++ b/src/useStellar/useEffects.ts @@ -1,57 +1,62 @@ -import { useEffect, useState } from "react"; +import { useMemo } from 'react'; import { getEffects } from "@bluxcc/core"; - import { - GetEffectsOptions, + useQuery, + UseQueryResult, + UseQueryOptions, +} from '@tanstack/react-query'; +import type { GetEffectsResult, + GetEffectsOptions, } from "@bluxcc/core/dist/exports/core/getEffects"; -export type UseEffectsResult = { - loading: boolean; - error: Error | null; - result: GetEffectsResult | null; -}; - -export function useEffects(options: GetEffectsOptions): UseEffectsResult { - const [result, setResult] = useState(null); - const [error, setError] = useState(null); - const [loading, setLoading] = useState(false); - - useEffect(() => { - let cancelled = false; - - setLoading(true); - setError(null); - setResult(null); - - getEffects(options) - .then((res) => { - if (!cancelled) { - setResult(res); - setLoading(false); - } - }) - .catch((err) => { - if (!cancelled) { - setError(err); - setLoading(false); - } - }); - - return () => { - cancelled = true; - }; - }, [ - options.network, - options.cursor, - options.limit, - options.order, - options.forAccount, - options.forLedger, - options.forTransaction, - options.forOperation, - options.forLiquidityPool, - ]); - - return { loading, error, result }; -} +import { getNetwork } from '../utils'; + +type R = GetEffectsResult; +type O = GetEffectsOptions; + +export function useEffects( + options?: O, + queryOptions?: UseQueryOptions, +): UseQueryResult { + const network = getNetwork(options?.network); + const enabled = queryOptions?.enabled ?? true; + + const deps = [ + options?.forAccount, + options?.forLedger, + options?.forTransaction, + options?.forOperation, + options?.forLiquidityPool, + options?.cursor, + options?.limit, + options?.network, + options?.order, + ]; + + const queryKey = useMemo( + () => ['blux', 'effects', network, ...deps], + [network, ...deps], + ); + + const queryFn = useMemo( + () => async () => { + const opts: O = { + ...options, + network, + }; + + return getEffects(opts); + }, + [network, ...deps], + ); + + const result = useQuery({ + queryKey, + queryFn, + enabled, + ...queryOptions, + }); + + return result; +} \ No newline at end of file diff --git a/src/useStellar/useLedgers.ts b/src/useStellar/useLedgers.ts index 3ee25e0..6a8f36c 100644 --- a/src/useStellar/useLedgers.ts +++ b/src/useStellar/useLedgers.ts @@ -1,47 +1,58 @@ -import { useEffect, useState } from "react"; +import { useMemo } from 'react'; import { getLedgers } from "@bluxcc/core"; - import { - GetLedgersOptions, + useQuery, + UseQueryResult, + UseQueryOptions, +} from '@tanstack/react-query'; +import type { GetLedgersResult, + GetLedgersOptions, } from "@bluxcc/core/dist/exports/core/getLedgers"; -export type UseLedgersResult = { - loading: boolean; - error: Error | null; - result: GetLedgersResult | null; -}; - -export function useLedgers(options: GetLedgersOptions): UseLedgersResult { - const [result, setResult] = useState(null); - const [error, setError] = useState(null); - const [loading, setLoading] = useState(false); - - useEffect(() => { - let cancelled = false; - - setLoading(true); - setError(null); - setResult(null); - - getLedgers(options) - .then((r) => { - if (!cancelled) { - setResult(r); - setLoading(false); - } - }) - .catch((err) => { - if (!cancelled) { - setError(err); - setLoading(false); - } - }); - - return () => { - cancelled = true; - }; - }, [options.network, options.cursor, options.limit, options.order, options.ledger]); - - return { loading, error, result }; -} +import { getNetwork } from '../utils'; + +type R = GetLedgersResult; +type O = GetLedgersOptions; + +export function useLedgers( + options?: O, + queryOptions?: UseQueryOptions, +): UseQueryResult { + const network = getNetwork(options?.network); + const enabled = queryOptions?.enabled ?? true; + + const deps = [ + options?.ledger, + options?.cursor, + options?.limit, + options?.network, + options?.order, + ]; + + const queryKey = useMemo( + () => ['blux', 'ledgers', network, ...deps], + [network, options, ...deps], + ); + + const queryFn = useMemo( + () => async () => { + const opts: O = { + ...options, + network, + }; + + return getLedgers(opts); + }, + [network, options, ...deps], + ); + + const result = useQuery({ + queryKey, + queryFn, + enabled, + ...queryOptions, + }); + + return result; +} \ No newline at end of file diff --git a/src/useStellar/useLiquidityPools.ts b/src/useStellar/useLiquidityPools.ts index 3fd2c4b..c679401 100644 --- a/src/useStellar/useLiquidityPools.ts +++ b/src/useStellar/useLiquidityPools.ts @@ -1,58 +1,59 @@ -// Gives "Issuer is invalid" - -import { useEffect, useState } from "react"; +import { useMemo } from 'react'; import { getLiquidityPools } from "@bluxcc/core"; - import { - GetLiquidityPoolsOptions, + useQuery, + UseQueryResult, + UseQueryOptions, +} from '@tanstack/react-query'; +import type { GetLiquidityPoolsResult, + GetLiquidityPoolsOptions, } from "@bluxcc/core/dist/exports/core/getLiquidityPools"; -export type UseLiquidityPoolsResult = { - loading: boolean; - error: Error | null; - result: GetLiquidityPoolsResult | null; -}; +import { getNetwork } from '../utils'; + +type R = GetLiquidityPoolsResult; +type O = GetLiquidityPoolsOptions; export function useLiquidityPools( - options: GetLiquidityPoolsOptions -): UseLiquidityPoolsResult { - const [result, setResult] = useState(null); - const [error, setError] = useState(null); - const [loading, setLoading] = useState(false); - - useEffect(() => { - let cancelled = false; - - setLoading(true); - setError(null); - setResult(null); - - getLiquidityPools(options) - .then((r) => { - if (!cancelled) { - setResult(r); - setLoading(false); - } - }) - .catch((err) => { - if (!cancelled) { - setError(err); - setLoading(false); - } - }); - - return () => { - cancelled = true; - }; - }, [ - options.network, - options.cursor, - options.limit, - options.order, - options.forAccount, - options.forAssets, - ]); - - return { loading, error, result }; -} + options?: O, + queryOptions?: UseQueryOptions, +): UseQueryResult { + const network = getNetwork(options?.network); + const enabled = queryOptions?.enabled ?? true; + + const deps = [ + options?.forAccount, + options?.forAssets, + options?.cursor, + options?.limit, + options?.network, + options?.order, + ]; + + const queryKey = useMemo( + () => ['blux', 'liquidityPools', network, ...deps], + [network, ...deps], + ); + + const queryFn = useMemo( + () => async () => { + const opts: O = { + ...options, + network, + }; + + return getLiquidityPools(opts); + }, + [network, ...deps], + ); + + const result = useQuery({ + queryKey, + queryFn, + enabled, + ...queryOptions, + }); + + return result; +} \ No newline at end of file diff --git a/src/useStellar/useOffers.ts b/src/useStellar/useOffers.ts index e69de29..e612d71 100644 --- a/src/useStellar/useOffers.ts +++ b/src/useStellar/useOffers.ts @@ -0,0 +1,63 @@ +import { useMemo } from 'react'; +import { getOffers } from "@bluxcc/core"; +import { + useQuery, + UseQueryResult, + UseQueryOptions, +} from '@tanstack/react-query'; +import type { + GetOffersResult, + GetOffersOptions, +} from "@bluxcc/core/dist/exports/core/getOffers"; + +import { getNetwork } from '../utils'; + +type R = GetOffersResult; +type O = GetOffersOptions; + +export function useOffers( + options?: O, + queryOptions?: UseQueryOptions, +): UseQueryResult { + const network = getNetwork(options?.network); + const enabled = queryOptions?.enabled ?? true; + + const deps = [ + options?.forAccount, + options?.buying, + options?.selling, + options?.sponsor, + options?.seller, + options?.forAccount, + options?.cursor, + options?.limit, + options?.network, + options?.order, + ]; + + const queryKey = useMemo( + () => ['blux', 'offers', network, ...deps], + [network, ...deps], + ); + + const queryFn = useMemo( + () => async () => { + const opts: O = { + ...options, + network, + }; + + return getOffers(opts); + }, + [network, ...deps], + ); + + const result = useQuery({ + queryKey, + queryFn, + enabled, + ...queryOptions, + }); + + return result; +} \ No newline at end of file diff --git a/src/useStellar/useOperations.ts b/src/useStellar/useOperations.ts index e69de29..aab80bc 100644 --- a/src/useStellar/useOperations.ts +++ b/src/useStellar/useOperations.ts @@ -0,0 +1,64 @@ +import { useMemo } from 'react'; +import { getOperations } from "@bluxcc/core"; +import { + useQuery, + UseQueryResult, + UseQueryOptions, +} from '@tanstack/react-query'; +import type { + GetOperationsResult, + GetOperationsOptions, +} from "@bluxcc/core/dist/exports/core/getOperations"; + +import { getNetwork } from '../utils'; + +type R = GetOperationsResult; +type O = GetOperationsOptions; + +export function useOperations( + options?: O, + queryOptions?: UseQueryOptions, +): UseQueryResult { + const network = getNetwork(options?.network); + const enabled = queryOptions?.enabled ?? true; + + const deps = [ + options?.forAccount, + options?.includeFailed, + options?.forClaimableBalance, + options?.forLedger, + options?.forTransaction, + options?.forLiquidityPool, + options?.forAccount, + options?.cursor, + options?.limit, + options?.network, + options?.order, + ]; + + const queryKey = useMemo( + () => ['blux', 'operations', network, ...deps], + [network, ...deps], + ); + + const queryFn = useMemo( + () => async () => { + const opts: O = { + ...options, + network, + }; + + return getOperations(opts); + }, + [network, options, ...deps], + ); + + const result = useQuery({ + queryKey, + queryFn, + enabled, + ...queryOptions, + }); + + return result; +} \ No newline at end of file diff --git a/src/useStellar/useOrderbook.ts b/src/useStellar/useOrderbook.ts index e69de29..63bb39b 100644 --- a/src/useStellar/useOrderbook.ts +++ b/src/useStellar/useOrderbook.ts @@ -0,0 +1,59 @@ +import { useMemo } from 'react'; +import { getOrderbook } from "@bluxcc/core"; +import { + useQuery, + UseQueryResult, + UseQueryOptions, +} from '@tanstack/react-query'; +import type { + GetOrderbookResult +} from "@bluxcc/core/dist/exports/core/getOrderbook"; + +import { Asset } from '@stellar/stellar-sdk'; +import { CallBuilderOptions } from '../utils'; +import { getNetwork } from '../utils'; + +type R = GetOrderbookResult; +type O = CallBuilderOptions; + +export function useOrderbook( + args: [selling: Asset, buying: Asset], + options?: O, + queryOptions?: UseQueryOptions, +): UseQueryResult { + const network = getNetwork(options?.network); + const enabled = queryOptions?.enabled ?? true; + + const deps = [ + args[0], + args[1], + options?.cursor, + options?.limit, + options?.network, + options?.order, + ]; + + const queryKey = useMemo( + () => ['blux', 'orderbook', network, ...deps], + [network, options, ...deps], + ); + + const queryFn = useMemo( + () => async () => { + const opts: O = { + ...options, + network, + }; + + return getOrderbook(args, opts); + }, + [network, options, ...deps], + ); + + return useQuery({ + queryKey, + queryFn, + enabled, + ...queryOptions, + }); +} diff --git a/src/useStellar/usePayments.ts b/src/useStellar/usePayments.ts index e69de29..8b8cc6a 100644 --- a/src/useStellar/usePayments.ts +++ b/src/useStellar/usePayments.ts @@ -0,0 +1,65 @@ +import { useMemo } from 'react'; +import { getPayments } from "@bluxcc/core"; +import { + useQuery, + UseQueryResult, + UseQueryOptions, +} from '@tanstack/react-query'; +import type { + GetPaymentsOptions, +} from "@bluxcc/core/dist/exports/core/getPayments"; + +import { PaymentCallBuilder } from '@stellar/stellar-sdk/lib/horizon/payment_call_builder'; +import { ServerApi } from '@stellar/stellar-sdk/lib/horizon'; +import { getNetwork } from '../utils'; + +type R = { + builder: PaymentCallBuilder; + response: ServerApi.CollectionPage; +} +type O = GetPaymentsOptions; + +export function usePayments( + options?: O, + queryOptions?: UseQueryOptions, +): UseQueryResult { + const network = getNetwork(options?.network); + const enabled = queryOptions?.enabled ?? true; + + const deps = [ + options?.forAccount, + options?.includeFailed, + options?.forLedger, + options?.forTransaction, + options?.cursor, + options?.limit, + options?.network, + options?.order, + ]; + + const queryKey = useMemo( + () => ['blux', 'payments', network, ...deps], + [network, ...deps], + ); + + const queryFn = useMemo( + () => async () => { + const opts: O = { + ...options, + network, + }; + + return getPayments(opts); + }, + [network, ...deps], + ); + + const result = useQuery({ + queryKey, + queryFn, + enabled, + ...queryOptions, + }); + + return result; +} \ No newline at end of file diff --git a/src/useStellar/useStrictReceivePaths.ts b/src/useStellar/useStrictReceivePaths.ts index e69de29..ef9fdc3 100644 --- a/src/useStellar/useStrictReceivePaths.ts +++ b/src/useStellar/useStrictReceivePaths.ts @@ -0,0 +1,66 @@ +import { useMemo } from 'react'; +import { getStrictReceivePaths } from "@bluxcc/core"; +import { + useQuery, + UseQueryResult, + UseQueryOptions, +} from '@tanstack/react-query'; +import type { + GetPaymentPathResult +} from "@bluxcc/core/dist/exports/core/getStrictReceivePaths"; + +import { Asset } from '@stellar/stellar-sdk'; +import { CallBuilderOptions } from '../utils'; +import { getNetwork } from '../utils'; + +type R = GetPaymentPathResult; +type O = CallBuilderOptions; + +export function useStrictReceivePaths( + args: [ + source: string | Asset[], + destinationAsset: Asset, + destinationAmount: string, + ], + options?: O, + queryOptions?: UseQueryOptions, +): UseQueryResult { + const network = getNetwork(options?.network); + const enabled = queryOptions?.enabled ?? true; + + const deps = [ + args[0], + args[1], + args[2], + options?.cursor, + options?.limit, + options?.network, + options?.order, + ]; + + const queryKey = useMemo( + () => ['blux', 'strictReceivePaths', network, ...deps], + [network, options, ...deps], + ); + + const queryFn = useMemo( + () => async () => { + const opts: O = { + ...options, + network, + }; + + return getStrictReceivePaths(args, opts); + }, + [network, options, ...deps], + ); + + const result = useQuery({ + queryKey, + queryFn, + enabled, + ...queryOptions, + }); + + return result; +} \ No newline at end of file diff --git a/src/useStellar/useStrictSendPaths.ts b/src/useStellar/useStrictSendPaths.ts index e69de29..1ece36c 100644 --- a/src/useStellar/useStrictSendPaths.ts +++ b/src/useStellar/useStrictSendPaths.ts @@ -0,0 +1,66 @@ +import { useMemo } from 'react'; +import { getStrictSendPaths } from "@bluxcc/core"; +import { + useQuery, + UseQueryResult, + UseQueryOptions, +} from '@tanstack/react-query'; +import type { + GetPaymentPathResult +} from "@bluxcc/core/dist/exports/core/getStrictSendPaths"; + +import { Asset } from '@stellar/stellar-sdk'; +import { CallBuilderOptions } from '../utils'; +import { getNetwork } from '../utils'; + +type R = GetPaymentPathResult; +type O = CallBuilderOptions; + +export function useStrictSendPaths( + args: [ + sourceAsset: Asset, + sourceAmount: string, + destination: string | Asset[], + ], + options?: O, + queryOptions?: UseQueryOptions, +): UseQueryResult { + const network = getNetwork(options?.network); + const enabled = queryOptions?.enabled ?? true; + + const deps = [ + args[0], + args[1], + args[2], + options?.cursor, + options?.limit, + options?.network, + options?.order, + ]; + + const queryKey = useMemo( + () => ['blux', 'strictSendPaths', network, ...deps], + [network, options, ...deps], + ); + + const queryFn = useMemo( + () => async () => { + const opts: O = { + ...options, + network, + }; + + return getStrictSendPaths(args, opts); + }, + [network, options, ...deps], + ); + + const result = useQuery({ + queryKey, + queryFn, + enabled, + ...queryOptions, + }); + + return result; +} \ No newline at end of file diff --git a/src/useStellar/useTradeAggregation.ts b/src/useStellar/useTradeAggregation.ts index e69de29..68289ef 100644 --- a/src/useStellar/useTradeAggregation.ts +++ b/src/useStellar/useTradeAggregation.ts @@ -0,0 +1,72 @@ +import { useMemo } from 'react'; +import { getTradeAggregation } from "@bluxcc/core"; +import { + useQuery, + UseQueryResult, + UseQueryOptions, +} from '@tanstack/react-query'; +import type { + GetTradeAggregationResult +} from "@bluxcc/core/dist/exports/core/getTradeAggregation"; + +import { Asset } from '@stellar/stellar-sdk'; +import { CallBuilderOptions } from '../utils'; +import { getNetwork } from '../utils'; + +type R = GetTradeAggregationResult; +type O = CallBuilderOptions; + +export function useTradeAggregation( + args: [ + base: Asset, + counter: Asset, + start_time: number, + end_time: number, + resolution: number, + offset: number, + ], + options?: O, + queryOptions?: UseQueryOptions, +): UseQueryResult { + const network = getNetwork(options?.network); + const enabled = queryOptions?.enabled ?? true; + + const deps = [ + args[0], + args[1], + args[2], + args[3], + args[4], + args[5], + options?.cursor, + options?.limit, + options?.network, + options?.order, + ]; + + const queryKey = useMemo( + () => ['blux', 'tradeAggregation', network, ...deps], + [network, options, ...deps], + ); + + const queryFn = useMemo( + () => async () => { + const opts: O = { + ...options, + network, + }; + + return getTradeAggregation(args, opts); + }, + [network, options, ...deps], + ); + + const result = useQuery({ + queryKey, + queryFn, + enabled, + ...queryOptions, + }); + + return result; +} \ No newline at end of file diff --git a/src/useStellar/useTrades.ts b/src/useStellar/useTrades.ts index e69de29..36ccc45 100644 --- a/src/useStellar/useTrades.ts +++ b/src/useStellar/useTrades.ts @@ -0,0 +1,63 @@ +import { useMemo } from 'react'; +import { getTrades } from "@bluxcc/core"; +import { + useQuery, + UseQueryResult, + UseQueryOptions, +} from '@tanstack/react-query'; +import type { + GetTradesResult, + GetTradesOptions, +} from "@bluxcc/core/dist/exports/core/getTrades"; + +import { getNetwork } from '../utils'; + +type R = GetTradesResult; +type O = GetTradesOptions; + +export function useTrades( + options?: O, + queryOptions?: UseQueryOptions, +): UseQueryResult { + const network = getNetwork(options?.network); + const enabled = queryOptions?.enabled ?? true; + + const deps = [ + options?.forAccount, + options?.forAssetPair, + options?.forOffer, + options?.forType, + options?.forLiquidityPool, + options?.forAccount, + options?.cursor, + options?.limit, + options?.network, + options?.order, + ]; + + const queryKey = useMemo( + () => ['blux', 'trades', network, ...deps], + [network, ...deps], + ); + + const queryFn = useMemo( + () => async () => { + const opts: O = { + ...options, + network, + }; + + return getTrades(opts); + }, + [network, ...deps], + ); + + const result = useQuery({ + queryKey, + queryFn, + enabled, + ...queryOptions, + }); + + return result; +} \ No newline at end of file diff --git a/src/useStellar/useTransactions.ts b/src/useStellar/useTransactions.ts index 3a41cc8..c9f4eae 100644 --- a/src/useStellar/useTransactions.ts +++ b/src/useStellar/useTransactions.ts @@ -1,573 +1,62 @@ -// import { useCallback, useEffect, useRef, useState } from "react"; -// import { getTransactions as coreGetTransactions } from "@bluxcc/core"; - -// import type { -// GetTransactionsOptions as CoreGetTransactionsOptions, -// GetTransactionsResult as CoreGetTransactionsResult, -// } from "@bluxcc/core/dist/exports/core/getTransactions"; - -// export type QueryOptions = { -// enabled?: boolean; -// retry?: boolean | number | ((failureCount: number, error: Error) => boolean); -// retryDelay?: number | ((retryAttempt: number, error: Error) => number); -// initialData?: CoreGetTransactionsResult | (() => CoreGetTransactionsResult); -// initialDataUpdatedAt?: number | (() => number | undefined); -// placeholderData?: -// | CoreGetTransactionsResult -// | (( -// previousValue: CoreGetTransactionsResult | undefined, -// previousQuery: UseTransactionsBaseResult | undefined -// ) => CoreGetTransactionsResult); -// notifyOnChangeProps?: string[] | "all" | (() => string[] | "all"); -// refetchInterval?: -// | number -// | false -// | ((data: CoreGetTransactionsResult | undefined, query: UseTransactionsBaseResult) => number | false | undefined); -// refetchIntervalInBackground?: boolean; -// staleTime?: number | typeof Infinity | undefined; -// refetchOnMount?: boolean; -// refetchOnWindowFocus?: boolean; -// refetchOnReconnect?: boolean; -// select?: (data: CoreGetTransactionsResult) => TSelect; -// }; - -// export type Status = "error" | "pending" | "success"; -// export type FetchStatus = "fetching" | "idle" | "paused"; - -// export type UseTransactionsBaseResult = { -// data: TSelect | null; -// result: CoreGetTransactionsResult | null; - -// loading: boolean; -// isFetching: boolean; -// fetchStatus: FetchStatus; -// status: Status; -// error: Error | null; - -// updatedAt: number | null; -// dataUpdatedAt: number | null; -// errorUpdatedAt: number | null; -// failureCount: number; - -// refetch: () => Promise; -// cancel: () => void; - -// isStale: boolean; - -// isError: boolean; -// isPending: boolean; -// isSuccess: boolean; -// isPaused: boolean; -// isFetched: boolean; -// isLoading: boolean; -// isLoadingError: boolean; -// isRefetchError: boolean; -// isRefetching: boolean; -// isFetchedAfterMount: boolean; -// isPlaceholderData: boolean; -// }; - -// export function useTransactions( -// options: CoreGetTransactionsOptions, -// queryOptions?: QueryOptions -// ): UseTransactionsBaseResult { -// const enabled = queryOptions?.enabled !== false; - -// const hasInitialized = useRef(false); -// const prevStateRef = useRef | null>(null); -// const cancelledRef = useRef(false); - -// const retryTimerRef = useRef | null>(null); -// const failureCountRef = useRef(0); - -// const mountedRef = useRef(false); - -// const runSelect = useCallback( -// (res: CoreGetTransactionsResult): TSelect | null => { -// if (!queryOptions?.select) { -// return (res as unknown) as TSelect; -// } -// try { -// return queryOptions.select(res); -// } catch (e) { -// console.error("select() threw an error:", e); -// return null; -// } -// }, -// [queryOptions?.select] -// ); - -// const [result, setResult] = useState(() => { -// if (queryOptions?.initialData) { -// hasInitialized.current = true; -// return typeof queryOptions.initialData === "function" -// ? (queryOptions.initialData as () => CoreGetTransactionsResult)() -// : queryOptions.initialData; -// } -// if (queryOptions?.placeholderData) { -// return typeof queryOptions.placeholderData === "function" -// ? queryOptions.placeholderData(undefined, undefined) -// : queryOptions.placeholderData; -// } -// return null; -// }); - -// const [data, setData] = useState(() => { -// const initial = queryOptions?.initialData -// ? typeof queryOptions.initialData === "function" -// ? (queryOptions.initialData as () => CoreGetTransactionsResult)() -// : queryOptions.initialData -// : queryOptions?.placeholderData -// ? typeof queryOptions.placeholderData === "function" -// ? queryOptions.placeholderData(undefined, undefined) -// : queryOptions.placeholderData -// : null; - -// if (!initial) return null; -// return runSelect(initial); -// }); - -// const [updatedAt, setUpdatedAt] = useState(() => { -// return queryOptions?.initialData ? Date.now() : null; -// }); - -// const [dataUpdatedAt, setDataUpdatedAt] = useState(() => { -// if (queryOptions?.initialData && queryOptions?.initialDataUpdatedAt) { -// const val = -// typeof queryOptions.initialDataUpdatedAt === "function" -// ? queryOptions.initialDataUpdatedAt() -// : queryOptions.initialDataUpdatedAt; -// return typeof val === "number" ? val : null; -// } -// return null; -// }); - -// const [errorUpdatedAt, setErrorUpdatedAt] = useState(null); - -// const [failureCount, setFailureCount] = useState(0); -// const [error, setError] = useState(null); -// const [loading, setLoading] = useState(false); - -// const [fetchStatus, setFetchStatus] = useState(() => -// enabled ? "idle" : "paused" -// ); - -// const [isFetched, setIsFetched] = useState(false); - -// const [isLoading, setIsLoading] = useState(false); - -// const [isLoadingError, setIsLoadingError] = useState(false); - -// const [isRefetchError, setIsRefetchError] = useState(false); - -// const [isPlaceholderData, setIsPlaceholderData] = useState(() => { -// if (queryOptions?.initialData) return false; -// if (queryOptions?.placeholderData) return true; -// return false; -// }); - -// const shouldNotifyChange = useCallback( -// (nextState: UseTransactionsBaseResult) => { -// const rule = queryOptions?.notifyOnChangeProps; -// if (!rule) return true; - -// const prev = prevStateRef.current; -// if (!prev) return true; - -// const keys = typeof rule === "function" ? rule() : rule; -// if (keys === "all") return true; - -// for (const key of keys) { -// if (prev[key as keyof UseTransactionsBaseResult] !== nextState[key as keyof UseTransactionsBaseResult]) { -// return true; -// } -// } -// return false; -// }, -// [queryOptions?.notifyOnChangeProps] -// ); - -// const clearRetryTimer = () => { -// if (retryTimerRef.current) { -// clearTimeout(retryTimerRef.current); -// retryTimerRef.current = null; -// } -// }; - -// const computeShouldRetry = (count: number, err: Error): boolean => { -// const opt = queryOptions?.retry; -// if (opt === undefined) { -// return count < 3; -// } -// if (typeof opt === "boolean") { -// return opt === true; -// } -// if (typeof opt === "number") { -// return count < opt; -// } -// if (typeof opt === "function") { -// try { -// return Boolean(opt(count, err)); -// } catch (e) { -// console.warn("retry function threw", e); -// return false; -// } -// } -// return false; -// }; - -// const computeRetryDelayMs = (attempt: number, err?: Error): number => { -// const opt = queryOptions?.retryDelay; - -// const defaultDelay = Math.min(1000 * 2 ** (attempt - 1), 30000); - -// if (opt === undefined) return defaultDelay; -// if (typeof opt === "number") { -// return Math.max(0, Math.floor(opt)); -// } -// if (typeof opt === "function") { -// try { -// const val = opt(attempt, err as Error); -// return typeof val === "number" && !Number.isNaN(val) ? Math.max(0, Math.floor(val)) : defaultDelay; -// } catch (e) { -// console.warn("retryDelay function threw", e); -// return defaultDelay; -// } -// } -// return defaultDelay; -// }; - -// const isStale = useCallback((): boolean => { -// const staleTimeVal = queryOptions?.staleTime ?? 0; -// if (staleTimeVal === Infinity) return false; -// if (dataUpdatedAt === null) return true; -// return Date.now() - dataUpdatedAt >= (staleTimeVal || 0); -// }, [queryOptions?.staleTime, dataUpdatedAt]); - -// const [isFetchedAfterMount, setIsFetchedAfterMount] = useState(false); - -// useEffect(() => { -// mountedRef.current = true; -// return () => { -// mountedRef.current = false; -// }; -// }, []); - -// const runFetch = useCallback(async (): Promise => { -// if (!enabled) { -// setFetchStatus("paused"); -// return; -// } - -// clearRetryTimer(); - -// setError(null); -// setLoading(true); -// setFetchStatus("fetching"); -// setIsLoadingError(false); -// setIsRefetchError(false); -// cancelledRef.current = false; - -// try { -// const res = await coreGetTransactions(options); -// if (cancelledRef.current) return; - -// failureCountRef.current = 0; -// setFailureCount(0); -// clearRetryTimer(); - -// const selected = runSelect(res); - -// const now = Date.now(); - -// const nextState: UseTransactionsBaseResult = { -// data: selected, -// result: res, -// loading: false, -// isFetching: false, -// fetchStatus: "idle", -// isPaused: false, -// status: "success", -// error: null, -// updatedAt: now, -// dataUpdatedAt: now, -// errorUpdatedAt: prevStateRef.current?.errorUpdatedAt ?? null, -// failureCount: 0, -// refetch: async () => res, -// cancel: () => {}, -// isStale: false, -// isError: false, -// isPending: false, -// isSuccess: true, -// isFetched: true, -// isLoading: false, -// isLoadingError: false, -// isRefetchError: false, -// isRefetching: false, -// isFetchedAfterMount: mountedRef.current ? true : false, -// isPlaceholderData: false, -// }; - -// nextState.refetch = refetch as any; -// nextState.cancel = cancel as any; - -// hasInitialized.current = true; - -// setIsFetched(true); -// setIsLoadingError(false); -// setIsRefetchError(false); -// setIsPlaceholderData(false); -// if (mountedRef.current) { -// setIsFetchedAfterMount(true); -// } - -// if (shouldNotifyChange(nextState)) { -// setResult(res); -// setData(selected); -// setError(null); -// setUpdatedAt(now); -// setDataUpdatedAt(now); -// setErrorUpdatedAt(nextState.errorUpdatedAt ?? null); -// setFetchStatus("idle"); -// setLoading(false); -// } else { -// setResult(res); -// setData(selected); -// setError(null); -// setUpdatedAt(now); -// setDataUpdatedAt(now); -// setErrorUpdatedAt(nextState.errorUpdatedAt ?? null); -// setFetchStatus("idle"); -// setLoading(false); -// } - -// prevStateRef.current = nextState; -// return res; -// } catch (err: any) { -// if (cancelledRef.current) return; -// const e = err instanceof Error ? err : new Error(String(err)); - -// failureCountRef.current = (failureCountRef.current || 0) + 1; -// setFailureCount(failureCountRef.current); - -// const now = Date.now(); - -// const firstFetchFailed = !hasInitialized.current; -// const refetchFailed = !firstFetchFailed; - -// const nextState: UseTransactionsBaseResult = { -// data: null, -// result: null, -// loading: false, -// isFetching: false, -// fetchStatus: "idle", -// isPaused: false, -// status: "error", -// error: e, -// updatedAt: now, -// dataUpdatedAt: dataUpdatedAt, -// errorUpdatedAt: now, -// failureCount: failureCountRef.current, -// refetch: async () => undefined, -// cancel: () => {}, -// isStale: isStale(), -// isError: true, -// isPending: false, -// isSuccess: false, -// isFetched: true, -// isLoading: false, -// isLoadingError: firstFetchFailed, -// isRefetchError: refetchFailed, -// isRefetching: false, -// isFetchedAfterMount: mountedRef.current ? true : false, -// isPlaceholderData: false, -// }; - -// nextState.refetch = refetch as any; -// nextState.cancel = cancel as any; - -// setIsFetched(true); -// if (firstFetchFailed) { -// setIsLoadingError(true); -// } -// if (refetchFailed) { -// setIsRefetchError(true); -// } -// setIsPlaceholderData(false); -// if (mountedRef.current) { -// setIsFetchedAfterMount(true); -// } - -// if (shouldNotifyChange(nextState)) { -// setResult(null); -// setData(null); -// setError(e); -// setUpdatedAt(now); -// setErrorUpdatedAt(now); -// setFetchStatus("idle"); -// setLoading(false); -// } else { -// setError(e); -// setUpdatedAt(now); -// setErrorUpdatedAt(now); -// setFetchStatus("idle"); -// setLoading(false); -// } - -// prevStateRef.current = nextState; - -// const shouldRetry = computeShouldRetry(failureCountRef.current, e); - -// if (shouldRetry) { -// const delay = computeRetryDelayMs(failureCountRef.current, e); -// clearRetryTimer(); -// retryTimerRef.current = setTimeout(() => { -// if (cancelledRef.current) return; -// runFetch().catch(() => {}); -// }, delay); -// } - -// return undefined; -// } -// }, [options, enabled, shouldNotifyChange, runSelect, queryOptions?.retry, queryOptions?.retryDelay, dataUpdatedAt]); - -// const refetch = useCallback(async () => { -// clearRetryTimer(); -// failureCountRef.current = 0; -// setFailureCount(0); -// cancelledRef.current = false; -// setIsLoadingError(false); -// setIsRefetchError(false); -// return runFetch(); -// }, [runFetch]); - -// const cancel = useCallback(() => { -// cancelledRef.current = true; -// clearRetryTimer(); -// setLoading(false); -// }, []); - -// const status: Status = error ? "error" : !hasInitialized.current ? "pending" : "success"; - -// const isError = status === "error"; -// const isPending = status === "pending"; -// const isSuccess = status === "success"; - -// const derivedIsFetching = fetchStatus === "fetching"; -// const derivedIsPaused = fetchStatus === "paused"; - -// const derivedIsLoading = derivedIsFetching && isPending; -// const derivedIsRefetching = derivedIsFetching && !isPending; - -// useEffect(() => { -// setIsLoading(derivedIsLoading); -// }, [derivedIsLoading]); - -// const currentState: UseTransactionsBaseResult = { -// data, -// result, -// loading, -// isFetching: derivedIsFetching, -// fetchStatus, -// isPaused: derivedIsPaused, -// status, -// error, -// updatedAt, -// dataUpdatedAt, -// errorUpdatedAt, -// failureCount, -// refetch, -// cancel, -// isStale: isStale(), - -// isError, -// isPending, -// isSuccess, - -// isFetched, -// isLoading, -// isLoadingError, -// isRefetchError, -// isRefetching: derivedIsRefetching, -// isFetchedAfterMount, -// isPlaceholderData, -// }; - -// prevStateRef.current = currentState; - -// useEffect(() => { -// if (!enabled) { -// setFetchStatus("paused"); -// } else { -// setFetchStatus((s) => (s === "fetching" ? s : "idle")); -// } -// }, [enabled]); - -// useEffect(() => { -// if (!enabled) return; - -// cancelledRef.current = false; - -// const shouldInitialFetch = !hasInitialized.current || (hasInitialized.current && queryOptions?.refetchOnMount && isStale()); - -// if (shouldInitialFetch) { -// runFetch().catch(() => {}); -// } - -// return () => { -// cancelledRef.current = true; -// clearRetryTimer(); -// }; -// }, [runFetch, enabled, queryOptions?.refetchOnMount, queryOptions?.staleTime, dataUpdatedAt]); - -// useEffect(() => { -// if (!enabled) return; - -// const onFocus = () => { -// if (queryOptions?.refetchOnWindowFocus && isStale()) { -// runFetch().catch(() => {}); -// } -// }; - -// const onOnline = () => { -// if (queryOptions?.refetchOnReconnect && isStale()) { -// runFetch().catch(() => {}); -// } -// }; - -// if (queryOptions?.refetchOnWindowFocus) { -// window.addEventListener("focus", onFocus); -// } -// if (queryOptions?.refetchOnReconnect) { -// window.addEventListener("online", onOnline); -// } - -// return () => { -// if (queryOptions?.refetchOnWindowFocus) { -// window.removeEventListener("focus", onFocus); -// } -// if (queryOptions?.refetchOnReconnect) { -// window.removeEventListener("online", onOnline); -// } -// }; -// }, [ -// enabled, -// queryOptions?.refetchOnWindowFocus, -// queryOptions?.refetchOnReconnect, -// queryOptions?.staleTime, -// dataUpdatedAt, -// isStale, -// runFetch, -// ]); - -// useEffect(() => { -// return () => { -// clearRetryTimer(); -// cancelledRef.current = true; -// }; -// }, []); - -// return currentState; -// } - -// export default useTransactions; +import { useMemo } from 'react'; +import { getTransactions } from "@bluxcc/core"; +import { + useQuery, + UseQueryResult, + UseQueryOptions, +} from '@tanstack/react-query'; +import type { + GetTransactionsResult, + GetTransactionsOptions, +} from "@bluxcc/core/dist/exports/core/getTransactions"; + +import { getNetwork } from '../utils'; + +type R = GetTransactionsResult; +type O = GetTransactionsOptions; + +export function useTransactions( + options?: O, + queryOptions?: UseQueryOptions, +): UseQueryResult { + const network = getNetwork(options?.network); + const enabled = queryOptions?.enabled ?? true; + + const deps = [ + options?.forAccount, + options?.includeFailed, + options?.forClaimableBalance, + options?.forLedger, + options?.forLiquidityPool, + options?.cursor, + options?.limit, + options?.network, + options?.order, + ]; + + const queryKey = useMemo( + () => ['blux', 'transactions', network, ...deps], + [network, ...deps], + ); + + const queryFn = useMemo( + () => async () => { + const opts: O = { + ...options, + network, + }; + + return getTransactions(opts); + }, + [network, ...deps], + ); + + const result = useQuery({ + queryKey, + queryFn, + enabled, + ...queryOptions, + }); + + return result; +} \ No newline at end of file diff --git a/src/useStellar/utils.ts b/src/useStellar/utils.ts deleted file mode 100644 index dd54f7b..0000000 --- a/src/useStellar/utils.ts +++ /dev/null @@ -1,35 +0,0 @@ -// import { getState } from '../../../core/dist/index.esm'; -// -// export const checkConfigCreated = () => { -// const { stellar } = getState(); -// -// return !!stellar; -// }; -// -// export const getAddress = (address?: string) => { -// const { user } = getState(); -// -// if (!user && !address) { -// throw new Error('Address not found'); -// } -// -// if (address) { -// return address; -// } -// -// return user?.address as string; -// }; -// -// export const getNetwork = (network?: string) => { -// const { stellar } = getState(); -// -// if (!network) { -// if (stellar) { -// return stellar.activeNetwork; -// } -// -// throw new Error('Custom network has no transports.'); -// } -// -// return network; -// };