@sodax/dapp-kit 0.0.1-rc.9 → 1.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +142 -44
- package/dist/index.d.mts +1514 -0
- package/dist/index.d.ts +1514 -4
- package/dist/index.js +997 -82
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +957 -84
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -8
- package/src/contexts/index.ts +3 -2
- package/src/hooks/backend/README.md +135 -0
- package/src/hooks/backend/index.ts +23 -0
- package/src/hooks/backend/useBackendAllMoneyMarketAssets.ts +49 -0
- package/src/hooks/backend/useBackendAllMoneyMarketBorrowers.ts +61 -0
- package/src/hooks/backend/useBackendIntentByHash.ts +53 -0
- package/src/hooks/backend/useBackendIntentByTxHash.ts +52 -0
- package/src/hooks/backend/useBackendMoneyMarketAsset.ts +57 -0
- package/src/hooks/backend/useBackendMoneyMarketAssetBorrowers.ts +67 -0
- package/src/hooks/backend/useBackendMoneyMarketAssetSuppliers.ts +67 -0
- package/src/hooks/backend/useBackendMoneyMarketPosition.ts +56 -0
- package/src/hooks/backend/useBackendOrderbook.ts +63 -0
- package/src/hooks/bridge/index.ts +5 -0
- package/src/hooks/bridge/useBridge.ts +57 -0
- package/src/hooks/bridge/useBridgeAllowance.ts +49 -0
- package/src/hooks/bridge/useBridgeApprove.ts +68 -0
- package/src/hooks/bridge/useGetBridgeableAmount.ts +50 -0
- package/src/hooks/bridge/useGetBridgeableTokens.ts +62 -0
- package/src/hooks/index.ts +4 -0
- package/src/hooks/migrate/index.ts +4 -0
- package/src/hooks/migrate/types.ts +15 -0
- package/src/hooks/migrate/useMigrate.tsx +110 -0
- package/src/hooks/migrate/useMigrationAllowance.tsx +79 -0
- package/src/hooks/migrate/useMigrationApprove.tsx +129 -0
- package/src/hooks/mm/useMMAllowance.ts +2 -1
- package/src/hooks/mm/useMMApprove.ts +2 -1
- package/src/hooks/mm/useReservesData.ts +1 -8
- package/src/hooks/mm/useReservesHumanized.ts +30 -0
- package/src/hooks/mm/useReservesList.ts +29 -0
- package/src/hooks/mm/useReservesUsdFormat.ts +38 -0
- package/src/hooks/mm/useUserFormattedSummary.ts +54 -0
- package/src/hooks/mm/useUserReservesData.ts +30 -31
- package/src/hooks/provider/useHubProvider.ts +3 -3
- package/src/hooks/provider/useSpokeProvider.ts +45 -21
- package/src/hooks/shared/index.ts +4 -0
- package/src/hooks/shared/useDeriveUserWalletAddress.ts +44 -0
- package/src/hooks/shared/useEstimateGas.ts +18 -0
- package/src/hooks/shared/useRequestTrustline.ts +103 -0
- package/src/hooks/shared/useStellarTrustlineCheck.ts +71 -0
- package/src/hooks/staking/index.ts +19 -0
- package/src/hooks/staking/useCancelUnstake.ts +52 -0
- package/src/hooks/staking/useClaim.ts +46 -0
- package/src/hooks/staking/useConvertedAssets.ts +47 -0
- package/src/hooks/staking/useInstantUnstake.ts +50 -0
- package/src/hooks/staking/useInstantUnstakeAllowance.ts +59 -0
- package/src/hooks/staking/useInstantUnstakeApprove.ts +52 -0
- package/src/hooks/staking/useInstantUnstakeRatio.ts +54 -0
- package/src/hooks/staking/useStake.ts +47 -0
- package/src/hooks/staking/useStakeAllowance.ts +57 -0
- package/src/hooks/staking/useStakeApprove.ts +50 -0
- package/src/hooks/staking/useStakeRatio.ts +53 -0
- package/src/hooks/staking/useStakingConfig.ts +40 -0
- package/src/hooks/staking/useStakingInfo.ts +50 -0
- package/src/hooks/staking/useUnstake.ts +54 -0
- package/src/hooks/staking/useUnstakeAllowance.ts +58 -0
- package/src/hooks/staking/useUnstakeApprove.ts +52 -0
- package/src/hooks/staking/useUnstakingInfo.ts +53 -0
- package/src/hooks/staking/useUnstakingInfoWithPenalty.ts +59 -0
- package/src/hooks/swap/index.ts +2 -1
- package/src/hooks/swap/useCancelSwap.ts +44 -0
- package/src/hooks/swap/useQuote.ts +16 -2
- package/src/hooks/swap/useStatus.ts +1 -1
- package/src/hooks/swap/{useCreateIntentOrder.ts → useSwap.ts} +16 -11
- package/src/hooks/swap/useSwapAllowance.ts +5 -1
- package/src/hooks/swap/useSwapApprove.ts +14 -14
- package/src/providers/SodaxProvider.tsx +8 -20
- package/dist/contexts/index.d.ts +0 -8
- package/dist/contexts/index.d.ts.map +0 -1
- package/dist/core/index.d.ts +0 -3
- package/dist/core/index.d.ts.map +0 -1
- package/dist/hooks/index.d.ts +0 -5
- package/dist/hooks/index.d.ts.map +0 -1
- package/dist/hooks/mm/index.d.ts +0 -9
- package/dist/hooks/mm/index.d.ts.map +0 -1
- package/dist/hooks/mm/useBorrow.d.ts +0 -35
- package/dist/hooks/mm/useBorrow.d.ts.map +0 -1
- package/dist/hooks/mm/useMMAllowance.d.ts +0 -26
- package/dist/hooks/mm/useMMAllowance.d.ts.map +0 -1
- package/dist/hooks/mm/useMMApprove.d.ts +0 -27
- package/dist/hooks/mm/useMMApprove.d.ts.map +0 -1
- package/dist/hooks/mm/useRepay.d.ts +0 -35
- package/dist/hooks/mm/useRepay.d.ts.map +0 -1
- package/dist/hooks/mm/useReservesData.d.ts +0 -19
- package/dist/hooks/mm/useReservesData.d.ts.map +0 -1
- package/dist/hooks/mm/useSupply.d.ts +0 -34
- package/dist/hooks/mm/useSupply.d.ts.map +0 -1
- package/dist/hooks/mm/useUserReservesData.d.ts +0 -3
- package/dist/hooks/mm/useUserReservesData.d.ts.map +0 -1
- package/dist/hooks/mm/useWithdraw.d.ts +0 -33
- package/dist/hooks/mm/useWithdraw.d.ts.map +0 -1
- package/dist/hooks/provider/index.d.ts +0 -3
- package/dist/hooks/provider/index.d.ts.map +0 -1
- package/dist/hooks/provider/useHubProvider.d.ts +0 -3
- package/dist/hooks/provider/useHubProvider.d.ts.map +0 -1
- package/dist/hooks/provider/useSpokeProvider.d.ts +0 -18
- package/dist/hooks/provider/useSpokeProvider.d.ts.map +0 -1
- package/dist/hooks/shared/index.d.ts +0 -2
- package/dist/hooks/shared/index.d.ts.map +0 -1
- package/dist/hooks/shared/useSodaxContext.d.ts +0 -8
- package/dist/hooks/shared/useSodaxContext.d.ts.map +0 -1
- package/dist/hooks/swap/index.d.ts +0 -6
- package/dist/hooks/swap/index.d.ts.map +0 -1
- package/dist/hooks/swap/useCreateIntentOrder.d.ts +0 -33
- package/dist/hooks/swap/useCreateIntentOrder.d.ts.map +0 -1
- package/dist/hooks/swap/useQuote.d.ts +0 -39
- package/dist/hooks/swap/useQuote.d.ts.map +0 -1
- package/dist/hooks/swap/useStatus.d.ts +0 -31
- package/dist/hooks/swap/useStatus.d.ts.map +0 -1
- package/dist/hooks/swap/useSwapAllowance.d.ts +0 -23
- package/dist/hooks/swap/useSwapAllowance.d.ts.map +0 -1
- package/dist/hooks/swap/useSwapApprove.d.ts +0 -26
- package/dist/hooks/swap/useSwapApprove.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/providers/SodaxProvider.d.ts +0 -10
- package/dist/providers/SodaxProvider.d.ts.map +0 -1
- package/dist/providers/index.d.ts +0 -2
- package/dist/providers/index.d.ts.map +0 -1
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { parseUnits } from 'viem';
|
|
2
|
+
import { useCallback, useState, useRef, useEffect } from 'react';
|
|
3
|
+
import type {
|
|
4
|
+
IcxCreateRevertMigrationParams,
|
|
5
|
+
UnifiedBnUSDMigrateParams,
|
|
6
|
+
SpokeProvider,
|
|
7
|
+
Result,
|
|
8
|
+
ChainId,
|
|
9
|
+
} from '@sodax/sdk';
|
|
10
|
+
import { useSodaxContext } from '../shared/useSodaxContext';
|
|
11
|
+
import { MIGRATION_MODE_BNUSD, MIGRATION_MODE_ICX_SODA, type MigrationIntentParams } from './types';
|
|
12
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
13
|
+
|
|
14
|
+
interface UseApproveReturn {
|
|
15
|
+
approve: ({ params }: { params: MigrationIntentParams }) => Promise<boolean>;
|
|
16
|
+
isLoading: boolean;
|
|
17
|
+
error: Error | null;
|
|
18
|
+
resetError: () => void;
|
|
19
|
+
isApproved: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Hook for approving token spending for migration actions
|
|
24
|
+
* @param params The parameters for the migration approval
|
|
25
|
+
* @param spokeProvider The spoke provider instance for the chain
|
|
26
|
+
* @returns Object containing approve function, loading state, error state and reset function
|
|
27
|
+
* @example
|
|
28
|
+
* ```tsx
|
|
29
|
+
* const { approve, isLoading, error } = useMigrationApprove(params, spokeProvider);
|
|
30
|
+
*
|
|
31
|
+
* // Approve tokens for migration
|
|
32
|
+
* await approve({ params });
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
export function useMigrationApprove(
|
|
37
|
+
params: MigrationIntentParams | undefined,
|
|
38
|
+
spokeProvider: SpokeProvider | undefined,
|
|
39
|
+
): UseApproveReturn {
|
|
40
|
+
const { sodax } = useSodaxContext();
|
|
41
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
42
|
+
const [error, setError] = useState<Error | null>(null);
|
|
43
|
+
const [isApproved, setIsApproved] = useState(false);
|
|
44
|
+
const queryClient = useQueryClient();
|
|
45
|
+
|
|
46
|
+
// Track previous values to reset approval state when needed
|
|
47
|
+
const prevTokenAddress = useRef<string | undefined>(undefined);
|
|
48
|
+
const prevAmount = useRef<string | undefined>(undefined);
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (prevTokenAddress.current !== params?.token?.address || prevAmount.current !== params?.amount) {
|
|
52
|
+
setIsApproved(false);
|
|
53
|
+
prevTokenAddress.current = params?.token?.address;
|
|
54
|
+
prevAmount.current = params?.amount;
|
|
55
|
+
}
|
|
56
|
+
}, [params?.token?.address, params?.amount]);
|
|
57
|
+
|
|
58
|
+
const approve = useCallback(
|
|
59
|
+
async ({ params: approveParams }: { params: MigrationIntentParams }) => {
|
|
60
|
+
try {
|
|
61
|
+
setIsLoading(true);
|
|
62
|
+
setError(null);
|
|
63
|
+
|
|
64
|
+
if (!spokeProvider) {
|
|
65
|
+
throw new Error('Spoke provider not found');
|
|
66
|
+
}
|
|
67
|
+
if (!approveParams) {
|
|
68
|
+
throw new Error('Migration intent not found');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const { token, amount, migrationMode = MIGRATION_MODE_ICX_SODA, toToken, destinationAddress } = approveParams;
|
|
72
|
+
const amountToMigrate = parseUnits(amount ?? '0', token?.decimals ?? 0);
|
|
73
|
+
|
|
74
|
+
let result: Result<string, unknown>;
|
|
75
|
+
if (migrationMode === MIGRATION_MODE_ICX_SODA) {
|
|
76
|
+
// ICX/SODA migration approval
|
|
77
|
+
const revertParams = {
|
|
78
|
+
amount: amountToMigrate,
|
|
79
|
+
to: destinationAddress as `hx${string}`,
|
|
80
|
+
} satisfies IcxCreateRevertMigrationParams;
|
|
81
|
+
|
|
82
|
+
result = await sodax.migration.approve(revertParams, 'revert', spokeProvider, false);
|
|
83
|
+
} else if (migrationMode === MIGRATION_MODE_BNUSD) {
|
|
84
|
+
// bnUSD migration approval
|
|
85
|
+
if (!toToken) throw new Error('Destination token is required for bnUSD migration');
|
|
86
|
+
|
|
87
|
+
const migrationParams = {
|
|
88
|
+
srcChainId: token?.xChainId as ChainId,
|
|
89
|
+
dstChainId: toToken?.xChainId as ChainId,
|
|
90
|
+
srcbnUSD: token?.address as string,
|
|
91
|
+
dstbnUSD: toToken?.address as string,
|
|
92
|
+
amount: amountToMigrate,
|
|
93
|
+
to: destinationAddress as `hx${string}` | `0x${string}`,
|
|
94
|
+
} satisfies UnifiedBnUSDMigrateParams;
|
|
95
|
+
|
|
96
|
+
result = await sodax.migration.approve(migrationParams, 'revert', spokeProvider, false);
|
|
97
|
+
} else {
|
|
98
|
+
throw new Error('Invalid migration mode');
|
|
99
|
+
}
|
|
100
|
+
if (!result.ok) {
|
|
101
|
+
throw new Error('Failed to approve tokens');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
setIsApproved(true);
|
|
105
|
+
queryClient.invalidateQueries({ queryKey: ['migration-allowance', params] });
|
|
106
|
+
return result.ok;
|
|
107
|
+
} catch (err) {
|
|
108
|
+
const error = err instanceof Error ? err : new Error('An unknown error occurred');
|
|
109
|
+
setError(error);
|
|
110
|
+
throw error;
|
|
111
|
+
} finally {
|
|
112
|
+
setIsLoading(false);
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
[spokeProvider, sodax, queryClient, params],
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
const resetError = useCallback(() => {
|
|
119
|
+
setError(null);
|
|
120
|
+
}, []);
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
approve,
|
|
124
|
+
isLoading,
|
|
125
|
+
error,
|
|
126
|
+
resetError,
|
|
127
|
+
isApproved,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
@@ -37,10 +37,11 @@ export function useMMAllowance(
|
|
|
37
37
|
queryKey: ['allowance', token.address, amount, action],
|
|
38
38
|
queryFn: async () => {
|
|
39
39
|
if (!spokeProvider) throw new Error('Spoke provider is required');
|
|
40
|
+
const actionBasedDecimals = action === 'withdraw' || action === 'borrow' ? 18 : token.decimals; // withdraw and borrow actions are in aToken decimals
|
|
40
41
|
const allowance = await sodax.moneyMarket.isAllowanceValid(
|
|
41
42
|
{
|
|
42
43
|
token: token.address,
|
|
43
|
-
amount: parseUnits(amount,
|
|
44
|
+
amount: parseUnits(amount, actionBasedDecimals),
|
|
44
45
|
action,
|
|
45
46
|
},
|
|
46
47
|
spokeProvider,
|
|
@@ -39,10 +39,11 @@ export function useMMApprove(token: XToken, spokeProvider: SpokeProvider | undef
|
|
|
39
39
|
if (!spokeProvider) {
|
|
40
40
|
throw new Error('Spoke provider not found');
|
|
41
41
|
}
|
|
42
|
+
const actionBasedDecimals = action === 'withdraw' || action === 'borrow' ? 18 : token.decimals; // withdraw and borrow actions are in aToken decimals
|
|
42
43
|
const allowance = await sodax.moneyMarket.approve(
|
|
43
44
|
{
|
|
44
45
|
token: token.address,
|
|
45
|
-
amount: parseUnits(amount,
|
|
46
|
+
amount: parseUnits(amount, actionBasedDecimals),
|
|
46
47
|
action,
|
|
47
48
|
},
|
|
48
49
|
spokeProvider,
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { getMoneyMarketConfig } from '@sodax/sdk';
|
|
2
|
-
import type { HubChainId } from '@sodax/types';
|
|
3
1
|
import { useQuery } from '@tanstack/react-query';
|
|
4
2
|
import { useSodaxContext } from '../shared/useSodaxContext';
|
|
5
3
|
/**
|
|
@@ -22,16 +20,11 @@ import { useSodaxContext } from '../shared/useSodaxContext';
|
|
|
22
20
|
|
|
23
21
|
export function useReservesData() {
|
|
24
22
|
const { sodax } = useSodaxContext();
|
|
25
|
-
const hubChainId = (sodax.config?.hubProviderConfig?.chainConfig.chain.id ?? 'sonic') as HubChainId;
|
|
26
23
|
|
|
27
24
|
return useQuery({
|
|
28
25
|
queryKey: ['reservesData'],
|
|
29
26
|
queryFn: async () => {
|
|
30
|
-
|
|
31
|
-
return await sodax.moneyMarket.getReservesData(
|
|
32
|
-
moneyMarketConfig.uiPoolDataProvider,
|
|
33
|
-
moneyMarketConfig.poolAddressesProvider,
|
|
34
|
-
);
|
|
27
|
+
return await sodax.moneyMarket.data.getReservesData();
|
|
35
28
|
},
|
|
36
29
|
});
|
|
37
30
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ReservesDataHumanized } from '@sodax/sdk';
|
|
2
|
+
import { useQuery, type UseQueryResult } from '@tanstack/react-query';
|
|
3
|
+
import { useSodaxContext } from '../shared/useSodaxContext';
|
|
4
|
+
/**
|
|
5
|
+
* Hook for fetching humanized reserves data from the Sodax money market.
|
|
6
|
+
*
|
|
7
|
+
* This hook provides access to the current state of all reserves (humanized format) in the money market protocol,
|
|
8
|
+
* including liquidity, interest rates, and other key metrics. The data is automatically
|
|
9
|
+
* fetched and cached using React Query.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const { data: reservesHumanized, isLoading, error } = useReservesHumanized();
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* @returns A React Query result object containing:
|
|
17
|
+
* - data: The reserves humanized data when available
|
|
18
|
+
* - isLoading: Loading state indicator
|
|
19
|
+
* - error: Any error that occurred during data fetching
|
|
20
|
+
*/
|
|
21
|
+
export function useReservesHumanized(): UseQueryResult<ReservesDataHumanized, Error> {
|
|
22
|
+
const { sodax } = useSodaxContext();
|
|
23
|
+
|
|
24
|
+
return useQuery({
|
|
25
|
+
queryKey: ['reservesHumanized'],
|
|
26
|
+
queryFn: async () => {
|
|
27
|
+
return await sodax.moneyMarket.data.getReservesHumanized();
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { useQuery } from '@tanstack/react-query';
|
|
2
|
+
import { useSodaxContext } from '../shared/useSodaxContext';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Hook for fetching list of reserves from the Sodax money market.
|
|
6
|
+
*
|
|
7
|
+
* This hook provides access to the list of addresses of all reserves in the money market protocol.
|
|
8
|
+
* The data is automatically fetched and cached using React Query.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* const { data: reservesList, isLoading, error } = useReservesList();
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* @returns A React Query result object containing:
|
|
16
|
+
* - data: The reserves list when available
|
|
17
|
+
* - isLoading: Loading state indicator
|
|
18
|
+
* - error: Any error that occurred during data fetching
|
|
19
|
+
*/
|
|
20
|
+
export function useReservesList() {
|
|
21
|
+
const { sodax } = useSodaxContext();
|
|
22
|
+
|
|
23
|
+
return useQuery({
|
|
24
|
+
queryKey: ['reservesList'],
|
|
25
|
+
queryFn: async () => {
|
|
26
|
+
return await sodax.moneyMarket.data.getReservesList();
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { FormatReserveUSDResponse, ReserveData } from '@sodax/sdk';
|
|
2
|
+
import { useQuery, type UseQueryResult } from '@tanstack/react-query';
|
|
3
|
+
import { useSodaxContext } from '../shared/useSodaxContext';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Hook for fetching formatted summary of Sodax user portfolio (holdings, total liquidity,
|
|
7
|
+
* collateral, borrows, liquidation threshold, health factor, available borrowing power, etc..).
|
|
8
|
+
*
|
|
9
|
+
* This hook provides access to the current state of user portfolio in the money market protocol.
|
|
10
|
+
* The data is automatically fetched and cached using React Query.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const { data: userFormattedSummary, isLoading, error } = useUserFormattedSummary();
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @returns A React Query result object containing:
|
|
18
|
+
* - data: The formatted summary of Sodax user portfolio when available
|
|
19
|
+
* - isLoading: Loading state indicator
|
|
20
|
+
* - error: Any error that occurred during data fetching
|
|
21
|
+
*/
|
|
22
|
+
export function useReservesUsdFormat(): UseQueryResult<
|
|
23
|
+
(ReserveData & { priceInMarketReferenceCurrency: string } & FormatReserveUSDResponse)[],
|
|
24
|
+
Error
|
|
25
|
+
> {
|
|
26
|
+
const { sodax } = useSodaxContext();
|
|
27
|
+
|
|
28
|
+
return useQuery({
|
|
29
|
+
queryKey: ['reservesUsdFormat'],
|
|
30
|
+
queryFn: async () => {
|
|
31
|
+
// fetch reserves and hub wallet address
|
|
32
|
+
const reserves = await sodax.moneyMarket.data.getReservesHumanized();
|
|
33
|
+
|
|
34
|
+
// format reserves
|
|
35
|
+
return sodax.moneyMarket.data.formatReservesUSD(sodax.moneyMarket.data.buildReserveDataWithPrice(reserves));
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { FormatUserSummaryResponse, FormatReserveUSDResponse, SpokeProvider } from '@sodax/sdk';
|
|
2
|
+
import { useQuery, type UseQueryResult } from '@tanstack/react-query';
|
|
3
|
+
import { useSodaxContext } from '../shared/useSodaxContext';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Hook for fetching formatted summary of Sodax user portfolio (holdings, total liquidity,
|
|
7
|
+
* collateral, borrows, liquidation threshold, health factor, available borrowing power, etc..).
|
|
8
|
+
*
|
|
9
|
+
* This hook provides access to the current state of user portfolio in the money market protocol.
|
|
10
|
+
* The data is automatically fetched and cached using React Query.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const { data: userFormattedSummary, isLoading, error } = useUserFormattedSummary(spokeProvider, address);
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @returns A React Query result object containing:
|
|
18
|
+
* - data: The formatted summary of Sodax user portfolio when available
|
|
19
|
+
* - isLoading: Loading state indicator
|
|
20
|
+
* - error: Any error that occurred during data fetching
|
|
21
|
+
*/
|
|
22
|
+
export function useUserFormattedSummary(
|
|
23
|
+
spokeProvider: SpokeProvider | undefined,
|
|
24
|
+
address: string | undefined,
|
|
25
|
+
): UseQueryResult<FormatUserSummaryResponse<FormatReserveUSDResponse>, Error> {
|
|
26
|
+
const { sodax } = useSodaxContext();
|
|
27
|
+
|
|
28
|
+
return useQuery({
|
|
29
|
+
queryKey: ['userFormattedSummary', spokeProvider?.chainConfig.chain.id, address],
|
|
30
|
+
queryFn: async () => {
|
|
31
|
+
if (!spokeProvider || !address) {
|
|
32
|
+
throw new Error('Spoke provider or address is not defined');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// fetch reserves and hub wallet address
|
|
36
|
+
const reserves = await sodax.moneyMarket.data.getReservesHumanized();
|
|
37
|
+
|
|
38
|
+
// format reserves
|
|
39
|
+
const formattedReserves = sodax.moneyMarket.data.formatReservesUSD(
|
|
40
|
+
sodax.moneyMarket.data.buildReserveDataWithPrice(reserves),
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
// fetch user reserves
|
|
44
|
+
const userReserves = await sodax.moneyMarket.data.getUserReservesHumanized(spokeProvider);
|
|
45
|
+
|
|
46
|
+
// format user summary
|
|
47
|
+
return sodax.moneyMarket.data.formatUserSummary(
|
|
48
|
+
sodax.moneyMarket.data.buildUserSummaryRequest(reserves, formattedReserves, userReserves),
|
|
49
|
+
);
|
|
50
|
+
},
|
|
51
|
+
enabled: !!spokeProvider && !!address,
|
|
52
|
+
refetchInterval: 5000,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
@@ -1,41 +1,40 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import type { ChainId } from '@sodax/types';
|
|
4
|
-
import { useQuery } from '@tanstack/react-query';
|
|
5
|
-
import { useHubProvider } from '../provider/useHubProvider';
|
|
1
|
+
import type { SpokeProvider, UserReserveData } from '@sodax/sdk';
|
|
2
|
+
import { useQuery, type UseQueryResult } from '@tanstack/react-query';
|
|
6
3
|
import { useSodaxContext } from '../shared/useSodaxContext';
|
|
7
4
|
|
|
8
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Hook for fetching user reserves data from the Sodax money market.
|
|
7
|
+
*
|
|
8
|
+
* This hook provides access to the current state of user reserves in the money market protocol.
|
|
9
|
+
* The data is automatically fetched and cached using React Query.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const { data: userReservesData, isLoading, error } = useUserReservesData(spokeProvider, address);
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* @returns A React Query result object containing:
|
|
17
|
+
* - data: The user reserves data when available
|
|
18
|
+
* - isLoading: Loading state indicator
|
|
19
|
+
* - error: Any error that occurred during data fetching
|
|
20
|
+
*/
|
|
21
|
+
export function useUserReservesData(
|
|
22
|
+
spokeProvider: SpokeProvider | undefined,
|
|
23
|
+
address: string | undefined,
|
|
24
|
+
refetchInterval = 5000,
|
|
25
|
+
): UseQueryResult<readonly [readonly UserReserveData[], number], Error> {
|
|
9
26
|
const { sodax } = useSodaxContext();
|
|
10
|
-
const hubChainId = (sodax.config?.hubProviderConfig?.chainConfig.chain.id ?? 'sonic') as HubChainId;
|
|
11
|
-
const hubProvider = useHubProvider();
|
|
12
27
|
|
|
13
|
-
|
|
14
|
-
queryKey: ['userReserves',
|
|
28
|
+
return useQuery({
|
|
29
|
+
queryKey: ['userReserves', spokeProvider?.chainConfig.chain.id, address],
|
|
15
30
|
queryFn: async () => {
|
|
16
|
-
if (!
|
|
17
|
-
|
|
31
|
+
if (!spokeProvider) {
|
|
32
|
+
throw new Error('Spoke provider or address is not defined');
|
|
18
33
|
}
|
|
19
34
|
|
|
20
|
-
|
|
21
|
-
const hubWalletAddress = await EvmWalletAbstraction.getUserHubWalletAddress(
|
|
22
|
-
spokeChainId as SpokeChainId,
|
|
23
|
-
addressBytes,
|
|
24
|
-
hubProvider as EvmHubProvider,
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
const moneyMarketConfig = getMoneyMarketConfig(hubChainId);
|
|
28
|
-
const [res] = await sodax.moneyMarket.getUserReservesData(
|
|
29
|
-
hubWalletAddress as `0x${string}`,
|
|
30
|
-
moneyMarketConfig.uiPoolDataProvider,
|
|
31
|
-
moneyMarketConfig.poolAddressesProvider,
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
return res;
|
|
35
|
+
return await sodax.moneyMarket.data.getUserReservesData(spokeProvider);
|
|
35
36
|
},
|
|
36
|
-
enabled: !!
|
|
37
|
-
refetchInterval
|
|
37
|
+
enabled: !!spokeProvider && !!address,
|
|
38
|
+
refetchInterval,
|
|
38
39
|
});
|
|
39
|
-
|
|
40
|
-
return userReserves;
|
|
41
40
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { EvmHubProvider } from '@sodax/sdk';
|
|
2
2
|
import { useSodaxContext } from '../shared/useSodaxContext';
|
|
3
3
|
|
|
4
|
-
export function useHubProvider(): EvmHubProvider
|
|
5
|
-
const {
|
|
4
|
+
export function useHubProvider(): EvmHubProvider {
|
|
5
|
+
const { sodax } = useSodaxContext();
|
|
6
6
|
|
|
7
|
-
return hubProvider;
|
|
7
|
+
return sodax.hubProvider;
|
|
8
8
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useSodaxContext } from '@/index';
|
|
1
2
|
import {
|
|
2
3
|
EvmSpokeProvider,
|
|
3
4
|
spokeChainConfig,
|
|
@@ -6,14 +7,17 @@ import {
|
|
|
6
7
|
type EvmSpokeChainConfig,
|
|
7
8
|
IconSpokeProvider,
|
|
8
9
|
type IconSpokeChainConfig,
|
|
9
|
-
|
|
10
|
-
type
|
|
10
|
+
InjectiveSpokeProvider,
|
|
11
|
+
type InjectiveSpokeChainConfig,
|
|
11
12
|
StellarSpokeProvider,
|
|
12
13
|
type StellarSpokeChainConfig,
|
|
13
14
|
type SpokeProvider,
|
|
14
15
|
type IWalletProvider,
|
|
15
16
|
SolanaSpokeProvider,
|
|
16
17
|
type SolanaChainConfig,
|
|
18
|
+
SONIC_MAINNET_CHAIN_ID,
|
|
19
|
+
SonicSpokeProvider,
|
|
20
|
+
type SonicSpokeChainConfig,
|
|
17
21
|
} from '@sodax/sdk';
|
|
18
22
|
import type {
|
|
19
23
|
IEvmWalletProvider,
|
|
@@ -24,7 +28,6 @@ import type {
|
|
|
24
28
|
IStellarWalletProvider,
|
|
25
29
|
ISolanaWalletProvider,
|
|
26
30
|
} from '@sodax/types';
|
|
27
|
-
import { getXChainType, useWalletProvider } from '@sodax/wallet-sdk';
|
|
28
31
|
import { useMemo } from 'react';
|
|
29
32
|
|
|
30
33
|
/**
|
|
@@ -45,56 +48,77 @@ export function useSpokeProvider(
|
|
|
45
48
|
spokeChainId: SpokeChainId | undefined,
|
|
46
49
|
walletProvider?: IWalletProvider | undefined,
|
|
47
50
|
): SpokeProvider | undefined {
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
const _walletProvider = walletProvider ?? walletProvider_;
|
|
51
|
+
const { rpcConfig } = useSodaxContext();
|
|
52
|
+
const xChainType = spokeChainId ? spokeChainConfig[spokeChainId]?.chain.type : undefined;
|
|
51
53
|
|
|
52
54
|
const spokeProvider = useMemo(() => {
|
|
53
|
-
if (!
|
|
55
|
+
if (!walletProvider) return undefined;
|
|
54
56
|
if (!spokeChainId) return undefined;
|
|
55
|
-
|
|
57
|
+
if (!xChainType) return undefined;
|
|
58
|
+
if (!rpcConfig) return undefined;
|
|
59
|
+
|
|
56
60
|
if (xChainType === 'EVM') {
|
|
61
|
+
if (spokeChainId === SONIC_MAINNET_CHAIN_ID) {
|
|
62
|
+
return new SonicSpokeProvider(
|
|
63
|
+
walletProvider as IEvmWalletProvider,
|
|
64
|
+
spokeChainConfig[spokeChainId] as SonicSpokeChainConfig,
|
|
65
|
+
);
|
|
66
|
+
}
|
|
57
67
|
return new EvmSpokeProvider(
|
|
58
|
-
|
|
68
|
+
walletProvider as IEvmWalletProvider,
|
|
59
69
|
spokeChainConfig[spokeChainId] as EvmSpokeChainConfig,
|
|
60
70
|
);
|
|
61
71
|
}
|
|
72
|
+
|
|
62
73
|
if (xChainType === 'SUI') {
|
|
63
74
|
return new SuiSpokeProvider(
|
|
64
75
|
spokeChainConfig[spokeChainId] as SuiSpokeChainConfig,
|
|
65
|
-
|
|
76
|
+
walletProvider as ISuiWalletProvider,
|
|
66
77
|
);
|
|
67
78
|
}
|
|
79
|
+
|
|
68
80
|
if (xChainType === 'ICON') {
|
|
69
81
|
return new IconSpokeProvider(
|
|
70
|
-
|
|
82
|
+
walletProvider as IIconWalletProvider,
|
|
71
83
|
spokeChainConfig[spokeChainId] as IconSpokeChainConfig,
|
|
72
84
|
);
|
|
73
85
|
}
|
|
86
|
+
|
|
74
87
|
if (xChainType === 'INJECTIVE') {
|
|
75
|
-
return new
|
|
76
|
-
spokeChainConfig[spokeChainId] as
|
|
77
|
-
|
|
88
|
+
return new InjectiveSpokeProvider(
|
|
89
|
+
spokeChainConfig[spokeChainId] as InjectiveSpokeChainConfig,
|
|
90
|
+
walletProvider as IInjectiveWalletProvider,
|
|
78
91
|
);
|
|
79
92
|
}
|
|
80
93
|
|
|
81
94
|
if (xChainType === 'STELLAR') {
|
|
82
95
|
const stellarConfig = spokeChainConfig[spokeChainId] as StellarSpokeChainConfig;
|
|
83
|
-
return new StellarSpokeProvider(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
96
|
+
return new StellarSpokeProvider(
|
|
97
|
+
walletProvider as IStellarWalletProvider,
|
|
98
|
+
stellarConfig,
|
|
99
|
+
rpcConfig.stellar
|
|
100
|
+
? rpcConfig.stellar
|
|
101
|
+
: {
|
|
102
|
+
horizonRpcUrl: stellarConfig.horizonRpcUrl,
|
|
103
|
+
sorobanRpcUrl: stellarConfig.sorobanRpcUrl,
|
|
104
|
+
},
|
|
105
|
+
);
|
|
87
106
|
}
|
|
88
107
|
|
|
89
108
|
if (xChainType === 'SOLANA') {
|
|
90
109
|
return new SolanaSpokeProvider(
|
|
91
|
-
|
|
92
|
-
|
|
110
|
+
walletProvider as ISolanaWalletProvider,
|
|
111
|
+
rpcConfig.solana
|
|
112
|
+
? ({
|
|
113
|
+
...spokeChainConfig[spokeChainId],
|
|
114
|
+
rpcUrl: rpcConfig.solana,
|
|
115
|
+
} as SolanaChainConfig)
|
|
116
|
+
: (spokeChainConfig[spokeChainId] as SolanaChainConfig),
|
|
93
117
|
);
|
|
94
118
|
}
|
|
95
119
|
|
|
96
120
|
return undefined;
|
|
97
|
-
}, [spokeChainId, xChainType,
|
|
121
|
+
}, [spokeChainId, xChainType, walletProvider, rpcConfig]);
|
|
98
122
|
|
|
99
123
|
return spokeProvider;
|
|
100
124
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// packages/dapp-kit/src/hooks/shared/useDeriveUserWalletAddress.ts
|
|
2
|
+
import { deriveUserWalletAddress, type SpokeProvider } from '@sodax/sdk';
|
|
3
|
+
import { useQuery, type UseQueryResult } from '@tanstack/react-query';
|
|
4
|
+
import { useSodaxContext } from './useSodaxContext';
|
|
5
|
+
import type { Address } from 'viem';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Hook for deriving user wallet address for hub abstraction.
|
|
9
|
+
*
|
|
10
|
+
* This hook derives the user's abstracted wallet address for the hub chain.
|
|
11
|
+
* If the spoke chain is the same as the hub chain, it returns the original wallet address.
|
|
12
|
+
* Otherwise, it returns the abstracted wallet address for cross-chain operations.
|
|
13
|
+
*
|
|
14
|
+
* @param spokeProvider - The spoke provider instance for the origin chain
|
|
15
|
+
* @param walletAddress - Optional user wallet address on spoke chain. If not provided, will fetch from spokeProvider
|
|
16
|
+
* @returns A React Query result object containing:
|
|
17
|
+
* - data: The derived user wallet address when available
|
|
18
|
+
* - isLoading: Loading state indicator
|
|
19
|
+
* - error: Any error that occurred during derivation
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const { data: derivedAddress, isLoading, error } = useDeriveUserWalletAddress(spokeProvider, userAddress);
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export function useDeriveUserWalletAddress(
|
|
27
|
+
spokeProvider: SpokeProvider | undefined,
|
|
28
|
+
walletAddress?: string | undefined,
|
|
29
|
+
): UseQueryResult<Address, Error> {
|
|
30
|
+
const { sodax } = useSodaxContext();
|
|
31
|
+
|
|
32
|
+
return useQuery({
|
|
33
|
+
queryKey: ['deriveUserWalletAddress', spokeProvider?.chainConfig.chain.id, walletAddress],
|
|
34
|
+
queryFn: async (): Promise<Address> => {
|
|
35
|
+
if (!spokeProvider) {
|
|
36
|
+
throw new Error('Spoke provider is required');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return await deriveUserWalletAddress(spokeProvider, sodax.hubProvider, walletAddress);
|
|
40
|
+
},
|
|
41
|
+
enabled: !!spokeProvider,
|
|
42
|
+
refetchInterval: false, // This is a deterministic operation, no need to refetch
|
|
43
|
+
});
|
|
44
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type GetEstimateGasReturnType, type SpokeProvider, SpokeService, type TxReturnType } from '@sodax/sdk';
|
|
2
|
+
import { useMutation, type UseMutationResult } from '@tanstack/react-query';
|
|
3
|
+
|
|
4
|
+
export function useEstimateGas<T extends SpokeProvider = SpokeProvider>(
|
|
5
|
+
spokeProvider: T | undefined,
|
|
6
|
+
): UseMutationResult<GetEstimateGasReturnType<T>, Error, TxReturnType<T, true>> {
|
|
7
|
+
return useMutation<GetEstimateGasReturnType<T>, Error, TxReturnType<T, true>>({
|
|
8
|
+
mutationFn: async (rawTx: TxReturnType<T, true>) => {
|
|
9
|
+
if (!spokeProvider) {
|
|
10
|
+
throw new Error('spokeProvider is not found');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const response = await SpokeService.estimateGas(rawTx, spokeProvider);
|
|
14
|
+
|
|
15
|
+
return response;
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
}
|