@sodax/dapp-kit 1.5.6-beta → 2.0.0-rc.1
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/README.md +300 -422
- package/ai-exported/AGENTS.md +134 -0
- package/ai-exported/integration/README.md +49 -0
- package/ai-exported/integration/ai-rules.md +79 -0
- package/ai-exported/integration/architecture.md +274 -0
- package/ai-exported/integration/features/README.md +29 -0
- package/ai-exported/integration/features/auxiliary-services.md +169 -0
- package/ai-exported/integration/features/bitcoin.md +87 -0
- package/ai-exported/integration/features/bridge.md +91 -0
- package/ai-exported/integration/features/dex.md +152 -0
- package/ai-exported/integration/features/migration.md +118 -0
- package/ai-exported/integration/features/money-market.md +116 -0
- package/ai-exported/integration/features/staking.md +123 -0
- package/ai-exported/integration/features/swap.md +101 -0
- package/ai-exported/integration/quickstart.md +187 -0
- package/ai-exported/integration/recipes/README.md +136 -0
- package/ai-exported/integration/recipes/backend-queries.md +157 -0
- package/ai-exported/integration/recipes/bitcoin.md +193 -0
- package/ai-exported/integration/recipes/bridge.md +174 -0
- package/ai-exported/integration/recipes/dex.md +204 -0
- package/ai-exported/integration/recipes/invalidations.md +115 -0
- package/ai-exported/integration/recipes/migration.md +212 -0
- package/ai-exported/integration/recipes/money-market.md +206 -0
- package/ai-exported/integration/recipes/mutation-error-handling.md +118 -0
- package/ai-exported/integration/recipes/observability.md +93 -0
- package/ai-exported/integration/recipes/setup.md +144 -0
- package/ai-exported/integration/recipes/staking.md +202 -0
- package/ai-exported/integration/recipes/swap.md +272 -0
- package/ai-exported/integration/recipes/wallet-connectivity.md +101 -0
- package/ai-exported/integration/reference/README.md +12 -0
- package/ai-exported/integration/reference/glossary.md +188 -0
- package/ai-exported/integration/reference/hooks-index.md +194 -0
- package/ai-exported/integration/reference/public-api.md +110 -0
- package/ai-exported/integration/reference/querykey-conventions.md +179 -0
- package/ai-exported/migration/README.md +60 -0
- package/ai-exported/migration/ai-rules.md +81 -0
- package/ai-exported/migration/breaking-changes/hook-signatures.md +233 -0
- package/ai-exported/migration/breaking-changes/querykey-conventions.md +108 -0
- package/ai-exported/migration/breaking-changes/result-handling.md +211 -0
- package/ai-exported/migration/breaking-changes/sdk-leakage.md +165 -0
- package/ai-exported/migration/checklist.md +89 -0
- package/ai-exported/migration/features/README.md +34 -0
- package/ai-exported/migration/features/auxiliary-services.md +114 -0
- package/ai-exported/migration/features/bitcoin.md +88 -0
- package/ai-exported/migration/features/bridge.md +123 -0
- package/ai-exported/migration/features/dex.md +101 -0
- package/ai-exported/migration/features/migration.md +120 -0
- package/ai-exported/migration/features/money-market.md +97 -0
- package/ai-exported/migration/features/staking.md +109 -0
- package/ai-exported/migration/features/swap.md +118 -0
- package/ai-exported/migration/recipes.md +188 -0
- package/ai-exported/migration/reference/README.md +15 -0
- package/ai-exported/migration/reference/deleted-hooks.md +110 -0
- package/ai-exported/migration/reference/error-shape-crosswalk.md +144 -0
- package/ai-exported/migration/reference/renamed-hooks.md +66 -0
- package/dist/index.cjs +2642 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1550 -0
- package/dist/index.d.ts +1020 -2051
- package/dist/index.mjs +1594 -1532
- package/dist/index.mjs.map +1 -1
- package/package.json +20 -10
- package/src/contexts/index.ts +0 -3
- package/src/hooks/_mutationContract.test.ts +99 -0
- package/src/hooks/backend/README.md +2 -2
- package/src/hooks/backend/index.ts +13 -13
- package/src/hooks/backend/unwrapResult.ts +1 -0
- package/src/hooks/backend/useBackendAllMoneyMarketAssets.ts +13 -45
- package/src/hooks/backend/useBackendAllMoneyMarketBorrowers.ts +29 -59
- package/src/hooks/backend/useBackendIntentByHash.ts +21 -47
- package/src/hooks/backend/useBackendIntentByTxHash.ts +23 -50
- package/src/hooks/backend/useBackendMoneyMarketAsset.ts +21 -54
- package/src/hooks/backend/useBackendMoneyMarketAssetBorrowers.ts +30 -57
- package/src/hooks/backend/useBackendMoneyMarketAssetSuppliers.ts +31 -58
- package/src/hooks/backend/useBackendMoneyMarketPosition.ts +22 -38
- package/src/hooks/backend/useBackendOrderbook.ts +27 -49
- package/src/hooks/backend/useBackendSubmitSwapTx.ts +30 -36
- package/src/hooks/backend/useBackendSubmitSwapTxStatus.ts +38 -58
- package/src/hooks/backend/useBackendUserIntents.ts +25 -63
- package/src/hooks/bitcoin/index.ts +9 -8
- package/src/hooks/bitcoin/useBitcoinBalance.ts +20 -5
- package/src/hooks/bitcoin/useExpiredUtxos.ts +26 -16
- package/src/hooks/bitcoin/useFundTradingWallet.ts +33 -30
- package/src/hooks/bitcoin/useRadfiAuth.ts +43 -40
- package/src/hooks/bitcoin/useRadfiSession.ts +53 -59
- package/src/hooks/bitcoin/useRadfiWithdraw.ts +35 -53
- package/src/hooks/bitcoin/useRenewUtxos.ts +30 -50
- package/src/hooks/bitcoin/useTradingWallet.ts +1 -1
- package/src/hooks/bitcoin/useTradingWalletBalance.ts +25 -14
- package/src/hooks/bridge/index.ts +5 -5
- package/src/hooks/bridge/useBridge.ts +29 -55
- package/src/hooks/bridge/useBridgeAllowance.ts +38 -38
- package/src/hooks/bridge/useBridgeApprove.ts +32 -57
- package/src/hooks/bridge/useGetBridgeableAmount.ts +23 -37
- package/src/hooks/bridge/useGetBridgeableTokens.ts +27 -50
- package/src/hooks/dex/index.ts +16 -16
- package/src/hooks/dex/useClaimRewards.ts +35 -54
- package/src/hooks/dex/useCreateDecreaseLiquidityParams.ts +7 -20
- package/src/hooks/dex/useCreateDepositParams.ts +7 -21
- package/src/hooks/dex/useCreateSupplyLiquidityParams.ts +13 -28
- package/src/hooks/dex/useCreateWithdrawParams.ts +7 -20
- package/src/hooks/dex/useDecreaseLiquidity.ts +40 -66
- package/src/hooks/dex/useDexAllowance.ts +29 -75
- package/src/hooks/dex/useDexApprove.ts +32 -43
- package/src/hooks/dex/useDexDeposit.ts +42 -49
- package/src/hooks/dex/useDexWithdraw.ts +32 -43
- package/src/hooks/dex/useLiquidityAmounts.ts +27 -84
- package/src/hooks/dex/usePoolBalances.ts +50 -72
- package/src/hooks/dex/usePoolData.ts +17 -43
- package/src/hooks/dex/usePools.ts +11 -38
- package/src/hooks/dex/usePositionInfo.ts +27 -62
- package/src/hooks/dex/useSupplyLiquidity.ts +80 -75
- package/src/hooks/index.ts +12 -10
- package/src/hooks/migrate/index.ts +13 -4
- package/src/hooks/migrate/useMigrateBaln.ts +42 -0
- package/src/hooks/migrate/useMigrateIcxToSoda.ts +44 -0
- package/src/hooks/migrate/useMigratebnUSD.ts +47 -0
- package/src/hooks/migrate/useMigrationAllowance.ts +76 -0
- package/src/hooks/migrate/useMigrationApprove.ts +66 -0
- package/src/hooks/migrate/useRevertMigrateSodaToIcx.ts +39 -0
- package/src/hooks/mm/index.ts +14 -12
- package/src/hooks/mm/useAToken.ts +25 -41
- package/src/hooks/mm/useATokensBalances.ts +29 -60
- package/src/hooks/mm/useBorrow.ts +38 -56
- package/src/hooks/mm/useMMAllowance.ts +37 -73
- package/src/hooks/mm/useMMApprove.ts +36 -43
- package/src/hooks/mm/useRepay.ts +33 -53
- package/src/hooks/mm/useReservesData.ts +12 -38
- package/src/hooks/mm/useReservesHumanized.ts +12 -31
- package/src/hooks/mm/useReservesList.ts +11 -31
- package/src/hooks/mm/useReservesUsdFormat.ts +15 -35
- package/src/hooks/mm/useSupply.ts +45 -51
- package/src/hooks/mm/useUserFormattedSummary.ts +32 -84
- package/src/hooks/mm/useUserReservesData.ts +27 -77
- package/src/hooks/mm/useWithdraw.ts +38 -54
- package/src/hooks/partner/index.ts +6 -0
- package/src/hooks/partner/useApproveToken.ts +42 -0
- package/src/hooks/partner/useFeeClaimSwap.ts +38 -0
- package/src/hooks/partner/useFetchAssetsBalances.ts +37 -0
- package/src/hooks/partner/useGetAutoSwapPreferences.ts +37 -0
- package/src/hooks/partner/useIsTokenApproved.ts +39 -0
- package/src/hooks/partner/useSetSwapPreference.ts +50 -0
- package/src/hooks/provider/index.ts +1 -2
- package/src/hooks/provider/useHubProvider.ts +1 -1
- package/src/hooks/recovery/index.ts +2 -0
- package/src/hooks/recovery/useHubAssetBalances.ts +43 -0
- package/src/hooks/recovery/useWithdrawHubAsset.ts +48 -0
- package/src/hooks/shared/index.ts +10 -6
- package/src/hooks/shared/types.ts +77 -0
- package/src/hooks/shared/unwrapResult.ts +19 -0
- package/src/hooks/shared/useDeriveUserWalletAddress.ts +22 -40
- package/src/hooks/shared/useEstimateGas.ts +18 -15
- package/src/hooks/shared/useGetUserHubWalletAddress.ts +25 -26
- package/src/hooks/shared/useRequestTrustline.ts +28 -61
- package/src/hooks/shared/useSafeMutation.test.ts +43 -0
- package/src/hooks/shared/useSafeMutation.ts +68 -0
- package/src/hooks/shared/useSodaxContext.ts +1 -1
- package/src/hooks/shared/useStellarTrustlineCheck.ts +30 -64
- package/src/hooks/shared/useXBalances.test.ts +113 -0
- package/src/hooks/shared/useXBalances.ts +61 -0
- package/src/hooks/staking/index.ts +18 -18
- package/src/hooks/staking/useCancelUnstake.ts +30 -41
- package/src/hooks/staking/useClaim.ts +27 -36
- package/src/hooks/staking/useConvertedAssets.ts +24 -34
- package/src/hooks/staking/useInstantUnstake.ts +33 -40
- package/src/hooks/staking/useInstantUnstakeAllowance.ts +37 -45
- package/src/hooks/staking/useInstantUnstakeApprove.ts +42 -42
- package/src/hooks/staking/useInstantUnstakeRatio.ts +24 -41
- package/src/hooks/staking/useStake.ts +32 -37
- package/src/hooks/staking/useStakeAllowance.ts +30 -43
- package/src/hooks/staking/useStakeApprove.ts +40 -40
- package/src/hooks/staking/useStakeRatio.ts +24 -40
- package/src/hooks/staking/useStakingConfig.ts +14 -27
- package/src/hooks/staking/useStakingInfo.ts +30 -38
- package/src/hooks/staking/useUnstake.ts +29 -43
- package/src/hooks/staking/useUnstakeAllowance.ts +37 -44
- package/src/hooks/staking/useUnstakeApprove.ts +40 -43
- package/src/hooks/staking/useUnstakingInfo.ts +29 -41
- package/src/hooks/staking/useUnstakingInfoWithPenalty.ts +31 -47
- package/src/hooks/swap/index.ts +8 -8
- package/src/hooks/swap/useCancelLimitOrder.ts +24 -41
- package/src/hooks/swap/useCancelSwap.ts +24 -33
- package/src/hooks/swap/useCreateLimitOrder.ts +29 -62
- package/src/hooks/swap/useQuote.ts +17 -43
- package/src/hooks/swap/useStatus.ts +22 -29
- package/src/hooks/swap/useSwap.ts +31 -49
- package/src/hooks/swap/useSwapAllowance.ts +38 -35
- package/src/hooks/swap/useSwapApprove.ts +48 -57
- package/src/index.ts +5 -3
- package/src/providers/SodaxProvider.tsx +17 -11
- package/src/providers/createSodaxQueryClient.ts +96 -0
- package/src/providers/index.ts +2 -1
- package/src/utils/dex-utils.ts +27 -5
- package/src/utils/index.ts +1 -1
- package/dist/index.d.mts +0 -2581
- package/dist/index.js +0 -2562
- package/dist/index.js.map +0 -1
- package/src/hooks/migrate/types.ts +0 -15
- package/src/hooks/migrate/useMigrate.tsx +0 -110
- package/src/hooks/migrate/useMigrationAllowance.tsx +0 -79
- package/src/hooks/migrate/useMigrationApprove.tsx +0 -129
- package/src/hooks/provider/useSpokeProvider.ts +0 -172
|
@@ -1,14 +1,16 @@
|
|
|
1
|
+
// packages/dapp-kit/src/hooks/bitcoin/useRadfiSession.ts
|
|
1
2
|
import { useState, useEffect, useRef, useCallback } from 'react';
|
|
2
|
-
import type {
|
|
3
|
+
import type { IBitcoinWalletProvider } from '@sodax/sdk';
|
|
3
4
|
import {
|
|
4
5
|
useRadfiAuth,
|
|
5
6
|
loadRadfiSession,
|
|
6
7
|
saveRadfiSession,
|
|
7
8
|
clearRadfiSession,
|
|
8
9
|
type RadfiSession,
|
|
9
|
-
} from './useRadfiAuth';
|
|
10
|
+
} from './useRadfiAuth.js';
|
|
11
|
+
import { useSodaxContext } from '../shared/useSodaxContext.js';
|
|
10
12
|
|
|
11
|
-
const REFRESH_INTERVAL = 5 * 60 * 1000;
|
|
13
|
+
const REFRESH_INTERVAL = 5 * 60 * 1000;
|
|
12
14
|
|
|
13
15
|
export type UseRadfiSessionReturn = {
|
|
14
16
|
walletAddress: string | undefined;
|
|
@@ -18,94 +20,86 @@ export type UseRadfiSessionReturn = {
|
|
|
18
20
|
isLoginPending: boolean;
|
|
19
21
|
};
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
* - On mount / wallet switch: refreshes token to validate session
|
|
24
|
-
* - Single interval (~5 min): refreshes access token. If refresh fails → clears session, isAuthed=false
|
|
25
|
-
* - ensureRadfiAccessToken (SDK layer) acts as safety net before swap/bridge
|
|
26
|
-
* - Exposes login() and isAuthed for UI
|
|
27
|
-
*/
|
|
28
|
-
export function useRadfiSession(
|
|
29
|
-
spokeProvider: BitcoinSpokeProvider | undefined,
|
|
30
|
-
): UseRadfiSessionReturn {
|
|
23
|
+
export function useRadfiSession(walletProvider: IBitcoinWalletProvider | undefined): UseRadfiSessionReturn {
|
|
24
|
+
const { sodax } = useSodaxContext();
|
|
31
25
|
const [walletAddress, setWalletAddress] = useState<string | undefined>();
|
|
32
26
|
const [isAuthed, setIsAuthed] = useState(false);
|
|
33
27
|
const [tradingAddress, setTradingAddress] = useState<string | undefined>();
|
|
34
28
|
const isRefreshingRef = useRef(false);
|
|
35
29
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
30
|
+
const silentRefresh = useCallback(
|
|
31
|
+
async (address: string) => {
|
|
32
|
+
if (!walletProvider || isRefreshingRef.current) return;
|
|
33
|
+
isRefreshingRef.current = true;
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
const session = loadRadfiSession(address);
|
|
37
|
+
if (!session?.refreshToken) {
|
|
38
|
+
setIsAuthed(false);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const radfi = sodax.spoke.bitcoin.radfi;
|
|
43
|
+
const { accessToken, refreshToken } = await radfi.refreshAccessToken(session.refreshToken);
|
|
44
|
+
const updated: RadfiSession = { ...session, accessToken, refreshToken };
|
|
45
|
+
|
|
46
|
+
saveRadfiSession(address, updated);
|
|
47
|
+
radfi.setRadfiAccessToken(accessToken, refreshToken);
|
|
48
|
+
setIsAuthed(true);
|
|
49
|
+
setTradingAddress(updated.tradingAddress || undefined);
|
|
50
|
+
} catch {
|
|
51
|
+
clearRadfiSession(address);
|
|
52
|
+
sodax.spoke.bitcoin.radfi.setRadfiAccessToken('', '');
|
|
44
53
|
setIsAuthed(false);
|
|
45
|
-
|
|
54
|
+
setTradingAddress(undefined);
|
|
55
|
+
} finally {
|
|
56
|
+
isRefreshingRef.current = false;
|
|
46
57
|
}
|
|
58
|
+
},
|
|
59
|
+
[walletProvider, sodax],
|
|
60
|
+
);
|
|
47
61
|
|
|
48
|
-
const { accessToken, refreshToken } = await spokeProvider.radfi.refreshAccessToken(session.refreshToken);
|
|
49
|
-
const updated: RadfiSession = {
|
|
50
|
-
...session,
|
|
51
|
-
accessToken,
|
|
52
|
-
refreshToken,
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
saveRadfiSession(address, updated);
|
|
56
|
-
spokeProvider.setRadfiAccessToken(accessToken, refreshToken);
|
|
57
|
-
setIsAuthed(true);
|
|
58
|
-
setTradingAddress(updated.tradingAddress || undefined);
|
|
59
|
-
} catch {
|
|
60
|
-
clearRadfiSession(address);
|
|
61
|
-
spokeProvider.setRadfiAccessToken('', '');
|
|
62
|
-
setIsAuthed(false);
|
|
63
|
-
setTradingAddress(undefined);
|
|
64
|
-
} finally {
|
|
65
|
-
isRefreshingRef.current = false;
|
|
66
|
-
}
|
|
67
|
-
}, [spokeProvider]);
|
|
68
|
-
|
|
69
|
-
// ── On mount / wallet switch: reset state + refresh to validate session ──
|
|
70
62
|
useEffect(() => {
|
|
71
|
-
if (!
|
|
63
|
+
if (!walletProvider) return;
|
|
72
64
|
|
|
73
|
-
// Reset state immediately to avoid stale data from previous wallet
|
|
74
65
|
setIsAuthed(false);
|
|
75
66
|
setTradingAddress(undefined);
|
|
76
67
|
setWalletAddress(undefined);
|
|
77
68
|
|
|
78
|
-
|
|
79
|
-
.
|
|
69
|
+
walletProvider
|
|
70
|
+
.getWalletAddress()
|
|
71
|
+
.then((addr: string) => {
|
|
80
72
|
setWalletAddress(addr);
|
|
81
73
|
const session = loadRadfiSession(addr);
|
|
82
74
|
if (!session?.refreshToken) return;
|
|
83
|
-
|
|
84
|
-
// Always refresh on mount to validate the session is actually valid
|
|
85
75
|
silentRefresh(addr);
|
|
86
76
|
})
|
|
87
77
|
.catch(() => {});
|
|
88
|
-
}, [
|
|
78
|
+
}, [walletProvider, silentRefresh]);
|
|
89
79
|
|
|
90
|
-
// ── Interval: refresh token every 5 min to keep access token fresh ──────
|
|
91
80
|
useEffect(() => {
|
|
92
|
-
if (!walletAddress || !
|
|
81
|
+
if (!walletAddress || !walletProvider) return;
|
|
93
82
|
|
|
94
83
|
const id = setInterval(() => {
|
|
95
84
|
silentRefresh(walletAddress);
|
|
96
85
|
}, REFRESH_INTERVAL);
|
|
97
86
|
|
|
98
87
|
return () => clearInterval(id);
|
|
99
|
-
}, [walletAddress,
|
|
88
|
+
}, [walletAddress, walletProvider, silentRefresh]);
|
|
100
89
|
|
|
101
|
-
|
|
102
|
-
const { mutateAsync: loginMutate, isPending: isLoginPending } = useRadfiAuth(spokeProvider);
|
|
90
|
+
const { mutateAsyncSafe: loginMutateSafe, isPending: isLoginPending } = useRadfiAuth();
|
|
103
91
|
|
|
104
92
|
const login = useCallback(async () => {
|
|
105
|
-
|
|
93
|
+
if (!walletProvider) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const result = await loginMutateSafe({ walletProvider });
|
|
97
|
+
if (!result.ok) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
106
100
|
setIsAuthed(true);
|
|
107
|
-
setTradingAddress(result.tradingAddress || undefined);
|
|
108
|
-
}, [
|
|
101
|
+
setTradingAddress(result.value.tradingAddress || undefined);
|
|
102
|
+
}, [loginMutateSafe, walletProvider]);
|
|
109
103
|
|
|
110
104
|
return { walletAddress, isAuthed, tradingAddress, login, isLoginPending };
|
|
111
105
|
}
|
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
// packages/dapp-kit/src/hooks/bitcoin/useRadfiWithdraw.ts
|
|
2
|
+
import { normalizePsbtToBase64, ChainKeys, type IBitcoinWalletProvider } from '@sodax/sdk';
|
|
3
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
4
|
+
import { loadRadfiSession } from './useRadfiAuth.js';
|
|
5
|
+
import { useSodaxContext } from '../shared/useSodaxContext.js';
|
|
6
|
+
import type { MutationHookParams } from '../shared/types.js';
|
|
7
|
+
import { useSafeMutation, type SafeUseMutationResult } from '../shared/useSafeMutation.js';
|
|
4
8
|
|
|
5
|
-
type
|
|
9
|
+
export type UseRadfiWithdrawVars = {
|
|
6
10
|
amount: string;
|
|
7
11
|
tokenId: string;
|
|
8
12
|
withdrawTo: string;
|
|
13
|
+
walletProvider: IBitcoinWalletProvider;
|
|
9
14
|
};
|
|
10
15
|
|
|
11
16
|
type WithdrawResult = {
|
|
@@ -14,72 +19,49 @@ type WithdrawResult = {
|
|
|
14
19
|
};
|
|
15
20
|
|
|
16
21
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* 1. Build withdraw transaction via Radfi API (returns unsigned PSBT)
|
|
21
|
-
* 2. User signs the PSBT with their wallet
|
|
22
|
-
* 3. Submit signed PSBT back to Radfi for co-signing and broadcasting
|
|
23
|
-
*
|
|
24
|
-
* @example
|
|
25
|
-
* ```tsx
|
|
26
|
-
* const { mutateAsync: withdraw, isPending } = useRadfiWithdraw(spokeProvider);
|
|
27
|
-
*
|
|
28
|
-
* const handleWithdraw = async () => {
|
|
29
|
-
* const result = await withdraw({
|
|
30
|
-
* amount: '10000',
|
|
31
|
-
* tokenId: '0:0',
|
|
32
|
-
* withdrawTo: 'bc1q...', // user's segwit address
|
|
33
|
-
* });
|
|
34
|
-
* console.log('Withdrawn:', result.txId);
|
|
35
|
-
* };
|
|
36
|
-
* ```
|
|
22
|
+
* React hook for withdrawing BTC from the user's Radfi trading wallet back to their personal
|
|
23
|
+
* Bitcoin wallet. Pure mutation: pass all inputs (including the wallet provider) to
|
|
24
|
+
* `mutate({...})`.
|
|
37
25
|
*/
|
|
38
|
-
export function useRadfiWithdraw(
|
|
39
|
-
|
|
40
|
-
|
|
26
|
+
export function useRadfiWithdraw({
|
|
27
|
+
mutationOptions,
|
|
28
|
+
}: MutationHookParams<WithdrawResult, UseRadfiWithdrawVars> = {}): SafeUseMutationResult<
|
|
29
|
+
WithdrawResult,
|
|
30
|
+
Error,
|
|
31
|
+
UseRadfiWithdrawVars
|
|
32
|
+
> {
|
|
33
|
+
const { sodax } = useSodaxContext();
|
|
41
34
|
const queryClient = useQueryClient();
|
|
42
35
|
|
|
43
|
-
return
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
36
|
+
return useSafeMutation<WithdrawResult, Error, UseRadfiWithdrawVars>({
|
|
37
|
+
mutationKey: ['bitcoin', 'radfiWithdraw'],
|
|
38
|
+
...mutationOptions,
|
|
39
|
+
mutationFn: async ({ amount, tokenId, withdrawTo, walletProvider }) => {
|
|
40
|
+
const radfi = sodax.spoke.bitcoin.radfi;
|
|
48
41
|
|
|
49
|
-
const userAddress = await
|
|
42
|
+
const userAddress = await walletProvider.getWalletAddress();
|
|
50
43
|
const session = loadRadfiSession(userAddress);
|
|
51
|
-
const accessToken = session?.accessToken ||
|
|
44
|
+
const accessToken = session?.accessToken || radfi.accessToken;
|
|
52
45
|
|
|
53
46
|
if (!accessToken) {
|
|
54
47
|
throw new Error('Radfi authentication required. Please login first.');
|
|
55
48
|
}
|
|
56
49
|
|
|
57
|
-
|
|
58
|
-
const buildResult = await spokeProvider.radfi.withdrawToUser(
|
|
59
|
-
{ userAddress, amount, tokenId, withdrawTo },
|
|
60
|
-
accessToken,
|
|
61
|
-
);
|
|
50
|
+
const buildResult = await radfi.withdrawToUser({ userAddress, amount, tokenId, withdrawTo }, accessToken);
|
|
62
51
|
|
|
63
|
-
|
|
64
|
-
const signedTx = await spokeProvider.walletProvider.signTransaction(
|
|
65
|
-
buildResult.base64Psbt,
|
|
66
|
-
false,
|
|
67
|
-
);
|
|
52
|
+
const signedTx = await walletProvider.signTransaction(buildResult.base64Psbt, false);
|
|
68
53
|
|
|
69
54
|
const signedBase64Tx = normalizePsbtToBase64(signedTx);
|
|
70
55
|
|
|
71
|
-
|
|
72
|
-
const txId = await spokeProvider.radfi.signAndBroadcastWithdraw(
|
|
73
|
-
{ userAddress, signedBase64Tx },
|
|
74
|
-
accessToken,
|
|
75
|
-
);
|
|
56
|
+
const txId = await radfi.signAndBroadcastWithdraw({ userAddress, signedBase64Tx }, accessToken);
|
|
76
57
|
|
|
77
58
|
return { txId, fee: buildResult.fee.totalFee };
|
|
78
59
|
},
|
|
79
|
-
onSuccess: () => {
|
|
80
|
-
queryClient.invalidateQueries({ queryKey: ['
|
|
81
|
-
queryClient.invalidateQueries({ queryKey: ['
|
|
82
|
-
queryClient.invalidateQueries({ queryKey: ['xBalances'] });
|
|
60
|
+
onSuccess: async (data, vars, ctx) => {
|
|
61
|
+
queryClient.invalidateQueries({ queryKey: ['bitcoin', 'tradingWalletBalance'] });
|
|
62
|
+
queryClient.invalidateQueries({ queryKey: ['bitcoin', 'balance'] });
|
|
63
|
+
queryClient.invalidateQueries({ queryKey: ['shared', 'xBalances', ChainKeys.BITCOIN_MAINNET] });
|
|
64
|
+
await mutationOptions?.onSuccess?.(data, vars, ctx);
|
|
83
65
|
},
|
|
84
66
|
});
|
|
85
67
|
}
|
|
@@ -1,72 +1,52 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
// packages/dapp-kit/src/hooks/bitcoin/useRenewUtxos.ts
|
|
2
|
+
import { normalizePsbtToBase64, type IBitcoinWalletProvider } from '@sodax/sdk';
|
|
3
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
4
|
+
import { loadRadfiSession } from './useRadfiAuth.js';
|
|
5
|
+
import { useSodaxContext } from '../shared/useSodaxContext.js';
|
|
6
|
+
import type { MutationHookParams } from '../shared/types.js';
|
|
7
|
+
import { useSafeMutation, type SafeUseMutationResult } from '../shared/useSafeMutation.js';
|
|
8
|
+
|
|
9
|
+
export type UseRenewUtxosVars = {
|
|
6
10
|
txIdVouts: string[];
|
|
11
|
+
walletProvider: IBitcoinWalletProvider;
|
|
7
12
|
};
|
|
8
13
|
|
|
9
14
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* Flow:
|
|
13
|
-
* 1. Build renew-utxo transaction via Radfi API (returns unsigned PSBT)
|
|
14
|
-
* 2. User signs the PSBT with their wallet
|
|
15
|
-
* 3. Submit signed PSBT back to Radfi for co-signing and broadcasting
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* ```tsx
|
|
19
|
-
* const { mutateAsync: renewUtxos, isPending } = useRenewUtxos(spokeProvider);
|
|
20
|
-
*
|
|
21
|
-
* const handleRenew = async (expiredUtxos: RadfiUtxo[]) => {
|
|
22
|
-
* const txIdVouts = expiredUtxos.map(u => u.txidVout);
|
|
23
|
-
* const txId = await renewUtxos({ txIdVouts });
|
|
24
|
-
* console.log('Renewed:', txId);
|
|
25
|
-
* };
|
|
26
|
-
* ```
|
|
15
|
+
* React hook for renewing expired UTXOs in the user's Radfi trading wallet. Pure mutation: pass
|
|
16
|
+
* `{ txIdVouts, walletProvider }` to `mutate({...})`.
|
|
27
17
|
*/
|
|
28
|
-
export function useRenewUtxos(
|
|
29
|
-
|
|
30
|
-
):
|
|
18
|
+
export function useRenewUtxos({
|
|
19
|
+
mutationOptions,
|
|
20
|
+
}: MutationHookParams<string, UseRenewUtxosVars> = {}): SafeUseMutationResult<string, Error, UseRenewUtxosVars> {
|
|
21
|
+
const { sodax } = useSodaxContext();
|
|
31
22
|
const queryClient = useQueryClient();
|
|
32
23
|
|
|
33
|
-
return
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
24
|
+
return useSafeMutation<string, Error, UseRenewUtxosVars>({
|
|
25
|
+
mutationKey: ['bitcoin', 'renewUtxos'],
|
|
26
|
+
...mutationOptions,
|
|
27
|
+
mutationFn: async ({ txIdVouts, walletProvider }) => {
|
|
28
|
+
const radfi = sodax.spoke.bitcoin.radfi;
|
|
38
29
|
|
|
39
|
-
const userAddress = await
|
|
30
|
+
const userAddress = await walletProvider.getWalletAddress();
|
|
40
31
|
const session = loadRadfiSession(userAddress);
|
|
41
|
-
const accessToken = session?.accessToken ||
|
|
32
|
+
const accessToken = session?.accessToken || radfi.accessToken;
|
|
42
33
|
|
|
43
34
|
if (!accessToken) {
|
|
44
35
|
throw new Error('Radfi authentication required. Please login first.');
|
|
45
36
|
}
|
|
46
37
|
|
|
47
|
-
|
|
48
|
-
const buildResult = await spokeProvider.radfi.buildRenewUtxoTransaction(
|
|
49
|
-
{ userAddress, txIdVouts },
|
|
50
|
-
accessToken,
|
|
51
|
-
);
|
|
38
|
+
const buildResult = await radfi.buildRenewUtxoTransaction({ userAddress, txIdVouts }, accessToken);
|
|
52
39
|
|
|
53
|
-
|
|
54
|
-
const signedTx = await spokeProvider.walletProvider.signTransaction(
|
|
55
|
-
buildResult.base64Psbt,
|
|
56
|
-
false,
|
|
57
|
-
);
|
|
40
|
+
const signedTx = await walletProvider.signTransaction(buildResult.base64Psbt, false);
|
|
58
41
|
|
|
59
42
|
const signedBase64Tx = normalizePsbtToBase64(signedTx);
|
|
60
43
|
|
|
61
|
-
|
|
62
|
-
return spokeProvider.radfi.signAndBroadcastRenewUtxo(
|
|
63
|
-
{ userAddress, signedBase64Tx },
|
|
64
|
-
accessToken,
|
|
65
|
-
);
|
|
44
|
+
return radfi.signAndBroadcastRenewUtxo({ userAddress, signedBase64Tx }, accessToken);
|
|
66
45
|
},
|
|
67
|
-
onSuccess: () => {
|
|
68
|
-
queryClient.invalidateQueries({ queryKey: ['
|
|
69
|
-
queryClient.invalidateQueries({ queryKey: ['
|
|
46
|
+
onSuccess: async (data, vars, ctx) => {
|
|
47
|
+
queryClient.invalidateQueries({ queryKey: ['bitcoin', 'expiredUtxos'] });
|
|
48
|
+
queryClient.invalidateQueries({ queryKey: ['bitcoin', 'tradingWalletBalance'] });
|
|
49
|
+
await mutationOptions?.onSuccess?.(data, vars, ctx);
|
|
70
50
|
},
|
|
71
51
|
});
|
|
72
52
|
}
|
|
@@ -1,22 +1,33 @@
|
|
|
1
1
|
import { useQuery, type UseQueryResult } from '@tanstack/react-query';
|
|
2
|
-
import type {
|
|
2
|
+
import type { RadfiWalletBalance, IBitcoinWalletProvider } from '@sodax/sdk';
|
|
3
|
+
import { useSodaxContext } from '../shared/useSodaxContext.js';
|
|
4
|
+
import type { ReadHookParams } from '../shared/types.js';
|
|
5
|
+
|
|
6
|
+
export type UseTradingWalletBalanceParams = ReadHookParams<
|
|
7
|
+
RadfiWalletBalance,
|
|
8
|
+
{
|
|
9
|
+
walletProvider: IBitcoinWalletProvider | undefined;
|
|
10
|
+
tradingAddress: string | undefined;
|
|
11
|
+
}
|
|
12
|
+
>;
|
|
13
|
+
|
|
14
|
+
export function useTradingWalletBalance({
|
|
15
|
+
params,
|
|
16
|
+
queryOptions,
|
|
17
|
+
}: UseTradingWalletBalanceParams = {}): UseQueryResult<RadfiWalletBalance, Error> {
|
|
18
|
+
const { sodax } = useSodaxContext();
|
|
19
|
+
const walletProvider = params?.walletProvider;
|
|
20
|
+
const tradingAddress = params?.tradingAddress;
|
|
3
21
|
|
|
4
|
-
/**
|
|
5
|
-
* Hook to fetch trading wallet balance from Radfi API.
|
|
6
|
-
* Returns confirmed + pending satoshi balances.
|
|
7
|
-
*/
|
|
8
|
-
export function useTradingWalletBalance(
|
|
9
|
-
spokeProvider: BitcoinSpokeProvider | undefined,
|
|
10
|
-
tradingAddress: string | undefined,
|
|
11
|
-
): UseQueryResult<RadfiWalletBalance, Error> {
|
|
12
22
|
return useQuery<RadfiWalletBalance, Error>({
|
|
13
|
-
queryKey: ['
|
|
23
|
+
queryKey: ['bitcoin', 'tradingWalletBalance', tradingAddress],
|
|
14
24
|
queryFn: () => {
|
|
15
|
-
if (!
|
|
16
|
-
throw new Error('
|
|
25
|
+
if (!walletProvider || !tradingAddress) {
|
|
26
|
+
throw new Error('walletProvider and tradingAddress are required');
|
|
17
27
|
}
|
|
18
|
-
return
|
|
28
|
+
return sodax.spoke.bitcoin.radfi.getBalance(tradingAddress);
|
|
19
29
|
},
|
|
20
|
-
enabled: !!
|
|
30
|
+
enabled: !!walletProvider && !!tradingAddress,
|
|
31
|
+
...queryOptions,
|
|
21
32
|
});
|
|
22
33
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export * from './
|
|
2
|
-
export * from './
|
|
3
|
-
export * from './
|
|
4
|
-
export * from './useGetBridgeableAmount';
|
|
5
|
-
export * from './useGetBridgeableTokens';
|
|
1
|
+
export * from './useBridge.js';
|
|
2
|
+
export * from './useBridgeAllowance.js';
|
|
3
|
+
export * from './useBridgeApprove.js';
|
|
4
|
+
export * from './useGetBridgeableAmount.js';
|
|
5
|
+
export * from './useGetBridgeableTokens.js';
|
|
@@ -1,64 +1,38 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
CreateBridgeIntentParams,
|
|
9
|
-
} from '@sodax/sdk';
|
|
10
|
-
import { useMutation, type UseMutationResult } from '@tanstack/react-query';
|
|
11
|
-
import type { SpokeProvider } from '@sodax/sdk';
|
|
1
|
+
// packages/dapp-kit/src/hooks/bridge/useBridge.ts
|
|
2
|
+
import { useSodaxContext } from '../shared/useSodaxContext.js';
|
|
3
|
+
import type { BridgeParams, SpokeChainKey, TxHashPair } from '@sodax/sdk';
|
|
4
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
5
|
+
import type { MutationHookParams } from '../shared/types.js';
|
|
6
|
+
import { useSafeMutation, type SafeUseMutationResult } from '../shared/useSafeMutation.js';
|
|
7
|
+
import { unwrapResult } from '../shared/unwrapResult.js';
|
|
12
8
|
|
|
13
9
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
*
|
|
22
|
-
* const { mutateAsync: bridge, isPending } = useBridge(spokeProvider);
|
|
23
|
-
*
|
|
24
|
-
* const handleBridge = async () => {
|
|
25
|
-
* const result = await bridge({
|
|
26
|
-
* srcChainId: '0x2105.base',
|
|
27
|
-
* srcAsset: '0x...',
|
|
28
|
-
* amount: 1000n,
|
|
29
|
-
* dstChainId: '0x89.polygon',
|
|
30
|
-
* dstAsset: '0x...',
|
|
31
|
-
* recipient: '0x...'
|
|
32
|
-
* });
|
|
10
|
+
* Mutation variables for {@link useBridge}. Generic over `K extends SpokeChainKey` (defaults to
|
|
11
|
+
* the full union). Sophisticated callers can lock K at the hook call site to narrow the
|
|
12
|
+
* `walletProvider` and `params.srcChainKey` types.
|
|
13
|
+
*/
|
|
14
|
+
export type UseBridgeVars<K extends SpokeChainKey = SpokeChainKey> = Omit<BridgeParams<K, false>, 'raw'>;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* React hook for executing a cross-chain bridge transfer.
|
|
33
18
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* hubTxHash: result.hubTxHash
|
|
37
|
-
* });
|
|
38
|
-
* };
|
|
39
|
-
* ```
|
|
19
|
+
* Throws on SDK failure so React Query's native error model engages (`isError`, `error`,
|
|
20
|
+
* `onError`, `retry`). Returns the unwrapped `TxHashPair` on success.
|
|
40
21
|
*/
|
|
41
|
-
export function useBridge(
|
|
42
|
-
|
|
43
|
-
|
|
22
|
+
export function useBridge<K extends SpokeChainKey = SpokeChainKey>({
|
|
23
|
+
mutationOptions,
|
|
24
|
+
}: MutationHookParams<TxHashPair, UseBridgeVars<K>> = {}): SafeUseMutationResult<TxHashPair, Error, UseBridgeVars<K>> {
|
|
44
25
|
const { sodax } = useSodaxContext();
|
|
26
|
+
const queryClient = useQueryClient();
|
|
45
27
|
|
|
46
|
-
return
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
spokeProvider,
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
if (!result.ok) {
|
|
58
|
-
throw new Error(`Bridge failed: ${result.error.code}`);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return result;
|
|
28
|
+
return useSafeMutation<TxHashPair, Error, UseBridgeVars<K>>({
|
|
29
|
+
mutationKey: ['bridge'],
|
|
30
|
+
...mutationOptions,
|
|
31
|
+
mutationFn: async vars => unwrapResult(await sodax.bridge.bridge({ ...vars, raw: false })),
|
|
32
|
+
onSuccess: async (data, vars, ctx) => {
|
|
33
|
+
queryClient.invalidateQueries({ queryKey: ['shared', 'xBalances', vars.params.srcChainKey] });
|
|
34
|
+
queryClient.invalidateQueries({ queryKey: ['shared', 'xBalances', vars.params.dstChainKey] });
|
|
35
|
+
await mutationOptions?.onSuccess?.(data, vars, ctx);
|
|
62
36
|
},
|
|
63
37
|
});
|
|
64
38
|
}
|
|
@@ -1,49 +1,49 @@
|
|
|
1
1
|
import { useQuery, type UseQueryResult } from '@tanstack/react-query';
|
|
2
|
-
import { useSodaxContext } from '../shared/useSodaxContext';
|
|
3
|
-
import type {
|
|
2
|
+
import { useSodaxContext } from '../shared/useSodaxContext.js';
|
|
3
|
+
import type { CreateBridgeIntentParams, GetWalletProviderType, SpokeChainKey } from '@sodax/sdk';
|
|
4
|
+
import type { ReadHookParams } from '../shared/types.js';
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
* - error: Any error that occurred during the check
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* ```typescript
|
|
21
|
-
* const { data: hasAllowed, isLoading } = useBridgeAllowance(params, spokeProvider);
|
|
22
|
-
* ```
|
|
23
|
-
*/
|
|
24
|
-
export function useBridgeAllowance(
|
|
25
|
-
params: CreateBridgeIntentParams | undefined,
|
|
26
|
-
spokeProvider: SpokeProvider | undefined,
|
|
27
|
-
): UseQueryResult<boolean, Error> {
|
|
6
|
+
export type UseBridgeAllowanceParams<K extends SpokeChainKey> = ReadHookParams<
|
|
7
|
+
boolean,
|
|
8
|
+
{
|
|
9
|
+
payload: CreateBridgeIntentParams<K> | undefined;
|
|
10
|
+
walletProvider: GetWalletProviderType<K> | undefined;
|
|
11
|
+
}
|
|
12
|
+
>;
|
|
13
|
+
|
|
14
|
+
export function useBridgeAllowance<K extends SpokeChainKey>({
|
|
15
|
+
params,
|
|
16
|
+
queryOptions,
|
|
17
|
+
}: UseBridgeAllowanceParams<K> = {}): UseQueryResult<boolean, Error> {
|
|
28
18
|
const { sodax } = useSodaxContext();
|
|
19
|
+
const payload = params?.payload;
|
|
20
|
+
const walletProvider = params?.walletProvider;
|
|
29
21
|
|
|
30
|
-
return useQuery({
|
|
31
|
-
|
|
22
|
+
return useQuery<boolean, Error>({
|
|
23
|
+
// Extract the (chain, owner, token, amount) tuple that actually scopes the allowance —
|
|
24
|
+
// raw-object keys break per Rule 4 (bigints) and churn on every render.
|
|
25
|
+
queryKey: [
|
|
26
|
+
'bridge',
|
|
27
|
+
'allowance',
|
|
28
|
+
payload?.srcChainKey,
|
|
29
|
+
payload?.srcAddress,
|
|
30
|
+
payload?.srcToken,
|
|
31
|
+
payload?.amount?.toString(),
|
|
32
|
+
],
|
|
32
33
|
queryFn: async () => {
|
|
33
|
-
if (!
|
|
34
|
+
if (!payload || !walletProvider) {
|
|
34
35
|
return false;
|
|
35
36
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
const result = await sodax.bridge.isAllowanceValid({
|
|
38
|
+
params: payload,
|
|
39
|
+
raw: false,
|
|
40
|
+
walletProvider,
|
|
40
41
|
});
|
|
41
|
-
|
|
42
|
-
if (allowance.ok) {
|
|
43
|
-
return allowance.value;
|
|
44
|
-
}
|
|
45
|
-
return false;
|
|
42
|
+
return result.ok ? result.value : false;
|
|
46
43
|
},
|
|
47
|
-
enabled: !!
|
|
44
|
+
enabled: !!payload && !!walletProvider,
|
|
45
|
+
refetchInterval: 2000,
|
|
46
|
+
gcTime: 0,
|
|
47
|
+
...queryOptions,
|
|
48
48
|
});
|
|
49
49
|
}
|