@scallop-io/scallop-swap-sdk-react 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,8 @@
1
+ // Copyright (c) Mysten Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { createContext } from 'react';
5
+
6
+ import type { SdkStore } from '../store.js';
7
+
8
+ export const SdkConfigContext = createContext<SdkStore | null>(null);
@@ -0,0 +1,4 @@
1
+ export { useGetSwapRoutes, type SwapRoutesResult } from './useGetSwapRoutes';
2
+ export { useBuildSwapTransaction } from './useBuildSwapTransaction';
3
+ export { useAggregatorContext } from './useAggregatorContext';
4
+ export { useAggregatorFetchingStatus } from './useAggregatorFetchingStatus';
@@ -0,0 +1,14 @@
1
+ import { useEffect } from 'react';
2
+ import { useSdkConfigStore } from './useSdkConfigStore';
3
+ import { useAggregatorContext } from './useAggregatorContext';
4
+
5
+ export const useActiveDexesChanged = () => {
6
+ const setActiveDexes = useSdkConfigStore((v) => v.setActiveDexes);
7
+ const aggregator = useAggregatorContext().aggregator;
8
+
9
+ useEffect(() => {
10
+ aggregator.events.on('poolStatusChanged', ({ name, pool, enabled }) => {
11
+ setActiveDexes(name, pool, enabled);
12
+ });
13
+ }, [aggregator]);
14
+ };
@@ -0,0 +1,14 @@
1
+ import { useContext } from 'react';
2
+ import { ScallopSwapSdkContext } from '../providers/scallop-swap-sdk-provider';
3
+
4
+ export const useAggregatorContext = () => {
5
+ const ctx = useContext(ScallopSwapSdkContext);
6
+
7
+ if (!ctx) {
8
+ throw new Error(
9
+ 'Could not find ScallopSwapSdkContext. Ensure that you have set up the ScallopSwapSdkProvider'
10
+ );
11
+ }
12
+
13
+ return ctx;
14
+ };
@@ -0,0 +1,56 @@
1
+ import { useEffect } from 'react';
2
+ import {
3
+ QueryKey,
4
+ useQuery,
5
+ useQueryClient,
6
+ UseQueryOptions,
7
+ } from '@tanstack/react-query';
8
+ import { useAggregatorContext } from './useAggregatorContext';
9
+ import { queryKeys } from 'src/constants/queryKeys';
10
+
11
+ export const useAggregatorFetchingStatus = (
12
+ options?: Omit<
13
+ UseQueryOptions<
14
+ Record<string, boolean>,
15
+ Error,
16
+ Record<string, boolean>,
17
+ QueryKey
18
+ >,
19
+ 'queryFn' | 'queryKey'
20
+ >
21
+ ) => {
22
+ const { aggregator } = useAggregatorContext();
23
+ const queryClient = useQueryClient();
24
+ const queryKey = queryKeys.api.getAggregatorFetchStatus();
25
+
26
+ useEffect(() => {
27
+ const onStart = ({ name }: { name: string }) => {
28
+ queryClient.setQueryData<Record<string, boolean>>(queryKey, (prev) => ({
29
+ ...(prev ?? aggregator.fetchingStatus),
30
+ [name]: true,
31
+ }));
32
+ };
33
+
34
+ const onEnd = ({ name }: { name: string }) => {
35
+ queryClient.setQueryData<Record<string, boolean>>(queryKey, (prev) => ({
36
+ ...(prev ?? aggregator.fetchingStatus),
37
+ [name]: false,
38
+ }));
39
+ };
40
+
41
+ aggregator.events.on('aggregatorFetchStart', onStart);
42
+ aggregator.events.on('aggregatorFetchEnd', onEnd);
43
+
44
+ return () => {
45
+ aggregator.events.off('aggregatorFetchStart', onStart);
46
+ aggregator.events.off('aggregatorFetchEnd', onEnd);
47
+ };
48
+ }, [aggregator, queryClient]);
49
+
50
+ return useQuery({
51
+ ...options,
52
+ queryKey,
53
+ staleTime: Infinity,
54
+ queryFn: () => aggregator.fetchingStatus,
55
+ });
56
+ };
@@ -0,0 +1,91 @@
1
+ import {
2
+ QueryKey,
3
+ useQuery,
4
+ UseQueryOptions,
5
+ UseQueryResult,
6
+ } from '@tanstack/react-query';
7
+ import { Aggregator } from '@scallop-io/scallop-swap-sdk';
8
+ import { useAggregatorContext } from './useAggregatorContext';
9
+ import { queryKeys } from 'src/constants/queryKeys';
10
+
11
+ type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<T>;
12
+ type AggregatorMethodName = {
13
+ [K in keyof Aggregator]: Aggregator[K] extends (
14
+ ...args: any[]
15
+ ) => Promise<any>
16
+ ? K
17
+ : never;
18
+ }[keyof Aggregator];
19
+
20
+ export type AggregatorMethods = {
21
+ [K in AggregatorMethodName]: {
22
+ name: K;
23
+ result: Awaited<ReturnType<Aggregator[K]>>;
24
+ params: Parameters<Aggregator[K]>;
25
+ };
26
+ };
27
+
28
+ type UseAggregatorQueryOptions<
29
+ T extends keyof AggregatorMethods,
30
+ TData,
31
+ > = PartialBy<
32
+ Omit<
33
+ UseQueryOptions<AggregatorMethods[T]['result'], Error, TData, QueryKey>,
34
+ 'queryFn'
35
+ >,
36
+ 'queryKey'
37
+ >;
38
+
39
+ const callAggregatorMethod = <T extends AggregatorMethodName>(
40
+ aggregator: Aggregator,
41
+ method: T,
42
+ params: AggregatorMethods[T]['params']
43
+ ): Promise<AggregatorMethods[T]['result']> => {
44
+ const fn = aggregator[method] as (
45
+ ...args: AggregatorMethods[T]['params']
46
+ ) => Promise<AggregatorMethods[T]['result']>;
47
+ return fn(...params);
48
+ };
49
+
50
+ export function useAggregatorQuery<
51
+ T extends keyof AggregatorMethods,
52
+ TData = AggregatorMethods[T]['result'],
53
+ >(
54
+ ...args: AggregatorMethods[T]['params'] extends []
55
+ ? [
56
+ method: T,
57
+ params?: AggregatorMethods[T]['params'],
58
+ options?: UseAggregatorQueryOptions<T, TData>,
59
+ ]
60
+ : [
61
+ method: T,
62
+ params: AggregatorMethods[T]['params'],
63
+ options?: UseAggregatorQueryOptions<T, TData>,
64
+ ]
65
+ ): UseQueryResult<TData, Error> {
66
+ const [method, params, { queryKey = [], ...options } = {}] = args as [
67
+ method: T,
68
+ params?: AggregatorMethods[T]['params'],
69
+ options?: UseAggregatorQueryOptions<T, TData>,
70
+ ];
71
+
72
+ const aggregatorContext = useAggregatorContext();
73
+
74
+ return useQuery({
75
+ ...options,
76
+ queryKey: [
77
+ ...queryKeys.sdk.aggregatorQuery({
78
+ method,
79
+ params,
80
+ }),
81
+ ...queryKey,
82
+ ],
83
+ queryFn: () =>
84
+ callAggregatorMethod(
85
+ aggregatorContext.aggregator,
86
+ method,
87
+ // if some methods take no args, params will be [] for them
88
+ (params ?? []) as AggregatorMethods[T]['params']
89
+ ),
90
+ });
91
+ }
@@ -0,0 +1,58 @@
1
+ import {
2
+ Transaction,
3
+ TransactionObjectArgument,
4
+ } from '@mysten/sui/transactions';
5
+ import { useMutation, UseMutationOptions } from '@tanstack/react-query';
6
+ import { FetchRouteResult } from '@scallop-io/scallop-swap-sdk';
7
+ import { useAggregatorContext } from './useAggregatorContext';
8
+
9
+ type UseBuildSwapTransactionMutationOptions = Omit<
10
+ UseMutationOptions<
11
+ {
12
+ coinOutType: string;
13
+ tx: Transaction;
14
+ coinOut?: TransactionObjectArgument;
15
+ },
16
+ Error,
17
+ {
18
+ route: FetchRouteResult<any>;
19
+ options?: {
20
+ txExtensionParams?: {
21
+ initTx: Transaction;
22
+ coinIn: TransactionObjectArgument;
23
+ };
24
+ mergeResult?: boolean;
25
+ slippage?: number;
26
+ };
27
+ }
28
+ >,
29
+ 'mutationFn'
30
+ >;
31
+
32
+ export const useBuildSwapTransaction = ({
33
+ mutationKey,
34
+ ...mutationOptions
35
+ }: UseBuildSwapTransactionMutationOptions = {}) => {
36
+ const aggregatorContext = useAggregatorContext();
37
+ return useMutation({
38
+ mutationKey: mutationKey ?? [
39
+ 'buildSwapTransaction',
40
+ aggregatorContext.client.network,
41
+ ],
42
+ mutationFn: async ({ route, options = {} }) => {
43
+ const { txExtensionParams, mergeResult, slippage } = options;
44
+ if (mergeResult === false) {
45
+ return aggregatorContext.aggregator.buildRouteTransaction(route, {
46
+ txExtensionParams,
47
+ mergeResult: false,
48
+ slippage,
49
+ });
50
+ }
51
+ return aggregatorContext.aggregator.buildRouteTransaction(route, {
52
+ txExtensionParams,
53
+ slippage,
54
+ });
55
+ },
56
+ ...mutationOptions,
57
+ });
58
+ };
@@ -0,0 +1,87 @@
1
+ import {
2
+ QueryKey,
3
+ useQuery,
4
+ useQueryClient,
5
+ UseQueryOptions,
6
+ } from '@tanstack/react-query';
7
+ import { Aggregator, FetchRouteResult } from '@scallop-io/scallop-swap-sdk';
8
+ import { useAggregatorContext } from './useAggregatorContext';
9
+ import { queryKeys } from 'src/constants/queryKeys';
10
+
11
+ export type SwapRoutesResult = Awaited<ReturnType<Aggregator['fetchRoutes']>>;
12
+
13
+ export function sortAndInsert(
14
+ old: SwapRoutesResult | undefined,
15
+ route: FetchRouteResult<any>
16
+ ): SwapRoutesResult {
17
+ // Remove existing route from the same aggregator, if any
18
+ const routes = (old?.routes ?? []).filter(
19
+ (r) => r.formattedResult.name !== route.formattedResult.name
20
+ );
21
+
22
+ // Find insertion point to maintain descending order by coinOut amount
23
+ const insertIndex = routes.findIndex(
24
+ (r) =>
25
+ route.formattedResult.coinOut.amount >= r.formattedResult.coinOut.amount
26
+ );
27
+
28
+ if (insertIndex === -1) {
29
+ routes.push(route);
30
+ } else {
31
+ routes.splice(insertIndex, 0, route);
32
+ }
33
+
34
+ return {
35
+ routes,
36
+ errors: old?.errors ?? [],
37
+ };
38
+ }
39
+
40
+ export const useGetSwapRoutes = (
41
+ {
42
+ coinInType,
43
+ coinOutType,
44
+ swapAmount,
45
+ }: {
46
+ coinInType: string;
47
+ coinOutType: string;
48
+ swapAmount: string;
49
+ },
50
+ options?: Omit<
51
+ UseQueryOptions<SwapRoutesResult, Error, SwapRoutesResult, QueryKey>,
52
+ 'queryFn' | 'queryKey'
53
+ >
54
+ ) => {
55
+ const { aggregator } = useAggregatorContext();
56
+ const queryClient = useQueryClient();
57
+
58
+ const queryKey = queryKeys.api.getSwapRoutes({
59
+ coinInType,
60
+ coinOutType,
61
+ swapAmount,
62
+ });
63
+
64
+ return useQuery({
65
+ ...options,
66
+ queryKey,
67
+ queryFn: () =>
68
+ aggregator.fetchRoutes(
69
+ {
70
+ coinInType,
71
+ coinOutType,
72
+ swapAmount: BigInt(swapAmount),
73
+ },
74
+ {
75
+ onRouteFound: (route: FetchRouteResult<any>) => {
76
+ queryClient.setQueryData(
77
+ queryKey,
78
+ (old: SwapRoutesResult | undefined) => sortAndInsert(old, route)
79
+ );
80
+ },
81
+ onError: (error) => {
82
+ console.error('Error fetching routes:', error);
83
+ },
84
+ }
85
+ ),
86
+ });
87
+ };
@@ -0,0 +1,44 @@
1
+ import { useAggregatorContext } from './useAggregatorContext';
2
+ import { useSdkConfigStore } from './useSdkConfigStore';
3
+ import { useEffect } from 'react';
4
+
5
+ export const useLoadConfig = () => {
6
+ const activeDexes = useSdkConfigStore((state) => state.activeDexes);
7
+ const slippage = useSdkConfigStore((state) => state.slippage);
8
+ const aggregator = useAggregatorContext().aggregator;
9
+ const setDefaultActiveDexes = useSdkConfigStore(
10
+ (state) => state.setDefaultActiveDexes
11
+ );
12
+
13
+ // Handle dexes
14
+ useEffect(() => {
15
+ if (Object.keys(activeDexes).length === 0) {
16
+ const defaultDexes = aggregator.aggregators.reduce(
17
+ (acc, curr) => {
18
+ acc[curr.name] = curr.pools.reduce(
19
+ (acc, curr) => {
20
+ acc[curr] = true;
21
+ return acc;
22
+ },
23
+ {} as Record<string, boolean>
24
+ );
25
+ return acc;
26
+ },
27
+ {} as Record<string, Record<string, boolean>>
28
+ );
29
+
30
+ setDefaultActiveDexes(defaultDexes);
31
+ } else {
32
+ Object.entries(activeDexes).forEach(([name, dexPools]) => {
33
+ const namedAggregator = aggregator.getAggregator(name as string);
34
+ if (!namedAggregator) return;
35
+ namedAggregator.poolsMap = new Map(Object.entries(dexPools));
36
+ });
37
+ }
38
+ }, [aggregator]);
39
+
40
+ // Handle slippage
41
+ useEffect(() => {
42
+ aggregator.setSlippage(slippage);
43
+ }, [aggregator]);
44
+ };
@@ -0,0 +1,14 @@
1
+ import { useContext } from 'react';
2
+ import { SdkConfigContext } from 'src/contexts/sdkContext';
3
+ import { StoreState } from 'src/store';
4
+ import { useStore } from 'zustand';
5
+
6
+ export function useSdkConfigStore<T>(selector: (state: StoreState) => T): T {
7
+ const store = useContext(SdkConfigContext);
8
+ if (!store) {
9
+ throw new Error(
10
+ 'Could not find SdkConfigContext. Ensure that you have set up the SdkConfigProvider.'
11
+ );
12
+ }
13
+ return useStore(store, selector);
14
+ }
@@ -0,0 +1,14 @@
1
+ import { useEffect } from 'react';
2
+ import { useAggregatorContext } from './useAggregatorContext';
3
+ import { useSdkConfigStore } from './useSdkConfigStore';
4
+
5
+ export const useSlippageChanged = () => {
6
+ const aggregator = useAggregatorContext().aggregator;
7
+ const setSlippage = useSdkConfigStore((v) => v.setSlippage);
8
+
9
+ useEffect(() => {
10
+ aggregator.events.on('aggregatorSlippageChanged', ({ slippageInBps }) => {
11
+ setSlippage(slippageInBps);
12
+ });
13
+ }, [aggregator]);
14
+ };
@@ -0,0 +1,21 @@
1
+ import { useCallback, useMemo } from 'react';
2
+ import { useAggregatorContext } from './useAggregatorContext';
3
+
4
+ export const useSwapSlippage = () => {
5
+ const { aggregator } = useAggregatorContext();
6
+
7
+ const setSlippage = useCallback(
8
+ (slippageInBps: number) => {
9
+ aggregator.setSlippage(slippageInBps);
10
+ },
11
+ [aggregator]
12
+ );
13
+
14
+ return useMemo(
15
+ () => ({
16
+ slippage: aggregator.slippage,
17
+ setSlippage,
18
+ }),
19
+ [aggregator.slippage, setSlippage]
20
+ );
21
+ };
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from './hooks';
2
+ export * from './providers';
3
+ export * from './types';
4
+ export { queryKeys } from './constants/queryKeys';
@@ -0,0 +1,2 @@
1
+ export { ScallopSwapSdkProvider } from './scallop-swap-sdk-provider';
2
+ export { SdkConfigProvider } from './sdk-config';
@@ -0,0 +1,74 @@
1
+ import { createContext, useEffect, useMemo } from 'react';
2
+ import {
3
+ ScallopSwapSdkProviderContext,
4
+ ScallopSwapSdkProviderProps,
5
+ } from './types';
6
+ import {
7
+ Aggregator,
8
+ AftermathSwap,
9
+ CetusSwap,
10
+ FlowXSwap,
11
+ _7kSwap,
12
+ } from '@scallop-io/scallop-swap-sdk';
13
+ import type { FC, PropsWithChildren } from 'react';
14
+ import { SdkConfigProvider } from '../sdk-config';
15
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
16
+
17
+ export const ScallopSwapSdkContext =
18
+ createContext<ScallopSwapSdkProviderContext | null>(null);
19
+
20
+ export const ScallopSwapSdkProvider: FC<
21
+ PropsWithChildren<ScallopSwapSdkProviderProps>
22
+ > = ({
23
+ children,
24
+ client,
25
+ walletAddress,
26
+ aggregator,
27
+ queryClient,
28
+ }: PropsWithChildren<ScallopSwapSdkProviderProps>) => {
29
+ const _aggregator = useMemo(() => {
30
+ return (
31
+ aggregator ??
32
+ new Aggregator({
33
+ client,
34
+ walletAddress,
35
+ })
36
+ );
37
+ }, [aggregator, client, walletAddress]);
38
+
39
+ useEffect(() => {
40
+ // Only initialize default aggregators when one wasn't provided by the caller
41
+ if (aggregator) return;
42
+
43
+ const params = {
44
+ walletAddress: _aggregator.walletAddress,
45
+ client: _aggregator.client,
46
+ };
47
+
48
+ _aggregator.setSlippage(10); // 0.1%
49
+ _aggregator.addAggregator([
50
+ new CetusSwap(params),
51
+ new AftermathSwap(params),
52
+ new FlowXSwap(params),
53
+ new _7kSwap(params),
54
+ ]);
55
+ }, [_aggregator, aggregator]);
56
+
57
+ const _queryClient = useMemo(
58
+ () => queryClient ?? new QueryClient(),
59
+ [queryClient]
60
+ );
61
+
62
+ const ctx = useMemo<ScallopSwapSdkProviderContext>(
63
+ () => ({ aggregator: _aggregator, client: client }),
64
+ [_aggregator, client]
65
+ );
66
+
67
+ return (
68
+ <ScallopSwapSdkContext.Provider value={ctx}>
69
+ <QueryClientProvider client={_queryClient}>
70
+ <SdkConfigProvider>{children}</SdkConfigProvider>
71
+ </QueryClientProvider>
72
+ </ScallopSwapSdkContext.Provider>
73
+ );
74
+ };
@@ -0,0 +1,16 @@
1
+ // import { SuiClient } from '@mysten/sui/client';
2
+ import { SuiClient } from '@mysten/sui/client';
3
+ import { Aggregator } from '@scallop-io/scallop-swap-sdk';
4
+ import { QueryClient } from '@tanstack/query-core';
5
+
6
+ export type ScallopSwapSdkProviderContext = {
7
+ aggregator: Aggregator;
8
+ client: SuiClient;
9
+ };
10
+
11
+ export type ScallopSwapSdkProviderProps = {
12
+ client: SuiClient;
13
+ walletAddress: string;
14
+ aggregator?: Aggregator;
15
+ queryClient?: QueryClient;
16
+ };
@@ -0,0 +1,36 @@
1
+ import { useRef, type FC, type PropsWithChildren } from 'react';
2
+ import { SdkProps } from './types';
3
+ import { SdkConfigContext } from 'src/contexts/sdkContext';
4
+ import { createSdkStore } from 'src/store';
5
+ import { DEFAULT_STORAGE, STORAGE_KEY } from 'src/constants/defaults';
6
+ import { createInMemoryStore } from 'src/utils/storage';
7
+ import { useActiveDexesChanged } from 'src/hooks/useActiveDexesChanged';
8
+ import { useLoadConfig } from 'src/hooks/useLoadConfig';
9
+ import { useSlippageChanged } from 'src/hooks/useSlippageChanged';
10
+
11
+ export const SdkConfigProvider: FC<PropsWithChildren<SdkProps>> = ({
12
+ storage = DEFAULT_STORAGE,
13
+ storageKey = STORAGE_KEY,
14
+ children,
15
+ }) => {
16
+ const storeRef = useRef(
17
+ createSdkStore({
18
+ storage: storage || createInMemoryStore(),
19
+ storageKey,
20
+ })
21
+ );
22
+
23
+ return (
24
+ <SdkConfigContext.Provider value={storeRef.current}>
25
+ <SdkDataManager>{children}</SdkDataManager>
26
+ </SdkConfigContext.Provider>
27
+ );
28
+ };
29
+
30
+ export const SdkDataManager: FC<PropsWithChildren<{}>> = ({ children }) => {
31
+ useLoadConfig();
32
+ useSlippageChanged();
33
+ useActiveDexesChanged();
34
+
35
+ return children;
36
+ };
@@ -0,0 +1,7 @@
1
+ import { StateStorage } from 'zustand/middleware';
2
+
3
+ export type SdkProps = {
4
+ storage?: StateStorage | null;
5
+ storageKey?: string;
6
+ };
7
+ export type SdkDataManagerProps = {};
package/src/store.ts ADDED
@@ -0,0 +1,61 @@
1
+ import { createStore } from 'zustand';
2
+ import { createJSONStorage, persist, StateStorage } from 'zustand/middleware';
3
+ import { DEFAULT_STORAGE } from './constants/defaults';
4
+
5
+ type StoreActions = {
6
+ setActiveAggregatorNames: (
7
+ activeAggregatorNames: Record<string, boolean>
8
+ ) => void;
9
+ setSlippage: (slippage: number) => void;
10
+ setActiveDexes: (name: string, pool: string, enabled: boolean) => void;
11
+ setDefaultActiveDexes: (
12
+ defaultDexes: Record<string, Record<string, boolean>>
13
+ ) => void;
14
+ };
15
+
16
+ export type StoreState = {
17
+ activeAggregatorNames: Record<string, boolean>;
18
+ slippage: number;
19
+ activeDexes: Record<string, Record<string, boolean>>;
20
+ } & StoreActions;
21
+
22
+ type StorageConfig = {
23
+ storage: StateStorage;
24
+ storageKey: string;
25
+ };
26
+
27
+ export const createSdkStore = ({ storageKey }: StorageConfig) => {
28
+ return createStore<StoreState>()(
29
+ persist(
30
+ (set, get) => ({
31
+ activeAggregatorNames: {},
32
+ slippage: 30, // Default to 30 bps (0.3%)
33
+ activeDexes: {},
34
+ setDefaultActiveDexes: (
35
+ defaultDexes: Record<string, Record<string, boolean>>
36
+ ) => {
37
+ set({ activeDexes: defaultDexes });
38
+ },
39
+ setActiveAggregatorNames: (
40
+ activeAggregatorNames: Record<string, boolean>
41
+ ) => {
42
+ set({ activeAggregatorNames });
43
+ },
44
+ setSlippage: (slippage: number) => {
45
+ set({ slippage });
46
+ },
47
+ setActiveDexes: (name: string, pool: string, enabled: boolean) => {
48
+ const newActiveDexes = { ...get().activeDexes };
49
+ newActiveDexes[name][pool] = enabled;
50
+ set({ activeDexes: newActiveDexes });
51
+ },
52
+ }),
53
+ {
54
+ name: storageKey,
55
+ storage: createJSONStorage(() => DEFAULT_STORAGE),
56
+ }
57
+ )
58
+ );
59
+ };
60
+
61
+ export type SdkStore = ReturnType<typeof createSdkStore>;
package/src/types.ts ADDED
@@ -0,0 +1,21 @@
1
+ export type {
2
+ FetchRouteResult,
3
+ FormattedRouteResult,
4
+ } from '@scallop-io/scallop-swap-sdk';
5
+
6
+ export namespace QueryKeys {
7
+ export namespace API {
8
+ export type GetAggregatorFetchStatus = {};
9
+ export type GetSwapRoutes = {
10
+ coinInType: string;
11
+ coinOutType: string;
12
+ swapAmount?: string;
13
+ };
14
+ }
15
+ export namespace SDK {
16
+ export type AggregatorQuery = {
17
+ method: string;
18
+ params: any;
19
+ };
20
+ }
21
+ }
@@ -0,0 +1,16 @@
1
+ import type { StateStorage } from 'zustand/middleware';
2
+
3
+ export const createInMemoryStore = (): StateStorage => {
4
+ const store = new Map();
5
+ return {
6
+ getItem(key: string) {
7
+ return store.get(key);
8
+ },
9
+ setItem(key: string, value: string) {
10
+ store.set(key, value);
11
+ },
12
+ removeItem(key: string) {
13
+ store.delete(key);
14
+ },
15
+ };
16
+ };